これまであまり積極的に使うことのなかった webpack を使ってみました:
2018082300


webpack は複数のモジュール(ファイル)を1つに(場合によっては複数に)まとめるバンドラ(bundler)ツールです。Node.js でいうと、エントリーポイントとなる main.js ファイルと、ここから呼ばれるサブ機能が sub1.js や sub2.js などの別ファイルに分かれている場合に、これら3つのファイルを1つのファイルにまとめるというものです。

【サンプルの紹介】
今回は jsonwebtoken パッケージを使ったシンプルなサンプルコード(main.js)を用意しました:
// main.js
const jwt = require( 'jsonwebtoken' );

function main( params ){
  const id = params.id;
  const password = params.password;
  const token = jwt.sign( { id: id, password: password }, 'secret' );

  console.log( token );
}

main({
  id: 'userid',
  password: 'password'
});

global.main = main;

↑ main() 関数の中で2つのパラメータ(id と password)を受け取り、JSON をトークン化して出力する、というものです。そして id = 'userid', password = 'password' を指定して main を実行しています。

この main.js を実行する前に、コード内で使っている jsonwebtoken パッケージをインストールする必要があります。以下の内容の package.json を用意します:
{
  "name": "jwt_test",
  "version": "0.0.1",
  "main": "main.js",
  "dependencies": {
    "jsonwebtoken": "^8.3.0"
  }
}

そして以下のコマンドで jsonwebtoken パッケージをインストールします:
$ npm install


その後に main.js を普通に実行すると、{ id: 'userid', password: 'password' } をトークン化した結果が表示されます:
$ node main.js
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImRvdG5zZiIsInBhc3N3b3JkIjoicGFzc3dvcmQiLCJpYXQiOjE1MzQ5OTU5NTh9.LUx0q5ycwIFeR1HNnNFgUrlX0w0cny0qDVsPmiVtVnI

とりあえずこの状態で動くことは確認できました。コードは main.js 1つだけに記述されていますが、jsonwebtoken パッケージを利用しているので、実行前に $npm install (jsonwebtoken) を実施しておく必要があり、実際にはここでインストールされるモジュールファイルも使われながら動作します。これらを1ファイルにまとめた上で実行できるようにするというのが今回の目的です。


【webpack のインストール】
webpack は npm を使ってインストールします。例えば以下のコマンドでグローバルインストールすることができます:
$ npm install webpack -g

今回は webpack を(このプロジェクト用に)ローカルインストールして使うことにします。なお webpack 4.0 以降では webpack-cli も合わせて導入する必要があるのでまとめてインストールし、webpack コマンドが実行できるようローカルモジュールへのパスを通します:
$ npm install webpack webpack-cli

$ export PATH=$PATH:./node_modules/.bin


【config ファイルの用意】
webpack を使ってバンドルする作業の条件を config ファイルと呼ばれるファイルで指定します。以下の内容で webpack.js ファイルを作成します:
var path = require( 'path' );
module.exports = {
  entry: './main.js',
  output: {
    path: path.resolve( __dirname, 'dist' ),
    filename: 'bundle.js'
  },
  target: 'node'
};

↑ main.js をエントリーポイント(最初に実行するファイル)とする一連の処理の中で必要とされるモジュール(今回の例では jsonwebtoken パッケージ)がバンドルの対象となり、バンドル結果は dist/bundle.js というファイルに出力される、という指定をしています。


【バンドルと実行】
ここまでに準備した環境とファイルを使って webpack を使ってみます。

まずはバンドル、上記で作成した webpack.js を config ファイルとして指定して webpack コマンドを実行します:
$ webpack --config webpack.js

バンドルが成功すると dist/bundle.js というファイルが生成され、この1ファイルに main.js と jsonwebtoken パッケージがバンドルされているはずです。

確認のため生成されたファイルを実行します。念の為、これらのパッケージモジュールが存在しないテンポラリディレクトリ(/tmp)に bundle.js ファイル1つだけをコピーした上で実行します:
$ cp dist/bundle.js /tmp
$ cd /tmp
$ node bundle.js
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImRvdG5zZiIsInBhc3N3b3JkIjoicGFzc3dvcmQiLCJpYXQiOjE1MzUwMDM1MjF9.llZuuWxqX607AWrJBvMEDpFksFX8IvigUrdIWbhItRg

期待通りにトークンが表示される結果になりました。この bundle.js 1ファイルの中に jsonwebtoken パッケージやその依存パッケージまでが含まれる形でバンドルされて実行されたことが確認できました。


webpack を使うことで今回の例のように依存関係ごとファイルをまとめることができるだけでなく、ファイルのモジュール化が促進されたり、一度のロードで全ファイルを読み込めることから SPA(Single Page Application) が作りやすくなったりします。その一方で、バンドル先のファイルが大きくなってしまうと最初のロードに時間がかかるようになる、という問題もあります。個人的にはパッケージ化されたあとに開発コンソールを使ったデバッグが難しくなることに懸念も持っています。

まあケース・バイ・ケース、なんだろうなあ。。