5-1. Rollup으로 라이브러리 번들하기

자, 이제 Rollup으로 우리가 만든 라이브러리를 번들해서 배포 할 준비를 해줍시다.

rollup에 필요한 패키지 설치하기

우선 Rollup을 사용하기 위하여 필요한 패키지들을 설치해주세요.

yarn add --dev rollup rollup-plugin-babel rollup-plugin-node-resolve rollup-plugin-peer-deps-external rollup-plugin-commonjs @svgr/rollup rollup-plugin-url
# 또는 npm install --save-dev rollup rollup-plugin-babel rollup-plugin-node-resolve rollup-plugin-peer-deps-external rollup-plugin-commonjs @svgr/rollup rollup-plugin-url

rollup 패키지를 비롯하여 다양한 plugin들을 설치해줬습니다.

  • rollup-plugin-babel: rollup에서 babel 을 사용 할 수 있게 해주는 플러그인입니다.

  • rollup-plugin-node-resolve: node_modules에서 써드파티 모듈을 사용하는 용도로 사용하며, js 이외의 확장자 (ts, tsx) 파일을 불러오기 위해서도 이 플러그인을 필요로 합니다.

  • rollup-plugin-peer-deps-external: peerDependency로 설치된 라이브러리의 코드가 번들링된 결과에 포함되지 않고, import 구문으로 불러와서 사용할 수 있게 만들어줍니다.

  • rollup-plugin-commonjs: CommonJS 형태로 이루어진 모듈의 코드를 ES6로 변환하여 결과물에 포함될 수 있게 해줍니다. (현재 우리 프로젝트에서는 필수로 적용해야하는 플러그인은 아닙니다)

  • @svgr/rollup: SVG를 컴포넌트 형태로 불러와서 사용 할 수 있게 해줍니다.

  • rollup-plugin-url: data-URI형태로 svg, png, jpg 파일 등을 불러와서 사용 할 수 있게 해줍니다. @svgr/rollup 플러그인을 사용 할 때, rollup-plugin-url과 함께 사용을 해야만 import { ReactComponent as icon } from './icon.svg' 형태의 코드를 사용 할 수 있습니다.

peerDependency 설정하기

그 다음에는 react와 react-dom을 peerDependency 로 설치해주세요. 해당 모듈은 현재 프로젝트에 이미 설치되어있긴 하지만, 설치되어있는 이유는 devDependency에 있는 @storybook/react 에서 의존하고 있기 때문입니다.

yarn add --peer react react-dom
# 또는 npm install --save react react-dom

package.json 을 열어보세요. peerDependencies 값이 다음과 같이 채워져있나요?

  "peerDependencies": {
    "@emotion/core": "^10.0.22",
    "react": "^16.12.0",
    "react-dom": "^16.12.0",
    "react-spring": "^8.0.27"
  }

yarn을 사용하지 않고 npm을 사용하신 분들은 peerDependencies 가 아닌 dependencies 로 설치가 되어있을 것입니다. 그런 경우에는, 그냥 텍스트를 바로 peerDependencies로 교체하시면 됩니다.

package.json 수정하기

package.json 의 상단부에서 name 값을 react-uikit-username 으로 변경하세요. username 부분엔 여러분의 아이디를 넣으세요.

그 다음에는, main 을 지우시고, module 값을 "dist/index.js" 로 설정하세요. 이는 우리가 ESModule 형태로 빌드한 결과물을 저장 할 경로를 의미합니다. 나중에 우리가 만든 패키지를 설치하고 불러오게 되면 이 module 값을 참조하여 코드를 불러오게 됩니다.

{
  "name": "react-uikit-sample",
  "version": "1.0.0",
  "module": "dist/index.js",

rollup.config.js 작성하기

rollup을 사용하게 될 때 단순히 명령어로 옵션을 정해줄 수도 있지만 더욱 편리한 설정을 위하여 설정파일을 만들어서 작업할수도 있습니다.

프로젝트의 루트 디렉터리에 rollup.config.js 를 생성하고, 다음 코드를 입력해보세요.

rollup.config.js

import commonjs from 'rollup-plugin-commonjs';
import resolve from 'rollup-plugin-node-resolve';
import babel from 'rollup-plugin-babel';
import pkg from './package.json';
import external from 'rollup-plugin-peer-deps-external';
import svgr from '@svgr/rollup';
import url from 'rollup-plugin-url';
import peerDepsExternal from 'rollup-plugin-peer-deps-external';

const extensions = ['.js', '.jsx', '.ts', '.tsx']; // 어떤 확장자를 처리 할 지 정함

// babel-preset-react-app를 사용한다면 BABEL_ENV를 필수로 설정해야함.
process.env.BABEL_ENV = 'production';

export default {
  input: './src/index.ts', // 어떤 파일부터 불러올지 정함.
  plugins: [
    peerDepsExternal() /* peerDependencies로 설치한 라이브러리들을 external 모듈로 설정
                               즉, 번들링된 결과에 포함시키지 않음 */,
    resolve({ extensions }), // node_modules 에서 모듈을 불러올 수 있게 해줌. ts/tsx 파일도 불러올 수 있게 해줌
    commonjs({
      include: 'node_modules/**'
    }), // CommonJS 형태로 만들어진 모듈도 불러와서 사용 할 수 있게 해줌. 현재 프로젝트 상황에서는 없어도 무방함
    babel({ extensions, include: ['src/**/*'], runtimeHelpers: true }), // Babel을 사용 할 수 있게 해줌
    url(), // 미디어 파일을 dataURI 형태로 불러와서 사용 할 수 있게 해줌.
    svgr() // SVG를 컴포넌트로 사용 할 수 있게 해줌.
  ],
  output: [
    {
      file: pkg.module, // 번들링한 파일을 저장 할 경로
      format: 'es' // ES Module 형태로 번들링함
    }
  ]
};

그 다음에는 babel 을 위한 설정을 해주어야 합니다. .babelrc 파일을 루트경로에 생성한 뒤, 다음 코드를 입력하세요.

.babelrc

{
  "presets": [["react-app", { "flow": false, "typescript": true }]]
}

참고로, .babelrc 파일을 만들지 않아도 babel rollup 플러그인 옵션 객체에 presets 값을 넣어주셔도 상관 없습니다.

빌드를 하기 전에, src 에 index.ts 파일을 만들어주세요. 이 파일에서는 우리가 만들었던 컴포넌트를 불러와서, 바로 내보내줍니다.

src/index.ts

export { default as Button } from './Button/Button';
export { default as ButtonGroup } from './ButtonGroup/ButtonGroup';
export { default as Dialog } from './Dialog/Dialog';
export { default as Icon } from './Icon/Icon';

이제 한번 빌드를 해봅시다! 다음 명령어를 입력해보세요.

yarn rollup -c
# 또는 ./node_modules/rollup/dist/bin/rollup -c

위와 같은 결과물이 나타날것입니다.

이 명령어를 package.json 에서 스크립트로 지정해봅시다.

yarn build (또는 npm build) 라고 입력해서 잘 작동하는지 확인해보세요.

성공적으로 빌드가 됐다면, dist/index.js 파일이 생성됐을 것입니다.

TypeScript declaration 파일 만들기

declaration이란, 우리가 만든 컴포넌트들에서 사용하고 있는 타입 정보들을 지니고 있는 파일을 의미합니다. 이는 다음 명령어로 생성을 할 수 있는데요

tsc --emitDeclarationOnly

이 명령어를 실행하기 전에 tsconfig.json 을 수정해주어야 합니다.

{
  "compilerOptions": {
    "target": "es5",
    "lib": ["dom", "dom.iterable", "esnext"],
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "jsx": "react",
    "declaration": true,
    "declarationDir": "dist/types"
  },
  "include": ["src"],
  "exclude": ["**/*.stories.tsx"]
}

위와 같이 declaration 값을 true 로 바꾸고 declarationDir 경로를 "dist/types" 로 정해주면 되는데요, 이 두가지 값을 추가하고 나면 기존에 있던 몇가지 옵션이 충돌나게 됩니다.

  • allowJs: 자바스크립트와 혼용을 하고 있다면 declaration 파일을 못만듭니다. 이 옵션을 제거해주세요.

  • noEmit: 결과물을 만들지 않는다는 옵션입니다. 이 옵션을 제거해주세요.

  • isolatedModules: 아무 값도 내보내지 않는 파일을 방지하는 옵션입니다. 이 옵션을 제거해주세요.

추가적으로, stories.tsx 확장자는 모두 무시하도록 exclude 옵션을 설정하셔야 합니다.

이제, package.json 을 열어서 다음과 같이 build:types 스크립트를 추가해보세요.

"scripts": {
  "storybook": "start-storybook -p 6006",
  "build-storybook": "build-storybook",
  "build": "rollup -c",
  "build:types": "tsc --emitDeclarationOnly"
},

그 다음에 yarn build:types 를 입력해보세요.

dist/types/index.d.ts 파일이 잘 만들어졌나요?

파일이 잘 만들어졌다면 package.json에서 definition 파일의 경로를 명시해주세요.

{
    "name": "react-uikit-sample",
    "version": "1.0.0",
    "module": "dist/index.js",
    "license": "MIT",
    "types": "dist/types/index.d.ts",
  ...

나중에 이 패키지를 설치해서 사용하게 될 때 TypeScript 컴파일러에서 자동으로dist/types/index.d.ts 에서 선언한 타입을 참고하게 된답니다.

Last updated