rollup.js 간단 정리

vhv3y8·2024년 1월 9일
0

tool

목록 보기
1/2

rollup.js는 자바스크립트 모듈을 번들링해주는 번들러이다.

번들링은 여러 파일로 나누어져 있는 모듈을 하나의 파일로 합치는 것이다.

rollup.js는 ES6에서 자바스크립트에 추가된 ES Module, node.js에서 사용되는 CommonJS, 그리고 AMD 등의 모듈에 대해 번들링을 지원한다.

기본적으로는 ES Module을 번들링한다.

사용 방법

rollup은 CLI나 API로도 사용 가능하고, npm scripts로 사용할 수도 있다.

npm i -D rollup
// package.json
{
  "scripts": {
    "build": "rollup -c" // or "rollup --config"
  }
}

보통은 이런 식으로 프로젝트 폴더에 설치하고 config 파일을 작성하는 식으로 사용하는 듯하다.

간단한 예시들

우선 ES Module 파일들을 하나의 ES Module 파일로 합치거나, CommonJS 파일들을 하나의 CommonJS 파일로 합치는 건 당연히 가능하다.

그리고 ES Module로 작성된 여러 개의 파일들을 하나의 CommonJS 파일로 번들링할 수도 있고, 그 반대도 가능하다.

심지어 여러 종류의 모듈들이 섞인 파일들을 하나의 ES Module로 번들링하는 것도 가능하므로 유연하게 번들링하게 해준다.

유연하게 번들링 가능한 경우들을 예시로 알아보자.

  • ES Module -> CommonJS
  • CommonJS -> ES Module
  • ES Module & CommonJS -> ES Module

1. ES Module -> CommonJS

// package.json
{
  "type": "module",
  "scripts": {
	  "build": "rollup -c"
  },
  ...
}
// rollup.config.js
export default {
  input: "main.js",
  output: {
    file: "dist.js",
    format: "cjs",
  },
}

outputformat에 CommonJS를 뜻하는 cjs를 적어줬다.

// main.js | ES Module
import { giveOne } from "./es"

const a = giveOne()

export { a }
// es.js | ES Module
export function giveOne() {
  return 1
}

이런 상황일 때 npm run build를 실행해주면 다음과 같은 파일이 생성된다.

// dist.js | CommonJS
"use strict"

function giveOne() {
  return 1
}

const a = giveOne()

exports.a = a

2. CommonJS -> ES Module

rollup은 기본적으로 ES Module만 번들링할 수 있다.

다른 종류의 모듈을 번들링하려면 플러그인을 써야 한다.

플러그인은 Awesome Rollup에서 주로 찾을 수 있다고 한다.

그 중에는 CommonJS 모듈을 ES Module로 변환해주는 공식 플러그인 @rollup/plugin-commonjs도 있다.

그리고 node_modules에 있는 third party 모듈의 위치를 resolve 해주는 @rollup/plugin-node-resolve 플러그인도 사용해줘야 한다.

npm i -D @rollup/plugin-commonjs @rollup/plugin-node-resolve
// package.json
{
  "type": "module",
  "scripts": {
    "build": "rollup -c"
  },
  ...
}
// rollup.config.js
import commonjs from "@rollup/plugin-commonjs"
import resolve from "@rollup/plugin-node-resolve"

export default {
  input: "main.js",
  output: {
    file: "dist.js",
    format: "es",
  },
  plugins: [resolve(), commonjs()],
}
// main.js | CommonJS
const common = require("./common")

console.log(common)
// common.js | CommonJS
module.exports = {
  message: "hi from common",
}

여기서 npm run build를 실행해주면 다음과 같은 파일이 생성된다.

// dist.js | ES Module
var main = {}

var common$1 = {
  message: "hi from common",
}

const common = common$1

console.log(common)

export { main as default }

3. ES Module & CommonJS -> ES Module

ES Module 파일과 CommonJS 파일을 둘 다 포함시키고,

main.js에서는 공통적으로 ES Module 형태로 import 해보자.

// package.json
{
  "type": "module",
  "scripts": {
    "build": "rollup -c"
  },
  ...
}
// rollup.config.js
import commonjs from "@rollup/plugin-commonjs"
import resolve from "@rollup/plugin-node-resolve"

export default {
  input: "main.js",
  output: {
    file: "dist.js",
    format: "es",
  },
  plugins: [resolve(), commonjs()],
}
// main.js | ES Module
import { esMsg } from "./es"
import common from "./common"

console.log(common.msg)
console.log(esMsg)
// es.js | ES Module
export const esMsg = "hi from es"
// common.js | CommonJS
module.exports = {
  msg: "hi from common",
}

이 상태에서 npm run build를 실행하면 다음과 같은 파일을 생성한다.

// dist.js | ES Module
const esMsg = "hi from es"

function getDefaultExportFromCjs(x) {
  return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default")
    ? x["default"]
    : x
}

var common = {
  msg: "hi from common",
}

var common$1 = /*@__PURE__*/ getDefaultExportFromCjs(common)

console.log(common$1.msg)
console.log(esMsg)

여기서는 ES Module과 CommonJS 파일이 섞여 있어도 제대로 번들링 된다는 걸 알 수 있다.

Configuration 옵션

Configuration Options (rollupjs.org)

config 파일에서 내보내는 객체프로퍼티에 어떤 게 올 수 있는지는 이 문서를 보면 자세히 알 수 있다.

그리고 그 중에 output.format 부분을 보면, 다음과 같은 포맷의 파일로 번들링 할 수 있다는 걸 알 수 있다.

amd, cjs, es, iife, umd, system

Tree Shaking

실제로 사용되지 않는 코드를 제외시키는 걸 자바스크립트 쪽에서 Tree Shaking이라고 부른다고 한다.

rollup은 Tree Shaking을 지원한다.

즉, import 하는 코드들을 정적으로(static) 분석해서 실제로 사용되지 않는 코드를 제외시킨다.

간단한 예시를 짜보면 다음과 같다.

// rollup.config.js
export default {
  input: "main.js",
  output: {
    file: "dist.js",
    format: "es",
  },
}
// main.js
import { sayHi, notUsedA } from "./a"
import { sayBye, notUsedB } from "./b"

sayHi()
sayBye()
// a.js
export function sayHi() {
  console.log("hi")
}

export function notUsedA() {
  console.log("not used")
}
// b.js
export function sayBye() {
  console.log("bye")
}

export function notUsedB() {
  console.log("not used")
}

여기서 npm run build(rollup -c)를 실행해주면 다음과 같은 파일이 생성된다.

// dist.js
function sayHi() {
  console.log("hi")
}

function sayBye() {
  console.log("bye")
}

sayHi()
sayBye()

사용되지 않은 코드(notUsedA, notUsedB)들은 번들링 될 때 모두 제외되었다는 걸 알 수 있다.

multiple entry point

entry point가 여러 개인 config 파일은 다음처럼 작성할 수 있다고 한다.

// rollup.config.js
export default [
  {
    input: "a.js",
    output: {
      file: "dist/a.js",
      format: "es",
    },
  },
  {
    input: "b.js",
    output: {
      file: "dist/b.js",
      format: "es",
    },
  },
]

플러그인

번들이 크고 복잡해질수록 더욱 다양하고 유연한 기능들이 요구된다.

npm으로 설치한 모듈 사용하기, Babel로 transpile 하기, JSON 파일 사용하기 등등의 확장된 기능들은 플러그인을 통해 얻을 수 있다.

플러그인은 Awesome Rollup에서 주로 찾을 수 있다고 한다.

사용하는 방법은 config 파일에서 plugins 프로퍼티의 값에 배열로 담아주면 되는듯하다.

import json from "@rollup/plugin-json"

export default {
  input: "main.js",
  output: {
    file: "dist.js",
    format: "es",
  },
  plugins: [json()],
}

Plugin Development (rollupjs.org)

이제 이 문서를 바탕으로 실제 플러그인이 어떤 식으로 구성되는지 조금 알아보자.

Rollup plugin은 객체이며, 프로퍼티, 빌드 hook, output generation hook 중에 하나 이상을 갖는다고 한다.

그리고 그 중 핵심은 빌드 hook인듯하다.

Hooks는 번들링여러 스테이지에서 실행되는 함수들이라고 한다.

플러그인 객체에 지정된 이름의 함수를 작성하면, 번들링의 해당 스테이지에서 함수를 실행해주는 방식인듯하다.

options -> buildStart -> resolveId -> ... -> transform -> ...

구체적인 예시로, @rollup/plugin-jsonsrc/index.js 코드를 보면 대충 이런 식의 틀로 구성되어 있다 :

export default function json() {
  return {
    name: "json",
    transform() {},
  }
}

transform은 빌드 hook 이름이다.

config 파일에서는 plugins: [json()] 이런 식으로 사용되고, json 함수가 돌려주는 게 플러그인 객체인듯하다.

참고

profile
개발 기록, 미래의 나에게 설명하기

0개의 댓글