2020-06-27 rollup の rollup-starter-lib を試した

rollup の rollup-starter-lib を試した。 の README の Getting started に従う。

$ git clone
# ...
$ cd rollup-starter-lib
$ npm install
# ...
$ exa -T --git-ignore --group-directories-first
├── src
│  ├── lunchtime.js
│  ├── main.js
│  └── millisecondsUntil.js
├── test
│  └── test.js
├── package-lock.json
├── package.json
└── rollup.config.js


まずは package.json を見る

  "name": "rollup-starter-lib",
  "version": "1.0.0",
  "main": "dist/how-long-till-lunch.cjs.js",
  "module": "dist/how-long-till-lunch.esm.js",
  "browser": "dist/how-long-till-lunch.umd.js",
  "dependencies": {
    "ms": "^2.0.0"
  "devDependencies": {
    "@rollup/plugin-commonjs": "^11.0.1",
    "@rollup/plugin-node-resolve": "^7.0.0",
    "rollup": "^1.29.0"
  "scripts": {
    "build": "rollup -c",
    "dev": "rollup -c -w",
    "test": "node test/test.js",
    "pretest": "npm run build"
  "files": ["dist"]

main / module / browser でエントリポイントを書き分けてあるのが印象的だ。各環境に一気に対応できるのだろう。あとで dist に生成されるものを確認する。

dependenciesms は用意されている例 src/main.js から使われているようだ。

devDependencies@rollup/plugin-* が気になるけど後回しにする。

scriptsrollup -c を何かしら動かすっぽい。 rollup -c -w-w はたぶん watch だろう。

$ (npm bin)/rollup --help

rollup version 1.29.0

Usage: rollup [options] <entry file>

Basic options:

-c, --config <filename>     Use this config file (if argument is used but value
                              is unspecified, defaults to rollup.config.js)
-d, --dir <dirname>         Directory for chunks (if absent, prints to stdout)
-e, --external <ids>        Comma-separate list of module IDs to exclude
-f, --format <format>       Type of output (amd, cjs, esm, iife, umd)
-g, --globals <pairs>       Comma-separate list of `moduleID:Global` pairs
-h, --help                  Show this help message
-i, --input <filename>      Input (alternative to <entry file>)
-m, --sourcemap             Generate sourcemap (`-m inline` for inline map)
-n, --name <name>           Name for UMD export
-o, --file <output>         Single output file (if absent, prints to stdout)
-v, --version               Show version number
-w, --watch                 Watch files in bundle and rebuild on changes <id>               ID for AMD module (default is anonymous)
--amd.define <name>         Function to use in place of `define`
--assetFileNames <pattern>  Name pattern for emitted assets
--banner <text>             Code to insert at top of bundle (outside wrapper)
--chunkFileNames <pattern>  Name pattern for emitted secondary chunks
--compact                   Minify wrapper code
--context <variable>        Specify top-level `this` value
--dynamicImportFunction <name>         Rename the dynamic `import()` function
--entryFileNames <pattern>  Name pattern for emitted entry chunks
--environment <values>      Settings passed to config file (see example)
--no-esModule               Do not add __esModule property
--exports <mode>            Specify export mode (auto, default, named, none)
--extend                    Extend global variable defined by --name
--footer <text>             Code to insert at end of bundle (outside wrapper)
--no-freeze                 Do not freeze namespace objects
--no-indent                 Don't indent result
--no-interop                Do not include interop block
--inlineDynamicImports      Create single bundle when using dynamic imports
--intro <text>              Code to insert at top of bundle (inside wrapper)
--namespaceToStringTag      Create proper `.toString` methods for namespaces
--noConflict                Generate a noConflict method for UMD globals
--no-strict                 Don't emit `"use strict";` in the generated modules
--outro <text>              Code to insert at end of bundle (inside wrapper)
--preferConst               Use `const` instead of `var` for exports
--preserveModules           Preserve module structure
--preserveSymlinks          Do not follow symlinks when resolving files
--shimMissingExports        Create shim variables for missing exports
--silent                    Don't print warnings
--sourcemapExcludeSources   Do not include source code in source maps
--sourcemapFile <file>      Specify bundle position for source maps
--strictDeprecations        Throw errors for deprecated features
--no-treeshake              Disable tree-shaking optimisations
--no-treeshake.annotations  Ignore pure call annotations
--no-treeshake.propertyReadSideEffects Ignore property access side-effects
--treeshake.pureExternalModules        Assume side-effect free externals


# use settings in config file
rollup -c

# in config file, process.env.INCLUDE_DEPS === 'true'
# and process.env.BUILD === 'production'
rollup -c --environment INCLUDE_DEPS,BUILD:production

# create CommonJS bundle.js from src/main.js
rollup --format=cjs --file=bundle.js -- src/main.js

# create self-executing IIFE using `window.jQuery`
# and `window._` as external globals
rollup -f iife --globals jquery:jQuery,lodash:_ \
  -i src/app.js -o build/app.js -m build/


* When piping to stdout, only inline sourcemaps are permitted

For more information visit

-w--watch で正解だった。 -c--config rollup.config.js のことだった。


rollup.config.js を見る。

import resolve from "@rollup/plugin-node-resolve";
import commonjs from "@rollup/plugin-commonjs";
import pkg from "./package.json";

export default [
  // browser-friendly UMD build
    input: "src/main.js",
    output: {
      name: "howLongUntilLunch",
      file: pkg.browser,
      format: "umd",
    plugins: [
      resolve(), // so Rollup can find `ms`
      commonjs(), // so Rollup can convert `ms` to an ES module

  // CommonJS (for Node) and ES module (for bundlers) build.
  // (We could have three entries in the configuration array
  // instead of two, but it's quicker to generate multiple
  // builds from a single configuration where possible, using
  // an array for the `output` option, where we can specify
  // `file` and `format` for each target)
    input: "src/main.js",
    external: ["ms"],
    output: [
      { file: pkg.main, format: "cjs" },
      { file: pkg.module, format: "es" },

export default [ /* ... */ ]; で 2 つの要素が指定されている。

1 つめの要素は UMD ビルド。 src/main.js を入力にして package.jsonbrowser で指定された位置に umd として出力する。プラグインとして @rollup/plugin-node-resolve@rollup/plugin-commonjs を使用している。プラグインは素朴に import して関数を呼び出す形で適用するようだ。 node-resolve はおそらく TypeScript の moduleResolution: node 相当の動作を実現するもので commonjs は CJS で書かれた ms パッケージを ESM に変換するためのものだろう。

2 つめの要素は CJS および ESM ビルド。先のものとは出力先やプラグインなどが異なる。そういう基準で要素を分割しているのだろう。src/main.js を読んで package.jsonmain / module にそれぞれ CJS と ESM で出力する。さっきのもそうだが package.json の記述を流用しているのが良い。 external はバンドル対象から外して外部のままにしておくのだろう。


npm run build の手順に戻って npm run build しよう。 rollup --config rollup.config.js 相当だ。

$ npm run build
# ...

src/main.js → dist/how-long-till-lunch.umd.js...
created dist/how-long-till-lunch.umd.js in 46ms

src/main.js → dist/how-long-till-lunch.cjs.js, dist/how-long-till-lunch.esm.js...
created dist/how-long-till-lunch.cjs.js, dist/how-long-till-lunch.esm.js in 6ms

$ exa -T dist/
├── how-long-till-lunch.cjs.js
├── how-long-till-lunch.esm.js
└── how-long-till-lunch.umd.js

dist/ に 3 ファイルが生成されている。

ざっと中身を確認したあともとのファイルである src/ を見る。

$ exa -T src/
├── lunchtime.js
├── main.js
└── millisecondsUntil.js

各環境向けに 3 ファイルを 1 つにバンドルしているようだ。

src/main.js からの ↓ で参照している箇所が消えている。

import lunchtime from "./lunchtime.js";
import millisecondsUntil from "./millisecondsUntil.js";

rollup.config.js の指定どおりではあるが dist/*.cjs.jsdist/*.esm.js には ms が外部モジュールを参照する形で残っている。 dist/*.umd.js では ms もバンドルされている。


umd の設定を変えてみる

rollup.config.js の UMD の設定を変えてみる。

  // ...
    input: "src/main.js",
    external: ["ms"], // external を追加
    output: {
      name: "howLongUntilLunch",
      file: pkg.browser,
      format: "umd",
      globals: { // output.globals を追加
        ms: "globalMs",
    // plugins を削除
  // ...

最初 external: ["ms"] だけを追加して npm run build したら ↓ のように output.globals を指定しろと言われた。

src/main.js → dist/how-long-till-lunch.umd.js...
(!) Missing global variable name
Use output.globals to specify browser global variable names corresponding to external modules
ms (guessing 'ms')
created dist/how-long-till-lunch.umd.js in 27ms

予想通りバンドル対象から ms が外れて代わりに global.globalMs が参照されるようになった。

(function (global, factory) {
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('ms')) :
  typeof define === 'function' && define.amd ? define(['ms'], factory) :
  (global = global || self, global.howLongUntilLunch = factory(global.globalMs));
}(this, (function (ms) { 'use strict';
// ...

npm run dev & npm test

npm run build (rollup -c) を watch して動かすだけなので特に書くことはなさそうだ。

npm test も特に固有の要素はなさそうなので飛ばす。


README に に TypeScript の例もあるっぽいので試してみる。


  • package.jsondevDependenciesrollup-plugin-typescriptts-nodetslibtypescript が追加された。
    • ts-nodenpm test のためのものっぽい。
  • rollup.config.js の各ビルドの pluginstypescript() が追加された。
  • tsconfig.json が追加された。
  • 拡張子が js -> ts に変更された。


リングフィットアドベンチャー 10 日目 レベル 30 ワールド 4 を終えた。

ABC172 死。