노현진's Blog

pnpm + tsdown으로 React 라이브러리 만들기 ② - React 라이브러리 생성

pnpm + tsdown으로 React 라이브러리를 만드는 과정에서 React 라이브러리 생성 방법에 대해 정리한 페이지입니다.

Posted
By HyunJinNo

Tags

monorepo, pnpm, React, tsdown

Environment

pnpm v10.32.1

react v19.2.3

tsdown v0.21.3

@tsdown/css v0.21.4

1. 개요

pnpm + tsdown으로 React 라이브러리를 만드는 방법에 대해 정리한 페이지입니다.

총 5개의 Part로 분리하여 작성하였으며, 이 페이지에서는 React 라이브러리 생성 과정을 다룹니다.

2. React 라이브러리 생성하기

2.1. React 라이브러리 초기화하기

프로젝트 루트에서 다음 명령어를 입력하여 React 라이브러리 폴더를 생성합니다.

bash
1mkdir -p packages/react-toc/src
2cd packages/react-toc

이후 다음 명령어를 입력하여 라이브러리를 초기화합니다.

bash
1pnpm init

생성된 package.json 파일을 열고 다음과 같이 라이브러리를 배포하기 위한 설정을 진행합니다.

json
1{
2  "name": "@hyunjinno/react-toc",
3  "version": "0.0.1",
4  "description": "A library that automatically generates a Table of Contents (TOC) from your headings with scroll tracking.",
5  "type": "module",
6  "main": "./dist/index.cjs",
7  "types": "./dist/index.d.cts",
8  "sideEffects": false,
9  "exports": {
10    ".": {
11      "types": "./dist/index.d.mts",
12      "import": "./dist/index.mjs",
13      "require": "./dist/index.cjs"
14    },
15    "./style.css": "./dist/style.css"
16  },
17  "files": ["dist"],
18  "scripts": {
19    "test": "echo \"Error: no test specified\" && exit 1",
20    "build": "tsdown",
21    "watch": "tsdown --watch ./src"
22  },
23  "keywords": ["toc", "table-of-contents"],
24  "author": "HyunJinNo",
25  "homepage": "https://hyunjinno.github.io/react-toc",
26  "repository": {
27    "type": "git",
28    "url": "https://github.com/HyunJinNo/react-toc"
29  },
30  "license": "MIT",
31  "peerDependencies": {
32    "react": "^18 || ^19",
33    "react-dom": "^18 || ^19"
34  }
35}

위의 package.json 설정 내용을 설명하면 다음과 같습니다.

2.1.1. 패키지 기본 정보

json
1{
2  "name": "@hyunjinno/react-toc",
3  "version": "0.0.1",
4  "description": "A library that automatically generates a Table of Contents (TOC) from your headings with scroll tracking."
5}
  • name
    npm에 배포되는 패키지 이름으로, @hyunjinno/...와 같이 스코프를 포함하도록 설정하였습니다. 추후 라이브러리를 배포한 후, npm install @hyunjinno/react-toc 명령어로 설치할 수 있습니다.
  • version
    현재 라이브러리 버전을 나타냅니다.
  • description
    패키지 설명 부분입니다.

2.1.2. 모듈 시스템 설정

json
1{
2  "type": "module",
3  "main": "./dist/index.cjs",
4  "types": "./dist/index.d.cts"
5}
  • type
    "type": "module"로 설정하면 기본을 ESM(ES Module)로 사용하게 되며, 모든 .js 파일이 ESM으로 해석됩니다.
  • main
    CommonJS 환경(require) 에서의 진입점입니다.
  • types
    TypeScript 타입 정의 파일을 지정하는 부분입니다.

2.1.3. sideEffects

json
1{
2  "sideEffects": false
3}

Tree-shaking 최적화를 통해 사용하지 않는 코드를 제거할 수 있습니다.

2.1.4. exports

json
1{
2  "exports": {
3    ".": {
4      "types": "./dist/index.d.mts",
5      "import": "./dist/index.mjs",
6      "require": "./dist/index.cjs"
7    },
8    "./style.css": "./dist/style.css"
9  }
10}

exports 옵션을 통해 ESM과 CJS 모두 지원하도록 설정합니다.

상황파일
ESM (import)index.mjs
CJS (require)index.cjs
타입index.d.mts
javascript
1import { Toc } from "@hyunjinno/react-toc";
javascript
1const { toc } = require("@hyunjinno/react-toc");

또한 CSS를 별도 export로 제공하도록 설정합니다.

javascript
1import "@hyunjinno/react-toc/style.css";

2.1.5. files

json
1{
2  "files": ["dist"]
3}

npm publishdist만 포함하도록 설정합니다.

2.1.7. scripts

json
1{
2  "scripts": {
3    "test": "echo \"Error: no test specified\" && exit 1",
4    "build": "tsdown",
5    "watch": "tsdown --watch ./src"
6  }
7}

위에서 설정한 명령어에 대해 설명하면 다음과 같습니다.

  • build
    tsdown 번들러를 통해 dist를 생성합니다.
  • watch
    watch 모드로 실행하면 코드 수정 시 자동으로 재빌드됩니다.

2.1.8. 메타 정보

json
1{
2  "keywords": ["toc", "table-of-contents"],
3  "author": "HyunJinNo",
4  "homepage": "https://hyunjinno.github.io/react-toc",
5  "repository": {
6    "type": "git",
7    "url": "https://github.com/HyunJinNo/react-toc"
8  },
9  "license": "MIT"
10}
  • keywords
    npm에 표시될 키워드 목록을 지정하는 부분입니다.
  • author
    라이브러리 제작자를 지정하는 부분입니다.
  • homepage
    npm에 표시될 Homepage를 지정하는 부분으로, 여기서는 GitHub Pages로 배포할 demo 웹사이트 URL을 작성하였습니다.
  • repository
    라이브러리 저장소를 지정하는 부분입니다.
  • license
    라이브러리 라이선스를 지정하는 부분입니다.

2.1.9. peerDependencies

json
1{
2  "peerDependencies": {
3    "react": "^18 || ^19",
4    "react-dom": "^18 || ^19"
5  }
6}

번들 중복 방지를 위해 peerDependencies에 React를 외부 의존성으로 지정합니다. 이를 통해 라이브러리 사용자가 React를 설치하게 됩니다.

2.2. tsconfig.json 설정하기

생성한 라이브러리 디렉토리에서 tsconfig.json 파일을 생성한 후, 프로젝트 루트에 있는 tsconfig.base.json을 확장하도록 설정합니다.

json
1{
2  "extends": "../../tsconfig.base.json",
3  "compilerOptions": {
4    "outDir": "dist",
5    "declaration": true,
6    "declarationDir": "dist"
7  },
8  "include": ["src"]
9}

2.3. React 라이브러리 의존성 설치하기

프로젝트 루트에서 다음 명령어를 입력하여 React 라이브러리 및 tsdown 번들러 의존성을 설치합니다.

bash
1pnpm add -Dw react react-dom @types/react @types/react-dom typescript tsdown

라이브러리에서 CSS도 제공할 경우, 다음 패키지를 설치할 수 있습니다.

bash
1pnpm add -Dw @tsdown/css

또한 특정 라이브러리에서만 필요한 의존성의 경우, 다음과 같이 설치할 수 있습니다.

bash
1pnpm add -D clsx

2.4. tsdown 설정하기

packages/react-toc 디렉토리에서 tsdown.config.ts 파일을 생성한 후, 다음과 같이 설정합니다.

typescript
1/* tsdown.config.ts */
2
3import { defineConfig } from "tsdown";
4
5export default defineConfig({
6  entry: ["./src/index.ts"],
7  format: ["esm", "cjs"],
8  dts: true,
9  clean: true,
10  deps: { neverBundle: ["react", "react-dom"] },
11});

위의 코드를 설명하자면 다음과 같습니다.

  • entry
    빌드 진입점을 설정합니다.
  • format
    ESM과 CJS 모두 지원하도록 설정합니다.
  • dts
    .d.ts 파일을 생성하도록 설정합니다.
  • clean
    라이브러리 빌드 전, 이전에 생성된 빌드 결과물을 삭제하도록 설정합니다.
  • deps
    React 번들을 제외하도록 설정합니다.

2.5. React 컴포넌트 생성하기

다음과 같이 라이브러리에서 사용하는 React 컴포넌트를 생성합니다.

typescript
1/* H2.tsx */
2
3import clsx from "clsx";
4
5type H2Props = Omit<
6  React.ComponentProps<"h2"> & {
7    children: string;
8  },
9  "id"
10>;
11
12export const H2 = ({ children, ...props }: H2Props) => {
13  return (
14    <h2 {...props} className={clsx("toc-heading", props.className)}>
15      {children}
16    </h2>
17  );
18};

2.6. style.css 생성하기

라이브러리에서 CSS 파일을 제공할 수 있습니다.

css
1.react-toc-wrapper {
2  display: flex;
3  flex-direction: column;
4  gap: 1rem;
5  border-left: 1px solid #dddddd;
6  height: fit-content;
7  padding-bottom: 1rem;
8}
9
10.react-toc-wrapper-heading {
11  padding-left: 1rem;
12  font-weight: 500;
13}
14
15.react-toc-list {
16  display: flex;
17  flex-direction: column;
18  gap: 0.625rem;
19}
20
21.react-toc-link {
22  overflow: hidden;
23  text-overflow: ellipsis;
24  white-space: nowrap;
25
26  &:hover {
27    color: #0056b2;
28  }
29}
30
31.react-toc-active {
32  border-left: 1px solid #0056b2;
33  color: #0056b2;
34  margin-left: -1px;
35}
36
37.react-toc-h2 {
38  padding-left: 1rem;
39}
40
41.react-toc-h3 {
42  padding-left: 1.75rem;
43}
44
45.react-toc-h4 {
46  padding-left: 2.5rem;
47}
48
49.react-toc-h5 {
50  padding-left: 3.25rem;
51}
52
53.react-toc-h6 {
54  padding-left: 4rem;
55}

2.7. index.ts 설정하기

라이브러리에서 제공하는 React 컴포넌트와 CSS 파일을 지정합니다.

typescript
1import "./style.css";
2
3export { H2 } from "./H2";
4export { H3 } from "./H3";
5export { H4 } from "./H4";
6export { H5 } from "./H5";
7export { H6 } from "./H6";
8export { Toc } from "./Toc";
9export { TocProvider } from "./TocProvider";

2.8. 라이브러리 빌드하기

다음 명령어를 입력하여 라이브러리 빌드를 수행할 수 있습니다.

bash
1pnpm run build

또는 watch 모드로 실행하여 코드 수정 시 자동으로 재빌드할 수 있습니다. watch 모드는 주로 개발 과정에서 사용합니다.

bash
1pnpm run watch

3. 다음 Part

다음 글에서는 Next.js demo 애플리케이션을 생성하고 라이브러리 문서를 작성하는 과정을 다룹니다.

3. Next.js demo 생성하기

4. 참고 자료

This post is licensed under CC BY 4.0 by the author.
공유하기:

© HyunJinNo. Some rights reserved.