📖

스토리텔링 형식으로 업데이트되었습니다! 실무 사례와 함께 더 쉽게 이해할 수 있어요.

이미지 로딩 중...

Vite 라이브러리 모드로 패키지 빌드하기 완벽 가이드 - 슬라이드 1/7
A

AI Generated

2025. 11. 25. · 11 Views

Vite 라이브러리 모드로 패키지 빌드하기 완벽 가이드

Vite의 라이브러리 모드를 활용하여 재사용 가능한 패키지를 빌드하는 방법을 배웁니다. lib 모드 설정부터 다양한 모듈 포맷 생성, TypeScript 선언 파일까지 실무에서 바로 적용할 수 있는 내용을 다룹니다.


목차

  1. Vite를_이용한_라이브러리_빌드
  2. lib_모드_설정
  3. 여러_엔트리_포인트_처리
  4. ESM_UMD_CommonJS_포맷_생성
  5. externals_설정으로_의존성_제외
  6. TypeScript_declaration_파일_생성

1. Vite를_이용한_라이브러리_빌드

입사 6개월 차 김개발 씨는 회사에서 여러 프로젝트에 공통으로 사용하는 유틸리티 함수들을 만들어 왔습니다. 그런데 매번 복사해서 붙여넣기를 하다 보니 코드 관리가 점점 힘들어졌습니다.

"이걸 npm 패키지로 만들어서 공유하면 어떨까?" 하는 생각이 들었지만, 어디서부터 시작해야 할지 막막했습니다.

Vite 라이브러리 모드는 애플리케이션이 아닌 재사용 가능한 패키지를 빌드하기 위한 Vite의 특별한 기능입니다. 마치 빵집에서 완제품 빵을 만드는 것과 빵 믹스를 만드는 것의 차이와 같습니다.

일반 빌드는 바로 먹을 수 있는 완제품을, 라이브러리 빌드는 다른 곳에서 활용할 수 있는 재료를 만들어냅니다.

다음 코드를 살펴봅시다.

// package.json - 라이브러리 패키지 기본 설정
{
  "name": "my-awesome-utils",
  "version": "1.0.0",
  "type": "module",
  "main": "./dist/my-utils.umd.cjs",
  "module": "./dist/my-utils.js",
  "types": "./dist/index.d.ts",
  "exports": {
    ".": {
      "import": "./dist/my-utils.js",
      "require": "./dist/my-utils.umd.cjs"
    }
  },
  "files": ["dist"]
}

김개발 씨는 평소처럼 새 프로젝트를 시작하려던 중이었습니다. 그런데 이번에는 뭔가 다른 걸 해보고 싶었습니다.

지금까지 여러 프로젝트에서 반복해서 작성했던 유틸리티 함수들, 이것들을 하나의 패키지로 만들어 팀원들과 공유하면 어떨까요? "근데 라이브러리를 어떻게 만들지?" 김개발 씨는 웹팩 설정 파일들을 떠올리며 한숨을 쉬었습니다.

복잡한 설정, 수많은 플러그인, 끝없는 삽질의 추억이 스쳐 지나갔습니다. 바로 그때 옆자리 박시니어 씨가 다가왔습니다.

"Vite 써본 적 있어요? 라이브러리 모드가 정말 편해요." Vite는 원래 빠른 개발 서버와 번들링을 위해 만들어진 도구입니다.

그런데 여기에는 숨겨진 보석 같은 기능이 있습니다. 바로 라이브러리 모드입니다.

이 모드를 사용하면 복잡한 설정 없이도 다른 프로젝트에서 가져다 쓸 수 있는 패키지를 만들 수 있습니다. 일반적인 웹 애플리케이션 빌드와 라이브러리 빌드는 목적이 완전히 다릅니다.

웹 애플리케이션은 브라우저에서 바로 실행되는 최종 결과물을 만들어냅니다. HTML, CSS, JavaScript가 하나로 묶여서 사용자에게 전달되지요.

반면 라이브러리는 다릅니다. 다른 개발자가 자신의 프로젝트에서 import하여 사용할 수 있는 형태로 만들어져야 합니다.

마치 레고 블록처럼 다른 구조물에 끼워 맞출 수 있어야 하는 것입니다. package.json 파일을 살펴보면 여러 중요한 필드들이 보입니다.

main 필드는 CommonJS 환경에서 사용할 파일을, module 필드는 ES 모듈 환경에서 사용할 파일을 지정합니다. exports 필드는 최신 Node.js에서 사용하는 더 정교한 진입점 설정입니다.

files 필드도 눈여겨볼 만합니다. npm에 패키지를 배포할 때 어떤 파일들을 포함할지 결정합니다.

dist 폴더만 지정해두면 소스 코드나 테스트 파일 같은 불필요한 것들은 배포에서 제외됩니다. 김개발 씨는 고개를 끄덕였습니다.

"생각보다 복잡하지 않네요. 그런데 실제 Vite 설정은 어떻게 하나요?" 박시니어 씨가 미소를 지었습니다.

"그건 다음에 알아보죠. 일단 이 기본 구조를 이해하는 게 중요해요." 라이브러리를 만든다는 것은 단순히 코드를 작성하는 것을 넘어섭니다.

다른 개발자들이 어떤 환경에서든 편하게 사용할 수 있도록 여러 형태로 빌드해야 합니다. Vite 라이브러리 모드는 이 복잡한 작업을 놀라울 정도로 간단하게 만들어줍니다.

실전 팁

💡 - package.json의 type을 module로 설정하면 ES 모듈이 기본값이 됩니다

  • exports 필드는 Node.js 12.7.0 이상에서 지원되며, 더 세밀한 진입점 제어가 가능합니다

2. lib_모드_설정

김개발 씨는 package.json 설정을 마쳤습니다. 이제 진짜 핵심인 Vite 설정을 할 차례입니다.

"설정 파일이 수백 줄은 되겠지?" 하고 걱정했지만, 박시니어 씨가 보여준 설정 파일은 놀라울 정도로 간결했습니다.

vite.config.js에서 build.lib 옵션을 설정하면 라이브러리 모드가 활성화됩니다. 마치 자동차의 기어를 드라이브에서 리버스로 바꾸는 것처럼, Vite의 빌드 방향을 애플리케이션에서 라이브러리로 전환하는 것입니다.

핵심은 entry와 name, fileName 세 가지 옵션입니다.

다음 코드를 살펴봅시다.

// vite.config.js - 라이브러리 모드 기본 설정
import { defineConfig } from 'vite'
import { resolve } from 'path'

export default defineConfig({
  build: {
    lib: {
      // 라이브러리의 진입점 파일
      entry: resolve(__dirname, 'src/index.ts'),
      // UMD 빌드에서 사용할 전역 변수명
      name: 'MyAwesomeUtils',
      // 출력 파일명 (확장자는 format에 따라 자동 결정)
      fileName: 'my-utils'
    }
  }
})

"이게 전부예요?" 김개발 씨는 눈을 동그랗게 떴습니다. 웹팩으로 라이브러리를 빌드하던 시절, 설정 파일만 수십 줄이었던 기억이 떠올랐기 때문입니다.

박시니어 씨가 설명을 이어갔습니다. "Vite는 합리적인 기본값을 제공해요.

필요한 것만 설정하면 나머지는 알아서 처리해주죠." entry 옵션은 라이브러리의 시작점을 지정합니다. 이 파일에서 export하는 모든 것이 라이브러리의 공개 API가 됩니다.

마치 건물의 정문과 같습니다. 방문객은 이 문을 통해서만 건물에 들어올 수 있습니다.

여기서 resolve 함수를 사용하는 이유가 있습니다. 상대 경로는 실행 위치에 따라 달라질 수 있기 때문입니다.

resolve와 __dirname을 조합하면 설정 파일 위치를 기준으로 한 절대 경로를 만들 수 있습니다. 이렇게 하면 어디서 빌드를 실행하든 같은 결과를 얻을 수 있습니다.

name 옵션은 조금 특별한 역할을 합니다. UMD 형식으로 빌드할 때 전역 변수명으로 사용됩니다.

예를 들어 name을 MyAwesomeUtils로 설정하면, script 태그로 로드했을 때 window.MyAwesomeUtils로 접근할 수 있게 됩니다. "UMD가 뭔가요?" 김개발 씨가 물었습니다.

"Universal Module Definition의 약자예요. 브라우저에서 script 태그로 로드하든, CommonJS로 require하든, ES 모듈로 import하든 모두 동작하는 만능 형식이죠." fileName 옵션은 출력 파일의 이름을 결정합니다.

재미있는 점은 확장자를 지정하지 않아도 된다는 것입니다. Vite가 빌드 형식에 따라 적절한 확장자를 자동으로 붙여줍니다.

ES 모듈이면 .js, UMD면 .umd.cjs가 붙습니다. 이 간단한 설정만으로 Vite는 라이브러리 빌드에 필요한 모든 것을 준비합니다.

코드 압축, 트리 셰이킹, 소스맵 생성까지 기본으로 포함됩니다. 김개발 씨는 터미널에 npm run build를 입력했습니다.

잠시 후 dist 폴더에 빌드된 파일들이 나타났습니다. 정말 간단했습니다.

"이제 기본은 끝났어요. 하지만 실무에서는 조금 더 복잡한 상황도 있죠." 박시니어 씨가 말했습니다.

실전 팁

💡 - fileName을 함수로 지정하면 형식별로 다른 이름을 사용할 수 있습니다

  • __dirname은 ES 모듈에서 직접 사용할 수 없으므로 import.meta.url을 활용해야 할 수도 있습니다

3. 여러_엔트리_포인트_처리

김개발 씨의 유틸리티 라이브러리가 점점 커지고 있습니다. 문자열 처리 함수, 날짜 처리 함수, 배열 처리 함수 등 다양한 카테고리가 생겼습니다.

"이걸 전부 한 파일에서 export하면 사용자가 필요 없는 코드까지 다 가져가게 되지 않을까요?"

여러 엔트리 포인트를 설정하면 라이브러리를 논리적인 단위로 분리할 수 있습니다. 마치 백화점에 여러 입구가 있는 것과 같습니다.

식품관에 갈 사람은 지하 입구로, 화장품을 살 사람은 1층 입구로 들어가면 됩니다. 사용자는 필요한 부분만 가져다 쓸 수 있어 번들 크기를 최적화할 수 있습니다.

다음 코드를 살펴봅시다.

// vite.config.js - 여러 엔트리 포인트 설정
import { defineConfig } from 'vite'
import { resolve } from 'path'

export default defineConfig({
  build: {
    lib: {
      entry: {
        // 메인 진입점 - 모든 기능 포함
        index: resolve(__dirname, 'src/index.ts'),
        // 문자열 유틸리티만 포함
        string: resolve(__dirname, 'src/string/index.ts'),
        // 날짜 유틸리티만 포함
        date: resolve(__dirname, 'src/date/index.ts'),
        // 배열 유틸리티만 포함
        array: resolve(__dirname, 'src/array/index.ts')
      },
      formats: ['es', 'cjs']
    }
  }
})

박시니어 씨가 물었습니다. "lodash 써본 적 있죠?

전체를 import하면 얼마나 무거운지 알아요?" 김개발 씨는 고개를 끄덕였습니다. 예전에 lodash를 그냥 import했다가 번들 크기가 급격히 커진 경험이 있었습니다.

그때부터 lodash-es를 사용하거나 lodash/get처럼 개별 함수만 가져오는 방식을 사용했습니다. "우리 라이브러리도 그렇게 만들 수 있어요.

여러 엔트리 포인트를 설정하면 됩니다." entry 옵션에 문자열 대신 객체를 전달하면 여러 진입점을 정의할 수 있습니다. 객체의 키는 출력 파일명이 되고, 값은 해당 진입점의 소스 파일 경로가 됩니다.

이렇게 설정하면 빌드 결과물이 달라집니다. 단일 진입점일 때는 하나의 파일만 생성되지만, 여러 진입점을 설정하면 각각에 대응하는 파일들이 생성됩니다.

index.js, string.js, date.js, array.js처럼요. 사용자 입장에서는 선택의 폭이 넓어집니다.

모든 기능이 필요하면 메인 모듈을 import하면 됩니다. 하지만 문자열 처리 함수만 필요하다면 string 모듈만 가져올 수 있습니다.

javascript // 모든 기능 사용 import * as utils from 'my-awesome-utils' // 문자열 유틸리티만 사용 - 번들 크기 최소화 import { capitalize, truncate } from 'my-awesome-utils/string' package.json의 exports 필드도 함께 수정해야 합니다. 각 진입점에 대한 경로를 명시적으로 지정해야 사용자가 서브 경로로 import할 수 있습니다.

json "exports": { ".": { "import": "./dist/index.js", "require": "./dist/index.cjs" }, "./string": { "import": "./dist/string.js", "require": "./dist/string.cjs" } } 여기서 주의할 점이 있습니다. 여러 엔트리 포인트를 사용할 때는 formats 옵션에 UMD를 포함하기 어렵습니다.

UMD는 단일 전역 변수를 사용하기 때문입니다. 따라서 es와 cjs 형식만 사용하는 것이 일반적입니다.

김개발 씨가 빌드를 실행하자 dist 폴더에 여러 파일이 생성되었습니다. 각각의 파일은 해당 카테고리의 함수만 포함하고 있었습니다.

깔끔했습니다. "트리 셰이킹도 되나요?" 김개발 씨가 물었습니다.

"물론이죠. ES 모듈 형식은 트리 셰이킹을 지원해요.

사용자가 특정 함수만 import하면 나머지는 최종 번들에서 제거됩니다."

실전 팁

💡 - 여러 엔트리 포인트 사용 시 공통 코드는 자동으로 별도 청크로 분리됩니다

  • package.json의 exports 필드를 반드시 업데이트해야 서브 경로 import가 작동합니다

4. ESM_UMD_CommonJS_포맷_생성

"이 라이브러리, Node.js에서도 쓸 수 있나요?" 팀원의 질문에 김개발 씨는 잠시 멈칫했습니다. 브라우저에서는 잘 동작하는데, Node.js 환경에서 require로 가져오려니 에러가 발생했습니다.

세상에는 다양한 자바스크립트 환경이 있고, 각각 다른 모듈 시스템을 사용합니다.

ESM, UMD, CommonJS는 자바스크립트의 대표적인 모듈 포맷입니다. ESM은 현대적인 import/export 문법을, CommonJS는 Node.js의 require/module.exports를, UMD는 어디서든 동작하는 만능 형식을 의미합니다.

Vite는 formats 옵션으로 원하는 형식들을 동시에 생성할 수 있습니다.

다음 코드를 살펴봅시다.

// vite.config.js - 다양한 모듈 포맷 설정
import { defineConfig } from 'vite'
import { resolve } from 'path'

export default defineConfig({
  build: {
    lib: {
      entry: resolve(__dirname, 'src/index.ts'),
      name: 'MyAwesomeUtils',
      // 여러 형식으로 동시 빌드
      formats: ['es', 'umd', 'cjs'],
      // 형식별로 다른 파일명 지정
      fileName: (format) => {
        if (format === 'es') return 'my-utils.js'
        if (format === 'umd') return 'my-utils.umd.js'
        if (format === 'cjs') return 'my-utils.cjs'
        return `my-utils.${format}.js`
      }
    }
  }
})

자바스크립트의 역사는 모듈 시스템의 역사이기도 합니다. 초기 자바스크립트에는 모듈이라는 개념이 없었습니다.

모든 코드가 전역 스코프를 공유했고, 이름 충돌은 개발자의 악몽이었습니다. CommonJS가 먼저 등장했습니다.

Node.js가 이 방식을 채택하면서 서버 사이드에서 표준이 되었습니다. require로 모듈을 가져오고 module.exports로 내보내는 익숙한 문법입니다.

javascript // CommonJS 방식 const utils = require('my-awesome-utils') module.exports = { someFunction } 브라우저에서는 상황이 달랐습니다. CommonJS는 동기적으로 파일을 로드하기 때문에 네트워크 환경인 브라우저에는 적합하지 않았습니다.

이를 해결하기 위해 AMD가 등장했고, 나중에 AMD와 CommonJS를 모두 지원하는 UMD가 나왔습니다. javascript // UMD는 script 태그로 로드하면 전역 변수가 됩니다 <script src="my-utils.umd.js"></script> <script> window.MyAwesomeUtils.someFunction() </script> 그리고 마침내 ESM(ECMAScript Modules)이 언어 표준으로 등장했습니다.

import/export 문법은 이제 브라우저와 최신 Node.js 모두에서 네이티브로 지원됩니다. 정적 분석이 가능해 트리 셰이킹 같은 최적화도 가능합니다.

javascript // ESM 방식 import { someFunction } from 'my-awesome-utils' export { anotherFunction } 좋은 라이브러리는 이 세 가지 형식을 모두 제공합니다. 어떤 환경에서든 사용할 수 있도록 말이죠.

Vite의 formats 옵션은 배열로 원하는 형식들을 지정할 수 있습니다. 'es'는 ESM, 'umd'는 UMD, 'cjs'는 CommonJS를 의미합니다.

한 번의 빌드로 세 가지 파일이 모두 생성됩니다. fileName 옵션을 함수로 지정하면 형식별로 다른 파일명을 사용할 수 있습니다.

이 함수는 format 매개변수를 받아 해당 형식에 맞는 파일명을 반환합니다. 김개발 씨는 빌드를 실행했습니다.

dist 폴더에 세 개의 파일이 생성되었습니다. my-utils.js, my-utils.umd.js, my-utils.cjs.

각각의 파일을 열어보니 문법이 확연히 달랐습니다. "이제 어떤 환경에서든 우리 라이브러리를 사용할 수 있겠네요!" 김개발 씨가 기뻐했습니다.

박시니어 씨가 덧붙였습니다. "요즘은 ESM이 대세예요.

하지만 레거시 프로젝트를 위해 CommonJS도 제공하는 게 좋습니다. UMD는 CDN으로 직접 script 태그에서 로드하는 경우를 위해 제공하고요."

실전 팁

💡 - 최신 프로젝트는 주로 ESM을 사용하므로 es 형식은 필수입니다

  • Node.js 레거시 지원이 필요하면 cjs 형식을 포함하세요

5. externals_설정으로_의존성_제외

김개발 씨의 라이브러리는 React 컴포넌트도 포함하고 있습니다. 빌드를 해보니 결과물의 크기가 엄청났습니다.

알고 보니 React 전체가 번들에 포함되어 있었습니다. "사용자도 React를 설치할 텐데, 왜 우리 라이브러리에도 React가 들어가 있죠?"

externals 설정은 특정 의존성을 빌드 결과물에서 제외하는 기능입니다. 마치 이사할 때 대형 가전제품은 새 집에 이미 있으니 가져가지 않는 것과 같습니다.

React, Vue 같은 피어 의존성을 제외하면 번들 크기를 대폭 줄일 수 있고, 버전 충돌도 방지할 수 있습니다.

다음 코드를 살펴봅시다.

// vite.config.js - externals 설정
import { defineConfig } from 'vite'
import { resolve } from 'path'

export default defineConfig({
  build: {
    lib: {
      entry: resolve(__dirname, 'src/index.ts'),
      name: 'MyReactComponents',
      formats: ['es', 'cjs']
    },
    rollupOptions: {
      // 번들에 포함하지 않을 의존성
      external: ['react', 'react-dom', 'react/jsx-runtime'],
      output: {
        // UMD 빌드 시 전역 변수 매핑
        globals: {
          react: 'React',
          'react-dom': 'ReactDOM'
        }
      }
    }
  }
})

라이브러리를 만들 때 흔히 저지르는 실수가 있습니다. 모든 의존성을 번들에 포함시키는 것입니다.

애플리케이션 빌드에서는 이게 맞습니다. 하지만 라이브러리는 다릅니다.

생각해 보세요. 여러분이 만든 React 컴포넌트 라이브러리를 누군가 설치했다고 합시다.

그 사람의 프로젝트에는 이미 React가 설치되어 있을 것입니다. 그런데 여러분의 라이브러리에도 React가 들어있다면 어떻게 될까요?

두 개의 React가 공존하게 됩니다. 최악의 경우 버전이 다르면 이상한 버그가 발생합니다.

"Invalid hook call" 에러를 본 적이 있다면, 이게 원인일 수 있습니다. 번들 크기도 불필요하게 커집니다.

이런 의존성을 **피어 의존성(peer dependency)**이라고 부릅니다. 라이브러리가 제공하는 것이 아니라, 라이브러리를 사용하는 프로젝트가 제공해야 하는 의존성입니다.

Vite는 Rollup을 기반으로 합니다. 그래서 rollupOptions를 통해 Rollup의 설정을 직접 조작할 수 있습니다.

external 옵션에 제외할 패키지 이름을 배열로 전달하면 됩니다. React를 사용한다면 보통 세 가지를 제외해야 합니다.

'react', 'react-dom', 그리고 'react/jsx-runtime'입니다. jsx-runtime은 최신 JSX 변환 방식에서 사용되는데, 이것도 제외하지 않으면 번들에 포함될 수 있습니다.

globals 옵션은 UMD 빌드에서 중요합니다. UMD는 전역 변수를 통해 의존성에 접근합니다.

번들에 react가 없으니, 런타임에 어디서 React를 찾을지 알려줘야 합니다. globals 설정은 "react 패키지가 필요하면 전역의 React 변수를 사용해라"라고 말하는 것입니다.

package.json에도 피어 의존성을 명시해야 합니다. json { "peerDependencies": { "react": ">=17.0.0", "react-dom": ">=17.0.0" } } 이렇게 하면 npm은 사용자에게 해당 패키지가 필요하다고 경고해줍니다.

김개발 씨가 다시 빌드를 실행하자 번들 크기가 극적으로 줄어들었습니다. 수백 KB였던 파일이 수십 KB로 줄었습니다.

이제야 제대로 된 라이브러리 같았습니다.

실전 팁

💡 - 정규표현식으로 여러 패키지를 한번에 제외할 수 있습니다: external: [/^react/]

  • 모든 dependencies를 자동으로 external로 설정하려면 vite-plugin-dts 같은 플러그인을 사용하세요

6. TypeScript_declaration_파일_생성

드디어 라이브러리를 npm에 배포했습니다. 그런데 팀원이 사용하려고 import하자마자 불만을 토로했습니다.

"자동완성이 안 되네요. 타입도 없고요." TypeScript를 지원하지 않는 라이브러리는 요즘 시대에 미완성이나 다름없습니다.

타입 선언 파일이 필요했습니다.

TypeScript declaration 파일(.d.ts)은 라이브러리의 타입 정보를 담고 있는 파일입니다. 마치 도서관의 카탈로그처럼, 라이브러리에 어떤 함수가 있고 어떤 매개변수를 받는지 IDE에게 알려줍니다.

이 파일이 있으면 사용자는 자동완성, 타입 체크, 문서화 기능을 모두 누릴 수 있습니다.

다음 코드를 살펴봅시다.

// vite.config.js - 타입 선언 파일 생성 설정
import { defineConfig } from 'vite'
import { resolve } from 'path'
import dts from 'vite-plugin-dts'

export default defineConfig({
  plugins: [
    // 타입 선언 파일 자동 생성
    dts({
      // 하나의 파일로 번들링
      rollupTypes: true,
      // 선언 파일 출력 경로
      outDir: 'dist',
      // tsconfig 경로 지정
      tsconfigPath: './tsconfig.json'
    })
  ],
  build: {
    lib: {
      entry: resolve(__dirname, 'src/index.ts'),
      name: 'MyAwesomeUtils',
      formats: ['es', 'cjs']
    }
  }
})

TypeScript 없이 개발하던 시절을 기억하시나요? 함수가 어떤 매개변수를 받는지 알려면 문서를 찾아보거나 소스 코드를 직접 열어봐야 했습니다.

오타를 내도 런타임에 가서야 에러가 발생했습니다. 타입 선언 파일은 이 모든 것을 해결해줍니다.

IDE는 이 파일을 읽어 자동완성을 제공하고, 잘못된 사용을 즉시 경고해줍니다. 라이브러리 사용자의 생산성이 크게 향상됩니다.

Vite 자체는 타입 선언 파일을 생성하지 않습니다. 대신 vite-plugin-dts라는 플러그인을 사용합니다.

이 플러그인은 빌드 과정에서 TypeScript 컴파일러를 실행하여 .d.ts 파일을 생성합니다. 먼저 플러그인을 설치해야 합니다.

bash npm install -D vite-plugin-dts 설정에서 rollupTypes 옵션은 특히 유용합니다. 이 옵션을 true로 설정하면 여러 개의 선언 파일이 하나로 합쳐집니다.

사용자 입장에서는 하나의 깔끔한 타입 파일만 있으면 되니까요. outDir은 선언 파일이 출력될 경로를 지정합니다.

보통 빌드 결과물과 같은 dist 폴더에 넣습니다. package.json에도 타입 파일의 위치를 알려줘야 합니다.

json { "types": "./dist/index.d.ts", "exports": { ".": { "types": "./dist/index.d.ts", "import": "./dist/my-utils.js", "require": "./dist/my-utils.cjs" } } } types 필드가 타입 선언 파일의 경로입니다. exports 안에도 types를 넣으면 더 정확하게 지정할 수 있습니다.

주의할 점이 있습니다. exports에서 types는 반드시 첫 번째로 와야 합니다.

TypeScript는 exports를 위에서부터 순서대로 확인하기 때문입니다. 김개발 씨가 빌드를 실행하자 dist 폴더에 index.d.ts 파일이 생성되었습니다.

파일을 열어보니 라이브러리의 모든 함수와 타입이 깔끔하게 정리되어 있었습니다. 팀원이 다시 import를 시도했습니다.

이번에는 자동완성이 잘 동작했습니다. 함수에 마우스를 올리면 매개변수와 반환값의 타입이 표시되었습니다.

잘못된 타입의 인자를 넘기면 빨간 밑줄이 그어졌습니다. "이제야 진짜 라이브러리 같네요!" 팀원이 만족한 표정을 지었습니다.

박시니어 씨가 마지막 조언을 덧붙였습니다. "좋은 라이브러리는 좋은 타입 정의를 가지고 있어요.

타입은 가장 좋은 문서이기도 하니까요."

실전 팁

💡 - tsconfig.json의 declaration 옵션은 vite-plugin-dts가 처리하므로 별도 설정이 필요 없습니다

  • 복잡한 타입은 별도의 types 폴더에서 관리하고 re-export하면 유지보수가 쉬워집니다

이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!

#Vite#LibraryMode#ESM#CommonJS#TypeScript#Vite,빌드도구,프론트엔드

댓글 (0)

댓글을 작성하려면 로그인이 필요합니다.

함께 보면 좋은 카드 뉴스