rollup으로 번들링하는 과정

처음 rollup으로 번들링하는 과정에서 겪은 문제들과 해결방법

2024-03-09

monorepo를 사용해 패키지들을 분리하는 과정에서 이슈를 확인했다.

번들링 하지않고, 패키지들을 index.ts에서 직접 내보내 사용했을 때, 사용하지 않는 코드들도 함께 포함되는 문제가 있었다. 이 문제점을 확인하고 tree-shaking을 적용하기 위해 rollup을 사용하게 되었다.


tree-shaking

tree-shaking은 최종 번들링한 결과에서 사용하지 않는 코드를 제거하는 기능이다. 불필요한 코드가 없어지기 때문에 번들 파일의 크기를 줄일 수 있다.

tree-shaking은 ES6 부터(esm) 지원되는 기능이다.


rollup

먼저 약 10개정도 되는 패키지들을 각각 설정하는건 비효율 적이라 생각했다. 그래서 공통적으로 사용할 rollup.config.mjs 파일을 만들어 사용하기로 했다.

import path from 'path';
import { readFileSync } from 'fs';
import { DEFAULT_EXTENSIONS } from '@babel/core';
import babel from '@rollup/plugin-babel';
import commonjs from '@rollup/plugin-commonjs';
import resolve from '@rollup/plugin-node-resolve';
import typescript from '@rollup/plugin-typescript';
import builtins from 'builtin-modules';
import json from '@rollup/plugin-json';
import { defineConfig } from 'rollup';
import terser from '@rollup/plugin-terser';

const extensions = [...DEFAULT_EXTENSIONS, '.ts', '.tsx'];

export function generateRollupConfig({ packageDir }) {

  {...}

  const plugins = [
    resolve({
      extensions,
    }),
    commonjs(),
    babel({
      exclude: 'node_modules/**',
      extensions,
      babelHelpers: 'bundled',
    }),
    json(),
    typescript({
      compilerOptions: {
        outDir: 'dist',
        module: 'esnext',
        moduleResolution: 'bundler',
      },
      tsconfig: path.join(packageDir, 'tsconfig.json'),
    }),
    terser(),
  ];

  const generateConfig = (output) => {
    return {
      input,
      output,
      external,
      plugins,
    };
  };

  return defineConfig([
    generateConfig([
      {
        dir: output,
        format: 'cjs',
        entryFileNames: '[name].js',
      },
      {
        dir: output,
        format: 'esm',
        entryFileNames: '[name].mjs',
        preserveModules: true,
        preserveModulesRoot: path.dirname(input),
      },
    ]),
  ]);
}

*Note. @rollup/plugin-commonjs 보다 뒤에

*Note. @rollup/plugin-node-resolve와 함께 사용

*Note. @rollup/plugin-commonjs와 함께 사용

*Note. Use this plugin before any others such as node-resolve or commonjs, so they do not alter the output.


각 패키지별 번들링

import path from 'path';
import { generateRollupConfig } from '@repo/rollup-config';

const __dirname = path.resolve();

export default generateRollupConfig({ packageDir: __dirname });

utils에서 내보내는 함수 중 프로젝트별로 사용하는곳과 사용하지 않는 곳이 있었는데, 초기에 번들링과정을 거치지 않았을 때 프로젝트 빌드시 해당 함수를 각 프로젝트에 모두 포함되었다.

번들링 과정을 확인하기 위해 vite.config.js에

{...}

    build: {
      rollupOptions: {
        output: {
          manualChunks: {
            utils: ['@repo/utils']
          },
        },
      },
    },

{...}

옵션을 추가해 비교해보았다.

bundle-testbundle-test

전, 후 용량에 차이가 있다는걸 확인했고, js파일을 확인해 사용하는 함수만 포함되는었는지 확인해보았다.


처음 rollup을 사용해 패키지들을 번들링하면서 tree-shaking이라는 개념도 알게되었고, cjs와 esm의 차이점도 알게되었다.

다른 기업들의 오픈소스들을 뒤져가며 작업을 진행하면서 많은 것을 배울 수 있었던 시간이었다.

rollup 설정에 대해서 아직 완벽하게 이해하지는 못했으며, 내가 의도한대로 작동하는지도 조금 확신이 들지 않지만 이번 기회에 조금 더 깊게 공부해보고 계속해서 확인해보며 수정해나가야겠다. 개인적으로는 최적화해 나가는 과정이 매우 재밌었던 작업이었다!