commonJS는 코드를 불러오는 require 문이 동기적으로 발생한다. 따라서 위와 같은 코드를 번들링한다고 가정했을 때, 어떤 파일을 필요로할지 정적으로 판단할 수 없으므로 production.js와 development.js를 모두 포함한 번들링 결과가 만들어진다. 이는 commonJS에서 기본적으로 tree-shaking이 불가능한 이유이다. 반대로 es modules 에서는 파일의 맨 위에서 import 해야만 하기 때문에 정적으로 코드를 분석할 수 있다.
import { Button } from 'loplat-ui';
import { subtract } from 'lodash-es';
exports 를 이용하는 cjs 결과와는 달리 export 를 이용하여 컴포넌트를 내보내는 것을 확인할 수 있다.
하지만 여전히 tree shaking 이 되지 않는 것이 확인되었다.
index.js 라는 하나의 파일에 모든 라이브러리 코드가 들어있어, tree shaking을 하기엔 아직 힌트(hint)가 부족하다고 판단했다. 그래서 컴포넌트마다 output을 번들링하여 결과물을 쪼갰다.
import multiInput from 'rollup-plugin-multi-input';
...
export default {
// NOTE: tree shaking 을 위해 esm 파일들을 code splitting 하여 빌드한다.
input: ['src/**/index.ts', 'src/**/index.tsx', 'src/**/generated/*.tsx'],
output: [
{
dir: 'dist',
format: 'esm',
sourcemap: true,
},
],
...
이때, 'rollup-plugin-multi-input' 이라는 플러그인을 이용하여 input에 모든 컴포넌트를 넘겨주었다.
아래는 번들링 결과이다.
index.js에서 전체 컴포넌트에 대한 모든 로직과 코드(2번에서 var Add = ...)가 있는 것이 아니라, 각각의 컴포넌트로 쪼개진 js 파일을 단순히 export함을 알 수 있다. 즉 import { Button } from 'loplat-ui'; 라고 했을 때, components/Button/index.js 에 해당하는 코드만 가져온다면 원하는대로 tree-shaking이 될 것이라 기대했다.