개발

typescript react npm 라이브러리 개발을 위한 환경 설정

배우겠습니다 2024. 12. 28. 22:53

모노레포

어떤 라이브러리를 개발하고 그 결과를 테스팅하기 위해 모노레포를 사용한다.

필자는 pnpm을 사용한다. pnpm monorepo는 pnpm-workspace.yaml 로 설정할 수 있다.

packages:
  - "packages/*"
  • packages에 각각의 패키지(테스팅, 라이브러리)를 개발하기위해 위 내용을 작성한다.
  • packages/example에 테스팅 용도 예제를 개발한다.
  • packages/(library)에 라이브러리를 개발한다.

package.json

라이브러리 패키지의 package.json을 설정한다.

{
  "name": "unique-lib-name",
  "version": "1.0.0",
  "main": "dist/cjs/index.js",
  "module": "dist/esm/index.js",
  "types": "dist/types/index.d.ts",
  "files": [
    "dist",
  ],
  "scripts": {
    "build": "rollup -c"
  },
  "peerDependencies": {
    "react": "^18.0.0",
    "react-dom": "^18.0.0"
  },
  "devDependencies": {
    "@types/react": "^18.3.18",
    "@types/react-dom": "^18.3.5",
    "react": "^18.3.1",
    "react-dom": "^18.3.1",
    ...
  • name엔 배포하고자 하는 라이브러리 이름이다. npm에 중복된 라이브러리가 존재해선 안된다.
  • version은 라이브러리 버전이다. 처음이므로 1.0.0이다. 업데이트할때마다 올려야한다.
  • main은 commonjs 시스템에서 라이브러리를 require할때 필요한 파일 경로를 설정한다. (esm으로만 사용하고자하면 당연히 필수는 아니다.)
  • module은 esm에서 라이브러리를 import할때 필요한 파일 경로를 설정한다.
  • types는 typescript에서 타입을 가져오기 위한 d.ts 파일 경로를 설정한다.
  • peerDep은 라이브러리를 사용하는 프로젝트에서 설치해야할 라이브러리와 그 버전을 설정한다.
  • 개발하기위해 depDep에도 peerDep에 기술한 라이브러리를 설치한다. 프로덕션 빌드에선 포함되지 않는다.

tsconfig

결국 typescript를 컴파일해 js로 변환해야 한다. 이 방식을 설정한다.

{
  "compilerOptions": {
    "target": "ES2019",
    "module": "ESNext",
    "jsx": "react",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "declaration": true, 
    "declarationDir": "./dist/types",
    "outDir": "./dist",
    "moduleResolution": "node"
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist"]
}
  • target으로 어떤 세대(버전)의 js문법으로 컴파일 할 것인지 결정한다.
  • module에선 모듈 시스템을 지정한다.
  • jsx로 tsx를 컴파일한다.
  • esModuleInterop으로 cjs 모듈과 esm간의 호환성을 제공한다. 예를들어, cjs 시대에 게발된 매우 옛날 모듈을 import ~ 처럼 사용하게 해준다.
  • skipLibCheck로 라이브러리 의존성을 굳이 검사하지 않는다.
  • declaration과 declarationDir로 d.ts 파일을 생성한다.
  • outdir은 컴파일 결과 경로이다.

rollup config

라이브러리를 빌드하기 위한 설정

// import peerDepsExternal from "rollup-plugin-peer-deps-external";
import resolve from "@rollup/plugin-node-resolve";
import commonjs from "@rollup/plugin-commonjs";
import typescript from "@rollup/plugin-typescript";
import dts from "rollup-plugin-dts";
// import copy from "rollup-plugin-copy";
import pkg from "./package.json" assert { type: "json" };

export default [
  {
    input: "src/index.ts",
    output: [
      {
        file: pkg.main, // dist/cjs/index.js
        format: "cjs",
        sourcemap: true,
      },
      {
        file: pkg.module, // dist/esm/index.js
        format: "esm",
        sourcemap: true,
      },
    ],
    external: [...Object.keys(pkg.peerDependencies || {})],
    plugins: [
      resolve(),
      commonjs(),
      typescript({
        tsconfig: "./tsconfig.json",
      }),
      // copy({
      //   targets: [{ src: "src/ui/styles.css", dest: "dist" }],
      // }),
    ],
  },
  {
    input: "src/index.ts",
    output: {
      file: "dist/types/index.d.ts",
      format: "es",
    },
    plugins: [dts()],
  },
];
  • input에는 빌드 진입점을 설정한다. 대부분 라이브러리 파일을 개발할땐, 한 파일(index.ts)에다 사용할 기능을 export한다.
  • ouput에는 빌드 결과물을 설정한다. file엔 빌드 결과의 경로, format은 모듈 시스템 형식, sourcemap은 번들 코드와 원본 코드(es6, ts형식)의 매핑 파일(js.map)을 형성한다.

plugin

  • resolve는 라이브러리에서 추가적인 의존성을 빌드결과에서 가져오고 ts와 jsx파일을 빌드하게 해준다.
  • commonjs는 cjs 형식을 esm으로 변환해준다. 기본적으로 rollup은 esm을 지원한다.
  • typescript는 tsc(타입스크립트 파일을 js로 변환)를 해준다.
  • dts는 index.d.ts를 생성해준다.

테스팅용 패키지에서 라이브러리 사용

라이브러리를 빌드한 뒤 그 결과를 워크스페이스내에서 사용

테스팅용 package의 package.json에서

  "dependencies": {
    "react": "^18.3.1",
    "react-dom": "^18.3.1",
    "my-lib": "workspace:*" 
  },

해당 내용 작성해준다.
my-lib이란 패키지를 워크스페이스 내에서 사용해준다는 의미이다.
my-lib을 빌드해준다면 그대로 테스팅용 패키지에서 사용 가능하다.