webpack を使ってみました

以前、 CommonJS Modules を使ったときに Browserify を使いました。 最近は(以前から)、 Browserify よりも webpack の方をよく見るので、 webpack を使ってみました。

Getting Started を参考に進めてみます。

環境

webpack 4.5.0

webpack?

Concepts

At its core, webpack is a static module bundler for modern JavaScript applications.

Concepts

モジュールバンドラーのようです。

Basic Setup

作業するためのディレクトリーを作成するようです。

$ mkdir webpack-demo && cd webpack-demo

プロジェクトを初期化するようです。

$ npm init -y
Wrote to /path/to/webpack-demo/package.json:

{
  "name": "webpack-demo",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}


webpack と webpack-cli のパッケージをインストールするようです。

$ npm install webpack webpack-cli --save-dev
npm WARN deprecated nomnom@1.8.1: Package no longer supported. Contact support@npmjs.com for more info.
npm WARN deprecated babel-preset-es2015@6.24.1: 🙌  Thanks for using Babel: we recommend using babel-preset-env now: please read babeljs.io/env to update!
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN webpack-demo@1.0.0 No description
npm WARN webpack-demo@1.0.0 No repository field.
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.1.3 (node_modules/fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.1.3: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"x64"})

+ webpack@4.5.0
+ webpack-cli@2.0.14
added 751 packages from 417 contributors in 77.495s

Babel の警告が出ていますが、 webpack は Babel に依存しているみたいです。 babel-preset-es2015 のプリセットじゃなくて、 babel-preset-env のプリセットを使うように言われました。

index.html と index.js を作成するようです

project

  webpack-demo
  |- package.json
+ |- index.html
+ |- /src
+   |- index.js

src/index.js ファイルを次の通り作成しました。

function component() {
  var element = document.createElement('div');

  // Lodash, currently included via a script, is required for this line to work
  element.innerHTML = _.join(['Hello', 'webpack'], ' ');

  return element;
}

document.body.appendChild(component());

Lodash は使ったことないのですが、 join して HTML に設定しているようです。

index.html ファイルを次の通り作成しました。

<!doctype html>
<html>
  <head>
    <title>Getting Started</title>
    <script src="https://unpkg.com/lodash@4.16.6"></script>
  </head>
  <body>
    <script src="./src/index.js"></script>
  </body>
</html>

Lodash を <script> で読み込むようです。

package.json ファイルを次のように修正しました。

  {
    "name": "webpack-demo",
    "version": "1.0.0",
    "description": "",
+   "private": true,
-   "main": "index.js",
    "scripts": {
      "test": "echo \"Error: no test specified\" && exit 1"
    },
    "keywords": [],
    "author": "",
    "license": "ISC",
    "devDependencies": {
      "webpack": "^4.0.1",
      "webpack-cli": "^2.0.9"
    },
    "dependencies": {}
  }

パッケージを誤って公開してしまわないように private にして、 main エントリーを削除しているようです。

これで、 index.html をブラウザーから開きます。

すると、 Hello webpack と表示されました。

まだ、ここでは webpack でバンドルしていない状態です。 どんな結果になるか最初に確認しているのかな。 webpack でバンドルしても同じ結果になるだろう、と。

Creating a Bundle

index.html を dsit/ ディレクトリーに移動するようです。

project

  webpack-demo
  |- package.json
+ |- /dist
+   |- index.html
- |- index.html
  |- /src
    |- index.js

Lodash のパッケージをインストールするようです。

$ npm install --save lodash
npm WARN webpack-demo@1.0.0 No description
npm WARN webpack-demo@1.0.0 No repository field.
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.1.3 (node_modules/fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.1.3: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"x64"})

+ lodash@4.17.5
updated 1 package in 18.089s

Lodash は <script> で読み込むのではなく、 npm のパッケージのものを使用してバンドルするみたいです。

src/index.js を次のように修正しました。

import _ from 'lodash';

function component() {
  var element = document.createElement('div');

  // Lodash, now imported by this script
  element.innerHTML = _.join(['Hello', 'webpack'], ' ');

  return element;
}

document.body.appendChild(component());

ECMAScript Modules の import を使って Lodash のパッケージ(モジュール)を読み込むようです。 webpack は Babel に依存しているようでしたので、 ECMAScript Modules の記述のままバンドルすることができるのかな。

dist/index.html を次のように修正しました。

<!doctype html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Getting Started</title>
  </head>
  <body>
    <script src="main.js"></script>
  </body>
</html>

Lodash を読み込む <script> が消えて、 main.js を読み込むだけになりました。

バンドルします。

$ npx webpack
Hash: 5c528a4f6539a8a8f045
Version: webpack 4.5.0
Time: 7292ms
Built at: 2018-4-6 14:19:48
  Asset    Size  Chunks             Chunk Names
main.js  70 KiB       0  [emitted]  main
Entrypoint main = main.js
   [1] (webpack)/buildin/module.js 519 bytes {0} [built]
   [2] (webpack)/buildin/global.js 509 bytes {0} [built]
   [3] ./src/index.js 263 bytes {0} [built]
    + 1 hidden module

WARNING in configuration
The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment.
You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/concepts/mode/

遅かった、かつ、警告が出ていますが、バンドルできたようです。

dist/main.js が作成されていました。 webpack のデフォルトの設定では、 dist ディレクトリーの main.js ファイルを作成するのかな。

dist/index.html をブラウザーで開きます。

すると、 Hello webpack と表示されました。

最初、 dist/index.html に <meta charset="utf-8"> を記述しなかったら何も表示されませんでした。 Microsoft Edge はコンソールにエラーも表示されませんでした。 Firefox は次のエラーが表示されました。

SyntaxError: unterminated character class
HTML ドキュメントの文字エンコーディングが宣言されていません。ドキュメントに US ASCII 外の文字が含まれている場合、ブラウザーの設定によっては文字化けすることがあります。ページの文字エンコーディングはドキュメント中または転送プロトコルで宣言されなければなりません。

Lodash が悪いのかな。 <script> で読み込んでいたファイル (https://unpkg.com/lodash@4.16.6) の中では '\xe6': 'ae' となっていたところが、バンドルしたファイル (dist/main.js) の中では "æ":"ae" となっていました。 hex で記述されていた文字列もバンドルすると純粋な文字列に置き換わってしまうのかな。

Using a Configuration

webpack.config.js ファイルを作成するようです。

project

  webpack-demo
  |- package.json
+ |- webpack.config.js
  |- /dist
    |- index.html
  |- /src
    |- index.js

webpack.config.js ファイルを次のように作成しました。

const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  }
};

webpack の設定ファイルは json とかじゃなく、 js みたいです。 これは、 Gulp も同じだったかもしれません。 でも、 config という名前だと json っていうイメージになってしまいます。 json っぽく記述することもできるのかな。

Configuration を見ると、たくさん設定項目があるようでした。

webpack.config.js ファイルを使ってバンドルします。

$ npx webpack --config webpack.config.js
Hash: 112fee20be517f32d471
Version: webpack 4.5.0
Time: 7444ms
Built at: 2018-4-6 14:52:06
    Asset      Size  Chunks             Chunk Names
bundle.js  69.9 KiB       0  [emitted]  main
Entrypoint main = bundle.js
   [1] (webpack)/buildin/module.js 519 bytes {0} [built]
   [2] (webpack)/buildin/global.js 509 bytes {0} [built]
   [3] ./src/index.js 256 bytes {0} [built]
    + 1 hidden module

WARNING in configuration
The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment.
You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/concepts/mode/

バンドルできたようです。

dist/index.html ファイルを次のように修正しました。

<!doctype html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Getting Started</title>
  </head>
  <body>
    <script src="bundle.js"></script>
  </body>
</html>

dist/index.html ファイルをブラウザーから開きます。

すると、 Hello webpack と表示されました。

終わり

webpack のトップのページを見ると、 bundle your styles, bundle your images とか記載されていて、もっとできそうでした。 今回は、ちょっとこれだけではあまりメリットが感じられませんでした。