アレがアレでアレ

(できれば)プログラミング関係のことを書きたい

webpackを使ってみる

webpack.js.org

前回、Babelについて書きました。
今回はwebpackの使い方をメモ程度のクオリティで書いていきます。

webpackとはなにか

モジュールバンドラというものです。
モジュールバンドラとは複数のJavaScriptファイルをまとめて1つのファイルにするツールのことです。

複数のJavaScriptファイルを1つにまとめると、どんな良いことがあるでしょうか?

  • jsファイルの読み込み順など気にしなくても勝手に依存関係を解決してファイルをまとめてくれる。恐らくこれが1番のメリット。
  • ファイルをまとめることでリクエスト数を減らす。通信回数を減らすことができる。
  • 実行時は1つにまとめるので、気にせず機能ごとにファイルを分割してコーディングできる。 変数名が被っても大丈夫。

などなど、メリットがあります。

ディレクトリ構造

今回は以下のようなディレクトリ構造で進めていきます。

.
├── src
│   ├── app.js
│   ├── factorial.js
│   └── fizzbuzz.js
│
├── dist
│   └── bundle.js
├── node_modules
├── package.json
└── webpack.config.js

webpackの環境構築

以下の環境でやってきます。

$ node --version
v10.15.0
$ npm --version
6.5.0

まずはpackage.jsonを作ります。

npm init -y

必要なパッケージをインストール。

npm install --save-dev webpack webpack-cli

webpack.config.jsというwebpackの設定ファイルを作ります。

const path = require('path');
 
module.exports = {
  mode: 'development',
  entry: './app.js',

  output: {
    filename: 'bundle.js',
    path: path.join(__dirname, 'dist')
  },
};
  • mode: development,production,noneがある。
    • development: 開発用。ビルド時間が短い。
    • production: 本番用。ビルド時間が長い。最小化されたファイルが出力される。
    • none: オプション無効。
  • entry: エントリーポイントの設定。起点となるjsファイルを指定する。 webpackはこのファイルが依存しているモジュールを調べてバンドル(まとめる)してくれる。
  • filename: 出力ファイル名
  • path: 出力先のパス

これで最低限のwebpackの環境ができました。

サンプルのコード

バンドルするJavaScriptを用意します。
サンプルでfizzbuzzと階乗を求めるモジュールを作りました。
これをapp.js上で呼び出します。

fizzbuzz.js

export const fizzbuzz = x => {
  let result = '';
  if (x % 3 == 0)
    result += 'Fizz';
  if (x % 5 == 0)
    result += 'Buzz';

  return result || x;
};

factorial.js

export const factorial = x => {
  if (x === 0)
    return 1;

  return x * factorial(x - 1);
};

app.js

import {fizzbuzz} from './fizzbuzz';
import {factorial} from './factorial';

console.log(fizzbuzz(3));
console.log(fizzbuzz(5));
console.log(fizzbuzz(15));
console.log(fizzbuzz(98));

console.log(factorial(5));

バンドルしてみる

npxコマンドを使用してwebpackを実行します。

npx webpack

npxが使えない環境は

./node_modules/.bin/webpack

実行結果

$ npx webpack
Hash: 9ca0da58fd666451390a
Version: webpack 4.29.6
Time: 99ms
Built at: 03/21/2019 12:07:03 AM
    Asset      Size  Chunks             Chunk Names
bundle.js  5.62 KiB    main  [emitted]  main
Entrypoint main = bundle.js
[./app.js] 211 bytes {main} [built]
[./factorial.js] 107 bytes {main} [built]
[./fizzbuzz.js] 156 bytes {main} [built]

特にエラーがなければdistフォルダの中に1つにまとめられたbundle.jsができています。

bundle.js実行

$ node dist/bundle.js
Fizz
Buzz
FizzBuzz
98
120

app.js上で呼び出したモジュールがまとめられ、ちゃんと実行できています。

webpack&Bebelで使う

次にwebpackとBabelと組み合わせて使ってみます。

必要なパッケージのインストール

$ npm install --save-dev babel-loader @babel/core @babel/preset-env
  • babel-loader: webpackでBabelを使うのに必要なパッケージ

webpack.config.jsを以下のように書き換えます。

const path = require('path');
 
module.exports = {
  mode: 'development',
  entry: './src/app.js',
  output: {
    filename: 'bundle.js',
    path: path.join(__dirname, 'dist')
  },

  // ↓以下追加
  module: {
    rules: [
      {
        // 処理対象ファイル
        test: /\.m?js$/,
        // 処理の対象外にするディレクトリ
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env']
          }
        }
      }
    ]
  }
};

moduleというのを追加しました。
ここは「jsファイルはBabelで変換するように。ただし、node_modulesディレクトリ内のjsファイルは無視してね。」という指示を書いています。
node_modulesを除外しないと変換の速度が遅くなったり、エラーになったりするようです。

Babelの設定はbabel.config.jsなどに書くのですが、webpack.config.jsoptionsに書いてしまうこともできます。今回はこっちに設定を書きました。

Babelとwebpackを連携させる設定ができたので、
あとはwebpackを実行すればトランスパイルされているbundle.jsが出力されます。

modeをnoneにすると変換したところがわかりやすいのでnoneで実行します。

$ npx webpack --mode=none

bundle.jsの中身抜粋

/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fizzbuzz", function() { return fizzbuzz; });
var fizzbuzz = function fizzbuzz(x) {
  var result = '';
  if (x % 3 == 0) result += 'Fizz';
  if (x % 5 == 0) result += 'Buzz';
  return result || x;
};

/***/ }),
/* 2 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "factorial", function() { return factorial; });
var factorial = function factorial(x) {
  if (x === 0) return 1;
  return x * factorial(x - 1);
};

/***/ })
/******/ ]);

わざとらしくアロー関数で書いたとこがトランスパイルされているのを確認できました!

おわり。