概要

そうだよ

さて、最近は CommonJS と ES Modules も研究したんで……

……次はそれを、各実行環境で使いやすいようバンドル化する webpack の話をしようぜ。

JavaScript は歴史上、 "モジュールシステムを使いてーけどモジュールで分割されてるとブラウザ側で使えねー" という問題を乗り越えるため、 webpack というスゴツールを2012年に生み出している。これは "モジュールシステムで分割されたコードをくっつける (バンドル化する) ことでブラウザが使えるようにする" ってやつだ。ついでに ES2015 -> ES5 のトランスパイルとか、 TypeScript のトランスパイルとか、 tree shaking とか minification 機能も持っているのでホンマモンのスゴツールだ。今回はそいつの威力を見ようぜ。

 

CommonJS を webpack でバンドルにしよっか

まずは CommonJS をそのまま実行しよっか

// index.js だよ。 require を使っているから CommonJS だ。
const dayjs = require('dayjs');

const today = dayjs();
console.log('Today:', today.format('YYYY-MM-DD'));

const tomorrow = today.add(1, 'day');
console.log('Tomorrow:', tomorrow.format('YYYY-MM-DD'));
# npm project を用意。
yarn init -y

# dayjs をインストール。
yarn add dayjs

node -v
# v20.3.0

# Node.js は普通に CommonJS を実行できる。
node index.js
# Today: 2023-07-05
# Tomorrow: 2023-07-06
<!--
  ブラウザ側で index.js を実行する index.html
  ブラウザで index.js を実行すると
  Uncaught ReferenceError: require is not defined
  を確認できる。
-->
<script src="node_modules/dayjs/dayjs.min.js"></script>
<script src="index.js"></script>

 

CommonJS を webpack でバンドルしよっか

// Node.js で実行できるバンドルを作るための webpack 設定。
// webpack.config-for-node.js
module.exports = {
  target: 'node',
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader'
        }
      }
    ]
  },
  output: {
    filename: 'main-for-node.js',
    libraryTarget: 'commonjs2'
  }
};
// ブラウザで実行できるバンドルを作るための webpack 設定。
// webpack.config-for-browser.js
module.exports = {
  target: 'web',
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader'
        }
      }
    ]
  },
  output: {
    filename: 'main-for-browser.js',
    libraryTarget: 'umd'
  }
};
# webpack をインストール。
yarn add --dev webpack webpack-cli babel-loader @babel/core

# Node.js のためのバンドル化する!
# production mode を使うとファイルサイズが小さくなる。
yarn webpack --mode development --entry ./index.js --config ./webpack.config-for-node.js

# Node.js では相変わらず普通に実行できる。
node ./dist/main-for-node.js
# Today: 2023-07-05
# Tomorrow: 2023-07-06

# ブラウザのためのバンドル化する!
yarn webpack --mode development --entry ./index.js --config ./webpack.config-for-browser.js
<!--
  ブラウザでバンドルを実行する index-with-webpack.html
  ブラウザでバンドルを実行すると
  Today: 2023-07-05
  Tomorrow: 2023-07-06
  を確認できる。
-->
<script src="dist/main-for-browser.js"></script>

 

ES Modules を webpack でバンドルにしよっか

まずは ES Modules をそのまま実行しよっか

// index.mjs だよ。 import を使っているから ES Modules だ。
import dayjs from 'dayjs';

const today = dayjs();
const tomorrow = today.add(1, 'day');

console.log(`Today: ${today.format('YYYY-MM-DD')}`);
console.log(`Tomorrow: ${tomorrow.format('YYYY-MM-DD')}`);
yarn init -y

yarn add dayjs

node -v
# v20.3.0

# Node.js は普通に ES Modules を実行できる。
node index.mjs
# Today: 2023-07-05
# Tomorrow: 2023-07-06
<!--
  ブラウザで実行すると
  GET http://127.0.../node_modules/dayjs/esm/constant net::ERR_ABORTED 404 (Not Found)
  GET http://127.0.../node_modules/dayjs/esm/locale/en 404 (Not Found)
  GET http://127.0.../node_modules/dayjs/esm/utils net::ERR_ABORTED 404 (Not Found)
  なんかよく分かんないけどうまくいかないことを確認できる。
  うまくいくこともあるんだろうけど npm package が関わるとダメなんかな?
-->
<script type="module">
  import dayjs from './node_modules/dayjs/esm/index.js';

  const today = dayjs();
  const tomorrow = today.add(1, 'day');

  console.log(`Today: ${today.format('YYYY-MM-DD')}`);
  console.log(`Tomorrow: ${tomorrow.format('YYYY-MM-DD')}`);
</script>

 

ES Modules を webpack でバンドルしよっか

// Node.js で実行できるバンドルを作るための webpack 設定。
// ちょっとこだわって ES Modules 形式にしよう。
// webpack.config-for-node.mjs
export default {
  // 中身は CommonJS のほうの設定と同じ。
};
// ブラウザで実行できるバンドルを作るための webpack 設定。
// こだわって ES Modules 形式にしよう。
// webpack.config-for-browser.mjs
export default {
  // 中身は CommonJS のほうの設定と同じ。
};
# webpack をインストール。
yarn add --dev webpack webpack-cli babel-loader @babel/core

# Node.js のためのバンドル化する!
# production mode を使うとファイルサイズが小さくなる。
yarn webpack --mode development --entry ./index.mjs --config ./webpack.config-for-node.mjs

# Node.js では相変わらず普通に実行できる。
node ./dist/main-for-node.js
# Today: 2023-07-05
# Tomorrow: 2023-07-06

# ブラウザのためのバンドル化する!
yarn webpack --mode development --entry ./index.mjs --config ./webpack.config-for-browser.mjs
<!--
  ブラウザでバンドルを実行する index-with-webpack.html
  ブラウザでバンドルを実行すると
  Today: 2023-07-05
  Tomorrow: 2023-07-06
  を確認できる。
-->
<script src="dist/main-for-browser.js"></script>

 

おしまい

どんなに今風のバージョンの JavaScript を書こうと、どんなモジュールシステムで書こうと、 Node.js でもブラウザでも動かせるようになったぜ! どれだけいかしたスクリプトを書こうと、動かせねーと意味がない。自分で手を動かすことで、 webpack のパワーを実感できたな。