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),
},
]),
]);
}
@rollup/plugin-babel
: rollup + babel 연동
*Note. @rollup/plugin-commonjs 보다 뒤에
@rollup/plugin-commonjs
: CommonJS 모듈을 ES6으로 변환하여 롤업 번들에 포함
*Note. @rollup/plugin-node-resolve와 함께 사용
@rollup/plugin-node-resolve
: node_modules에 외부 모듈 확인
*Note. @rollup/plugin-commonjs와 함께 사용
@rollup/plugin-terser
: 간결하고 축소된 번들 생성 (띄어쓰기나 주석 제거)@rollup/plugin-url
: data-URIs, ESM으로 가져옴@rollup/plugin-virtual
: 메모리에서 가상 모듈을 로드
*Note. Use this plugin before any others such as node-resolve or commonjs, so they do not alter the output.
-
@svgr/rollup
: svgr 플러그인 -
builtin-modules
: node.js 빌트인 모듈 -
external
: 특정 모듈을 번들에 포함하지 않고, 외부 모듈로 설정
각 패키지별 번들링
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']
},
},
},
},
{...}
옵션을 추가해 비교해보았다.
전, 후 용량에 차이가 있다는걸 확인했고, js파일을 확인해 사용하는 함수만 포함되는었는지 확인해보았다.
처음 rollup을 사용해 패키지들을 번들링하면서 tree-shaking이라는 개념도 알게되었고, cjs와 esm의 차이점도 알게되었다.
다른 기업들의 오픈소스들을 뒤져가며 작업을 진행하면서 많은 것을 배울 수 있었던 시간이었다.
rollup 설정에 대해서 아직 완벽하게 이해하지는 못했으며, 내가 의도한대로 작동하는지도 조금 확신이 들지 않지만 이번 기회에 조금 더 깊게 공부해보고 계속해서 확인해보며 수정해나가야겠다. 개인적으로는 최적화해 나가는 과정이 매우 재밌었던 작업이었다!