React + Typescript + rollup 으로 컴포넌트 라이브러리 만들어보기

세니·2024년 6월 4일
0

리액트와 타입스크립트를 이용해 UI 컴포넌트 라이브러리를 사내에서 사용할 일이 생겼다. 이를 위해 간단한 UI 컴포넌트를 npm publish 말고 로컬 파일로 사용할 수 있도록 코드를 정리해보겠다.

필요 목록

  1. react ui component 작성
  2. index.js 파일 필요
  3. rollup config 번들러 작성
  4. package.json dependencies 정리

React UI Component 작성

// MyComponent.jsx
import React from 'react';

export default function MyComponent() {
	return (
		<div>hello</div>;
	)
}

// index.js
import MyComponent from './MyComponent.jsx';
export { MyComponent };

rollup이란

javascript 모듈 번들러로 ES6 모듈 형식으로 결과물을 생성한다.
트리 쉐이킹으로 최소한의 필수 요소만 포함하기 때문에 더 가볍고 빠르고 복잡한 라이브러리 애플리케이션을 만들 수 있다.

rollup을 이용해 빌드하기

import {babel} from "@rollup/plugin-babel";
import peerDepsExternal from "rollup-plugin-peer-deps-external";
import nodeResolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import typescript from "@rollup/plugin-typescript";

export default {
  input: "./src/index.ts", // 진입점
  output: {
    file: './dist/bundle.js',
    format: 'esm', // esmodule로 output
    sourcemap: true,
  },
  plugins: [
    peerDepsExternal(),
    nodeResolve(),
    commonjs(),
    babel({
      babelHelpers: 'bundled',
      extensions: ['.js', '.jsx', '.ts', '.tsx'],
      presets: ["@babel/env", "@babel/react", "@babel/preset-typescript"]
    }),
    typescript() // typescript compile
  ]
};

rollup plugin

  • rollup-plugin-peer-deps-external
    package.json의 peerDenpendencies를 제외하고 번들을 한다.
    사용하고자 하는 프로젝트의 의존성에 맞추기 위해 제거하면 번들 사이즈도 작아진다.
  • @rollup/plugin-node-resolve
    node-modules에서 third party 모듈을 사용하기 위해 Node.js 모듈 해석 알고리즘을 사용해 모듈을 찾는다.
  • @rollup/plugin-commonjs
    CommonJS 코드를 ES6로 변환하는 플러그인
  • @rollup/plugin-babel
    rollup과 babel의 통합을 위한 플러그인

babelHelpers
해당 바벨 헬퍼가 코드에 삽입되는 방법을 결정하는지 명시적으로 구성해야 한다.

runtime: 헬퍼 함수를 @babel/runtime 라이브러리에서 가져온다.
bundled: 헬퍼 함수가 각 번들 파일에 포함된다. 기본설정
inline: 각 헬퍼 함수가 각 파일에 인라인으로 삽입된다.
external: 헬퍼 함수를 외부 모듈로 설정한다.

extensions : babel이 변환해야하는 파일 확장자들

package.json 파일 작성하기

{
  "name": "MyComponent",
  "version": "1.0.0",
  "description": "",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "rollup -c",
    "doc": "typedoc --out ./docs",
    "prepack": "rimraf ./package && npm run build && npm run doc && mkdirp ./package ./package/docs ./package/dist && xcopy README.md .\\package\\ /k /Y && xcopy package.json .\\package\\ /k /Y && xcopy docs\\*.* .\\package\\docs\\*.* /e /h /k /Y && xcopy dist\\*.* .\\package\\dist\\*.* /e /h /k /Y && json -I -f ./package/package.json -e \"this.main='dist/bundle.js';this.types='dist/types/index.d.ts'\"",
    "pack": "tar cvzf my_component.tar.gz package/*"
  },
  "author": "",
  "license": "ISC",
  "main": "./dist/bundle.js",
  "devDependencies": {
    "@babel/core": "^7.19.1",
    "@babel/preset-env": "^7.19.1",
    "@babel/preset-react": "^7.18.6",
    "@rollup/plugin-babel": "^5.3.1",
    "@rollup/plugin-commonjs": "^22.0.0",
    "@rollup/plugin-node-resolve": "^13.3.0",
    "babel-loader": "^9.1.3",
    "rollup": "^2.79.0",
    "rollup-plugin-peer-deps-external": "^2.2.4"
  },
  "peerDependencies": {
    "react": "^18.0.0",
    "react-dom": "^18.0.0"
  }
}

저는 이전 글에서 작성했던 패키지화 하는 방식으로 라이브러리화를 하였습니다. npm run pack을 하면 간편하게 패키지를 뽑을 수 있습니다.

사용하기

MyComponent 에서 npm package 설치 후 npm run build를 수행한다.

사용하려는 프로젝트에서 MyComponent를 로컬적으로 사용하려면 npm i path로 설치하면 된다.

// other project
import React from 'react';
import { MyComponent } from 'my-component';

export default function App() {
	return (
	<>
		<MyComponent />
	</>
	)
}
profile
세니는 무엇을 하고 있을까

0개의 댓글