본문 바로가기

FrontEnd

Rollup.js 알아보기 1편 : Rollup.js 튜토리얼

반응형

요즘 많이 사용하는 Vite 플러그인(vite plugin)은 롤업 플러그인의 슈퍼셋입니다.

Rollup.js 플러그인의 아키텍처와 작성방법을 알면 Vite 플러그인에 대해 깊히 이해할 수 있습습니다.

Vite 플러그인은 몇 가지 추가 Vite 관련 옵션으로 Rollup의 잘 설계된 플러그인 인터페이스를 확장합니다.

rollupj.s 공식문서의 튜토리얼을 정리한 글입니다.

해당 튜토리얼을 통해 rollup.js의 매우 기본적인 기능들을 파악할 수 있습니다.

(파일을 입력으로 받아, 출력 파일로 번들링, 트리 셰이킹, 코드 스플리팅, js 이외의 파일 처리하기)

Rolliip.js

번들 만들어보기

Rollup을 사용하는 가장 쉬운 방법은 명령줄 인터페이스(또는 CLI)를 사용하는 것입니다.
먼저, rollup을 전역 설치합니다.
npm install rollup --global
# or `npm i rollup -g` for short
이제 롤업 명령을 실행할 수 있습니다. 
rollup

인수가 전달되지 않았기 때문에 Rollup은 사용 지침을 인쇄합니다.
이는 rollup --help 또는 rollup -h를 실행하는 것과 동일합니다.

 

간단한 프로젝트를 만들어 봅시다:
mkdir -p my-rollup-project/src
cd my-rollup-project

먼저 프로젝트 진입점이 필요합니다. 이것을 src/main.js라는 새 파일에 복사 / 붙여넣기 합니다.

// src/main.js
import foo from './foo.js';
export default function () {
  console.log(foo);
}
그런 다음 진입점이 가져오는 foo.js 모듈을 생성해 보겠습니다.
// src/foo.js
export default 'hello world!';
이제 번들을 만들 준비가 되었습니다.
rollup src/main.js -f cjs
-f 옵션(--format의 줄임말)은 생성할 번들의 포맷을 지정합니다. 이 경우 CommonJS(Node.js에서 실행됨)입니다.
출력 파일 포맷을 지정하지 않았기 때문에 stdout에 바로 출력됩니다.
'use strict';

const foo = 'hello world!';

const main = function () {
  console.log(foo);
};

module.exports = main;
다음과 같이 번들을 파일로 저장할 수 있습니다.
rollup src/main.js -o bundle.js -f cjs

(rollup src/main.js -f cjs > bundle.js를 수행할 수도 있지만
나중에 살펴보겠지만 소스맵을 생성하는 경우 유연성이 떨어집니다.) 코드를 실행해 보세요.

node
> var myBundle = require('./bundle.js');
> myBundle();
'hello world!'
축하합니다! Rollup으로 첫 번째 번들을 만들었습니다.

설정 파일 사용하기

더 많은 옵션을 추가하기 시작하면 cli를 사용하는 것이 성가신 일이 됩니다.
필요한 모든 옵션을 포함하며 반복해서 사용할 수 있는 설정 파일을 만들 수 있습니다.
설정 파일은 JavaScript로 작성되며 CLI보다 더 유연합니다.

rollup.config.js라는 프로젝트 루트에 파일을 만들고 다음 코드를 추가합니다.
// rollup.config.js
export default {
  input: 'src/main.js',
  output: {
    file: 'bundle.js',
    format: 'cjs'
  }
};

(CJS 모듈을 사용할 수 있으므로 module.exports = {/* config */})
설정 파일을 사용하려면 --config 또는 -c 플래그를 사용합니다.

rm bundle.js # so we can check the command works!
rollup -c
동등한 기능의 명령줄 옵션을 사용하여 설정 파일의 모든 옵션을 재정의할 수 있습니다.
rollup -c -o bundle-2.js # `-o` is equivalent to `--file` (formerly "output")
Note: Rollup 자체는 config 파일을 처리하므로 export default 구문을 사용할 수 있습니다.
코드는 Babel 또는 이와 유사한 것을 이용해 변환되지 않으므로
Node 버전에서 지원되는 ES2015 기능만 사용할 수 있습니다.
 
원하는 경우 기본 rollup.config.js와 다른 설정 파일을 지정할 수 있습니다.
rollup --config rollup.config.dev.js
rollup --config rollup.config.prod.js

프로젝트 의존성으로 롤업 설치

팀 또는 분산 환경에서 작업할 때 롤업을 로컬 종속성으로 추가하는 것이 좋습니다.
Rollup을 로컬에 설치하면 여러 기여자가 별도의 추가 단계로 Rollup을 설치해야 하는 요구 사항을 방지하고
모든 기여자가 동일한 버전의 Rollup을 사용할 수 있습니다.
 
NPM을 사용하여 로컬로 롤업을 설치하려면:
npm install rollup --save-dev
설치 후 롤업은 프로젝트의 루트 디렉터리 내에서 실행할 수 있습니다.
npx rollup --config
package.json에 단일 빌드 스크립트를 추가하여 모든 기여자에게 편리한 명령을 제공하는 것이 일반적입니다.
{
  "scripts": {
    "build": "rollup --config"
  }
}

참고: 로컬 설치 시 패키지 스크립트에서 호출될 때

NPM과 Yarn 모두 종속성의 bin 파일을 확인하고 Rollup을 실행합니다.

플러그인 사용하기

지금까지 상대 경로를 통해 가져온 모듈과 진입점에서 간단한 번들을 만들었습니다.
더 복잡한 번들을 빌드하기 위하여,
NPM으로 설치된 모듈 가져오기, Babel로 코드 컴파일, JSON 파일 작업 등
더 많은 유연성이 필요한 경우가 많습니다.
 
이를 위해 번들링 프로세스의 주요 지점에서 롤업의 동작을 변경하는 플러그인을 사용합니다.
the Rollup Awesome List 에서 여러 멋진 플러그인을 구경할 수 있습니다.
 
이 자습서에서는 Rollup이 JSON 파일에서 데이터를 가져올 수 있도록 하는 @rollup/plugin-json을 사용합니다.
package.json이라는 프로젝트 루트에 파일을 만들고 다음 콘텐츠를 추가합니다.
{
  "name": "rollup-tutorial",
  "version": "1.0.0",
  "scripts": {
    "build": "rollup -c"
  }
}
개발 종속성으로 @rollup/plugin-json을 설치합니다.
npm install --save-dev @rollup/plugin-json
( --save 대신 --save-dev 를 사용하고 있습니다. 
코드가 실행될 때 실제로 플러그인에 의존하지 않기 때문입니다. 
번들을 빌드할 때만 해당 의존성을 사용합니다.)
src/foo.js 대신 package.json에서 가져오도록 src/main.js 파일을 업데이트합니다.
// src/main.js
import { version } from '../package.json';

export default function () {
  console.log('version ' + version);
}
JSON 플러그인을 포함하도록 rollup.config.js 파일을 편집합니다.
// rollup.config.js
import json from '@rollup/plugin-json';

export default {
  input: 'src/main.js',
  output: {
    file: 'bundle.js',
    format: 'cjs'
  },
  plugins: [json()]
};
npm 실행 빌드로 롤업을 실행합니다. 출력 결과는 다음과 같아야 합니다.
'use strict';

var version = '1.0.0';

function main() {
  console.log('version ' + version);
}

module.exports = main;

참고: 실제로 필요한 데이터만 가져옵니다. name 및 devDependencies와 package.json의 다른 부분은 무시합니다.
이를 트리 셰이킹이라 합니다.

출력 플러그인 사용하기

일부 플러그인은 일부 출력에 특별히 적용될 수도 있습니다.
출력별 플러그인이 할 수 있는 일에 대한 기술적 세부사항은 plugin hooks를 참조하세요.
간단히 말해서 이러한 플러그인은 Rollup의 기본 분석이 완료된 후에만 코드를 수정할 수 있습니다.
Rollup은 호환되지 않는 플러그인이 출력 관련 플러그인으로 사용되는 경우 경고합니다.
출력 플러그인의 사용 사례 중 하나는 브라우저에서 사용할 번들을 최소화하는 것입니다.

이전 예제를 확장하여 축소(minify)되지 않은 빌드와 함께 축소된 빌드를 제공하겠습니다.
이를 위해 @rollup/plugin-terser를 설치합니다.

npm install --save-dev @rollup/plugin-terser
두 번째 출력 파일로 축소된 출력을 추가하려면 rollup.config.js 파일을 편집합니다.
포맷으로 iife를 선택합니다.
이 포맷은 다른 코드와의 원치 않는 상호 작용을 피하면서 브라우저의 스크립트 태그를 통해 사용할 수 있도록 코드를 래핑합니다.
해당 번들에는 export가 있으므로
다른 코드가 이 변수를 통해 내보내기에 액세스할 수 있도록
번들에서 생성할 전역 변수의 이름(version)을 제공해야 합니다.
// rollup.config.js
import json from '@rollup/plugin-json';
import terser from '@rollup/plugin-terser';

export default {
  input: 'src/main.js',
  output: [
    {
      file: 'bundle.js',
      format: 'cjs'
    },
    {
      file: 'bundle.min.js',
      format: 'iife',
      name: 'version',
      plugins: [terser()]
    }
  ],
  plugins: [json()]
};
​
bundle.js 외에도 Rollup은 이제 두 번째 파일인 bundle.min.js를 생성합니다.
var version = (function () {
  'use strict';
  var n = '1.0.0';
  return function () {
    console.log('version ' + n);
  };
})();

코드 스플리팅

코드 스플리팅의 경우
  • 롤업이 다이나믹 로딩 또는 멀티 엔트리와 같이 자동으로 코드를 청크로 분할하는 경우가 있으며
  • output.manualChunks 옵션을 통해 어떤 모듈을 별도의 청크로 분할할지 롤업에 명시적으로 알리는 방법이 있습니다.
코드 분할 기능을 사용하여 지연 다이나믹 로딩(일부 임포트한 모듈은 함수 실행 후에만 로드됨)을 달성하기 위해
원래 예제로 돌아가서 정적 대신 동적으로 src/foo.js를 로드하도록 src/main.js를 수정합니다. 
// src/main.js
export default function () {
  import('./foo.js').then(({ default: foo }) => console.log(foo));
}

롤업은 동적 임포트를 사용하여 요청 시에만 로드되는 별도의 청크를 생성합니다.
Rollup이 두 번째 청크를 배치할 위치를 알기 위해 --file 옵션을 전달하는 대신 --dir 옵션을 사용하여 출력할 폴더를 설정합니다.

rollup src/main.js -f cjs -d dist

이 명령어는 두 개의 파일, main.js 및 chunk-[hash].js를 포함하는 dist 폴더를 생성합니다.
여기서 [hash]는 콘텐츠 기반 해시 문자열입니다. 
output.chunkFileNamesoutput.entryFileNames 옵션을 지정하여 고유한 이름 지정 패턴을 제공할 수 있습니다.

 

./foo.js의 로드 및 구문 분석은 처음으로 내보낸 함수를 호출한 후에만 시작되기 때문에 조금 더 느리지만

이전과 마찬가지로 동일한 출력으로 코드를 실행할 수 있습니다

node -e "require('./dist/main.js')()"
--dir 옵션을 사용하지 않으면 Rollup은 청크 경계를 강조 표시하는 주석을 추가하여 청크를 stdout에 다시 인쇄합니다.
//→ main.js:
'use strict';

function main() {
  Promise.resolve(require('./chunk-b8774ea3.js')).then(({ default: foo }) => console.log(foo));
}

module.exports = main;

//→ chunk-b8774ea3.js:
('use strict');

var foo = 'hello world!';

exports.default = foo;
비용이 많이 드는 기능을 사용한 후에만 로드하고 구문 분석하려는 경우에 유용합니다.
코드 분할의 다른 용도는 일부 종속성을 공유하는 여러 진입점을 지정하는 기능입니다.
다시 예제를 확장하여 원래 예제에서 수행한 것처럼 src/foo.js를 정적으로 가져오는
두 번째 진입점 src/main2.js를 추가합니다.
// src/main2.js
import foo from './foo.js';
export default function () {
  console.log(foo);
}​
롤업에 두 진입점을 모두 제공하면 세 개의 청크가 생성됩니다.
rollup src/main.js src/main2.js -f cjs

해당 명령어는 다음 출력을 생성합니다.

//→ main.js:
'use strict';

function main() {
  Promise.resolve(require('./chunk-b8774ea3.js')).then(({ default: foo }) => console.log(foo));
}

module.exports = main;

//→ main2.js:
('use strict');

var foo_js = require('./chunk-b8774ea3.js');

function main2() {
  console.log(foo_js.default);
}

module.exports = main2;

//→ chunk-b8774ea3.js:
('use strict');

var foo = 'hello world!';

exports.default = foo;

두 진입점이 동일한 공유 청크를 어떻게 가져오는지 확인하세요
롤업은 코드를 복제하지 않으며 대신 필요한 최소한의 항목만 로드하기 위해 추가 청크를 생성합니다.
다시 --dir 옵션을 전달하면 파일이 디스크에 기록됩니다.

 

네이티브 ES 모듈, AMD 로더 또는 SystemJS를 통해 브라우저에 대해 동일한 코드를 빌드할 수 있습니다.
예를 들어 네이티브 모듈 포맷을 위해 -f es를 사용하면 다음과 같습니다.

rollup src/main.js src/main2.js -f es -d dist
<!DOCTYPE html>
<script type="module">
  import main2 from './dist/main2.js';
  main2();
</script>
또는 -f system을 사용하는 SystemJS의 경우:
rollup src/main.js src/main2.js -f system -d dist
다음을 통해 SystemJS 설치합니다.
npm install --save-dev systemjs
필요에 따라 HTML 페이지에서 진입점 중 하나 또는 둘 모두를 로드합니다.
<!DOCTYPE html>
<script src="node_modules/systemjs/dist/s.min.js"></script>
<script>
  System.import('./dist/main2.js').then(({ default: main }) => main());
</script>

필요에 따라 SystemJS로 대체하여 지원하는 브라우저에서 기본 ES 모듈을 사용하는 웹 앱을 설정하는 방법에 대한 예제는
rollup-starter-code-splitting을 참조하세요.

반응형