Chapter 07

Babelとrollup.jsを使用してリリースモジュールを作成する

manycicadas
manycicadas
2021.01.16に更新

rollup.jsのインストール

rollup.jsはJavaScriptのモジュールバンドラです。
モジュールバンドラは複数のファイルを一つにまとめます。
以下を実行し、関連モジュールをまとめてインストールしてください。

$ yarn add rollup rollup-plugin-terser @rollup/plugin-babel @rollup/plugin-commonjs @rollup/plugin-node-resolve @rollup/plugin-typescript tslib --dev
  • rollup ・・・ rollup.js本体
  • rollup-plugin-terser ・・・ minifyを行う
  • @rollup/plugin-babel ・・・ ファイルをBabelでコンパイルする
  • @rollup/plugin-commonjs ・・・ CommonJSをES6に変換する
  • @rollup/plugin-node-resolve ・・・ サードパーティのライブラリを読み込めるようにする
  • @rollup/plugin-typescript ・・・ rollupとTypeScriptをシームレスに結合する
  • tslib ・・・ TypeScriptのヘルパー関数を含むTypeScriptのランタイムライブラリ

Babelのインストール

Babelは指定のバージョンのJavaScriptに変換するトランスパイラです。

$ yarn add @babel/core @babel/preset-env --dev
  • @babel/core ・・・ Babel本体
  • @babel/preset-env ・・・ 実行環境に応じた構文変換を提供する

.babelrc.jsの追加

プロジェクトの直下に.babelrc.jsを追加します。
.babelrc.jsはBabelの設定ファイルです。
今回は単純に@babel/preset-envを使用するだけの設定にします。

module.exports = {
  presets: [
    [
      "@babel/preset-env",
    ],
  ],
};

rollup.config.jsの追加

プロジェクト直下にrollup.config.jsを追加し、rollupの設定を記載します。
今回はブラウザ用・ES Module用・CommonJS用の設定を記載しています。

// minifyに用
import { terser as pluginTerser } from 'rollup-plugin-terser';
// typescript用
import pluginTypescript from '@rollup/plugin-typescript';
// CommonJS用
import pluginCommonjs from '@rollup/plugin-commonjs';
// サードパーティライブラリ用
import pluginNodeResolve from '@rollup/plugin-node-resolve';
// トランスパイル用
import { babel as pluginBabel } from '@rollup/plugin-babel';
import * as path from 'path';

import pkg from './package.json';


// モジュール名
const moduleName = pkg.name.replace(/^@.*\//, '');
// エントリーとなるファイル名
const inputFileName = 'src/index.ts';

// ライセンス表記用のバナー
const banner = `
  /**
   * @license
   * ${moduleName}.js v${pkg.version}
   * Released under the ${pkg.license} License.
   */
`;

export default [
  // ブラウザ用の設定
  {
    input: inputFileName,
    output: [
      // uncompressed
      {
        name: moduleName,
        file: pkg.browser,
        format: 'iife',
        sourcemap: 'inline',
        banner
      },
      // minified
      {
        name: moduleName,
        file: pkg.browser.replace('.js', '.min.js'),
        format: 'iife',
        sourcemap: 'inline',
        banner,
        plugins: [
          pluginTerser(),
        ],
      }
    ],
    plugins: [
      pluginTypescript(),
      pluginCommonjs({
        extensions: ['.js', '.ts'],
      }),
      pluginBabel({
        babelHelpers: 'bundled',
        configFile: path.resolve(__dirname, '.babelrc.js'),
      }),
      pluginNodeResolve({
        // ブラウザ向けにバンドルする
        browser: true,
      }),
    ],
  },

  // ES Module用の設定
  {
    input: inputFileName,
    output: [
      {
        file: pkg.module,
        format: 'es',
        sourcemap: 'inline',
        banner,
        exports: 'named',
      },
    ],
    external: [
      ...Object.keys(pkg.dependencies || {}),
      ...Object.keys(pkg.devDependencies || {}),
    ],
    plugins: [
      pluginTypescript(),
      pluginCommonjs({
        extensions: ['.js', '.ts'],
      }),
      pluginBabel({
        babelHelpers: 'bundled',
        configFile: path.resolve(__dirname, '.babelrc.js'),
      }),
      pluginNodeResolve({
        browser: false,
      }),
    ],
  },

  // CommonJS用の設定
  {
    input: inputFileName,
    output: [
      {
        file: pkg.main,
        format: 'cjs',
        sourcemap: 'inline',
        banner,
        exports: 'default',
      },
    ],
    external: [
      ...Object.keys(pkg.dependencies || {}),
      ...Object.keys(pkg.devDependencies || {}),
    ],
    plugins: [
      pluginTypescript(),
      pluginCommonjs({
        extensions: ['.js', '.ts'],
      }),
      pluginBabel({
        babelHelpers: 'bundled',
        configFile: path.resolve(__dirname, '.babelrc.js'),
      }),
      pluginNodeResolve({
        browser: false,
      }),
    ],
  },
];

package.jsonの修正

package.jsonの以下の部分を修正します。

{
  // 省略
  "main": "dist/hellolib.cjs.js", // Node.js環境での使用する用
  "module": "dist/hellolib.es.js", // ES Module環境で使用する用
  "browser": "dist/hellolib.js", // ブラウザで使用する用
  // 省略
  "scripts": {
    "build": "rollup -c", // ビルド用のスクリプト追加
    "lint": "eslint --fix 'src/**/*.ts'",
    "test": "jest"
  },
  // 省略
}

ビルドの実行

以下のコマンドを実行し、ビルドをしましょう。

$ yarn build

distディレクトリにhellolib.cjs.jshellolib.es.jshellolib.jshellolib.min.jsが生成されるはずです。

動作確認

試しに別のプロジェクトを作成し、先程作成したライブラリがうまく動作するか確認してみます。

nodeでの使用

以下のコマンドを実行します。

$ mkdir hello-js-lib-test
$ cd hello-js-lib-test
$ yarn init
$ yarn add ../hello-js-lib

上記で作成したプロジェクト直下にsample.jsというファイルを作成し、以下のように記述します。

const { trim } = require('@cigalecigales/hellolib');

const value = trim('    HELLO WORLD     ');

console.log(value);

その後、以下のコマンドを実行すると正しく動作していることがわかります。

$ node sample.js
# HELLO WORLD

ブラウザでの使用

別途フォルダを作成し、dist/hellolib.jsをコピーして配置します。
その後、HTMLファイルを作成し、以下のように記述します。
HTMLを開いて、コンソールにHTLLO WORLDが表示されているはずです。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>for browser</title>
  <script src="hellolib.js"></script>
</head>
<body>
  <script>
    const value = hellolib.trim('    HELLO WORLD     ');
    
    console.log(value);
  </script>
</body>
</html>