현재 회사에서 디자인시스템을 모노레포로 만드는 작업을 하고 있다. 모노레포에 있는 각각의 라이브러리들을 rollup을 통해 번들링이되는데, 지금 모노레포와 rollup 관련해서 꽤나 삽질을 하고 있다. 그래도 배우는 것이 있어서 정리해보고자 한다.
현재 rollup.config.js파일이다. 여기선 결과물의 경로나 format을 정할 수 있다 cjs로 선택되어 있는 상태이다.
// rollup.config.js
output: {
dir: "lib",
format: "cjs",
exports: "named",
},
이렇게 나온 번들 결과물을 package.json에서 사용하겠다고 지정을 한다.
main은 이 라이브러리를 사용할 때 참조할 파일이고, types는 타입스크립트 파일이 되겠다.
그러면 module와 esm은 뭐고 왜 필요하지라는 궁금증이 생기게 되었다.
// package.json
{
...
"main": "lib/index.js",
"module": "lib/index.esm.js",
"types": "lib/index.d.ts",
...
}
여기서 우선 esm과 cjs의 차이를 알아보면 우선 코드상에서 import, export할 때의 차이가 있다는 걸 알 수 있다.
리액트로 개발하는 개발자라면 esm이 눈에는 더 익숙할 것이다.
이 외에도 차이가 다양하니 여기서 자세히보면 되겠다.
CommonJs (CJS)
// util.js
module.exports = (x, y) => x + y;
// main.js
const whateverWeWant = require('util');
console.log(whateverWeWant(2, 4));
ECMAScript Modules (ESM)
// util.js
export const sum = (x, y) => x + y;
// main.js
import { sum } from 'util'
console.log(sum(2, 4));
그래서 라이브러리의 빌드 결과로 나온 index.js 외에 index.esm.js는 왜 필요한 것인가?
main
라이브러리 빌드 결과의 메인 파일로 어떤 프로젝트에서 이 라이브러리를 설치하게되면 index.js 파일을 참조하게된다.
module
이 라이브러리를 설치한 프로젝트를 빌드할 때, index.esm.js를 참조해 빌드하게된다.
ems는 트리쉐이킹이 가능해 JavaScript 번들의 사이즈를 줄여서 렌더링이 중단되는 시간을 최소화는 효과가 있다.
위의 설명보다 자세히 예시를 들어보겠다.
프로젝트에서 아래와 같이 libraryA라는 라이브러리를 설치했다고하자.
import { Button } from "libraryA";
로컬에서 개발할 때 command나 ctrl을 누르상태로 libraryA 부분을 클릭하면 node_modules에 해당 라이브러리의 index.js파일을 가리키는 것을 확인할 수 있다. main에서 지정한 데로 index.js 파일에서 import가 된다는 것이다.
여기서 import로 불러오든 require로 불러오든 상관이 없다! 자세한 건 여기서 확인할 수 있다.
그런데 module에서 선택한 esm의 경우는 개발할 때가 아닌 번들링할 때 참조가 이뤄진다. 프로젝트 완성 후, 완성한 프로젝트를 번들러로 빌드를 할때 libraryA의 package.json의 module에서 지정한 esm형식을 참고해 빌드가 이뤄진다. 그리고 esm은 트리쉐이킹 가능해서 빌드할 때 프로젝트에서 libraryA에서 사용한 것만 긁어서 빌드가 된다.
위의 경우 Button만 import했다면 Button만 골라서 빌드가 된다는 것이다.
일반적으로 CommonJS형태는 트리쉐이킹을 할 수 없다. lodash를 예로 들면, lodash는 CommonJS 형태로 번들링되어 배포되기 때문에 webpack의 기본설정으로는 lodash를 트리쉐이킹 할 수 없다. 트리쉐이킹을 위해서는 babel-plugin-lodash을 사용하거나 lodash-es를 사용하는 것을 추천한다.
그래서 결론은 라이브러리를 만들 때 cjs와 esm을 둘다 제공해주는 것이 좋고 esm버전이 프로젝트의 번들사이즈를 줄이는 데 도움을 줄 수 있다는 것이다.
참고
- https://roseline.oopy.io/dev/translation-why-cjs-and-esm-cannot-get-along
- https://pencilflip.medium.com/using-es-modules-with-commonjs-modules-in-node-js-1015786dab03
- https://maeng2418.github.io/development/library_deploy/
- https://toss.tech/article/commonjs-esm-exports-field
'Developer > Javascript' 카테고리의 다른 글
Throttle와 Debounce 개념 알고 상황에 맞게 쓰기 (0) | 2023.03.02 |
---|---|
습관적으로 쓰는 async/await의 기초 (0) | 2021.12.08 |
만들 때마다 고민하게 되는 함수 이름 🤧 (0) | 2021.10.07 |
var, let, const 제대로 알기 (0) | 2021.09.24 |
함수 선언문과 함수 표현식 차이 (0) | 2021.09.23 |