Future Tech Blog
フューチャー開発者ブログ

webpack入門


春の入門祭り15 日目です。

はじめに

想定読者はプログラミング初心者/フロントエンド未経験者です。

TIG メディアユニットの二瓶賢です。
入門祭りということで、今回はフロントエンドの入門記事を書きました。

JavaScriptでの開発は実行結果が視覚的&ツール周りが充実しているのでプログラミング覚えたての人も楽しみながら進められると思います。一方、開発環境周りは充実しすぎているがゆえ難しいと思ったので記事にしました。

webpackがどんなものか理解し、実際にwebpackを使えるようになることをゴールとしています。

webpack について

webpackとはフロントエンドのモジュールバンドラーツールです。 簡単に言うと、部品(モジュール)単位で開発した複数のJSを1つのJSにまとめる(バンドル)ツールです。(実は、JSだけでなくCSS, 画像ファイルについてもバンドルできます)

webpackを使うと、以下の利点があります。

  1. ファイルがまとめられる=通信の回数をまとめられるのでHTTP リクエストの回数が減り、パフォーマンス向上に繋がる
  2. ファイルを部品単位で作れるので、管理がしやすくなる

1.の具体例を出します。

例えば、1 ページで複数のJSをモジュール単位で開発していたとします。webpackを使わない場合HTMLは以下のようになります。

1
2
3
4
5
6
7
8
9
10
<!DOCTYPE html>
<html>
<body>
...
<script src="js/button.js"></script>
<script src="js/form.js"></script>
<script src="js/toggle.js"></script>
...
</body>
</html>

webpackを使う場合は以下のようになります。

1
2
3
4
5
6
7
<!DOCTYPE html>
<html>
<body>
...
<script src="dist/main.js"></script>
</body>
</html>

複数のJSファイルをdist/main.jsにバンドルすることができます。そのため、開発者はファイルを部品単位で開発し、まとめ方をwebpackで指定してあげるだけで良くなります。

webpack 導入手順

webpackはNode.js (JavaScriptの実行環境) 上で動きます。
※ここではNode.js についての詳細な説明は割愛します。

次に、npmを使ってwebpackをインストールします。

npmについても詳細は割愛します。端的に記載するとnpm(Node Packaging Manager)はNode.jsのパッケージ管理ツールです。JavaScriptのパッケージ(フレームワーク/ライブラリ/ツール)のインストールや、バージョン管理が可能です。

npmでの開発を初めるためのコマンドを実行します。

1
$npm init -y

下記のコマンドでwebpackをインストールします。

1
$npm isntall -D webpack webpack-cli

これでwebpackを使う準備は完了です。

実際に webpack を使ってみよう

実際にwebpackを体験してみましょう。JSファイルをバンドルし、バンドル後のJSファイルをHTML上から読み込みます。

まず、ディレクトリ dist/, js/を作成しておきます。

1
2
3
4
5
6
7
.
├── dist/
├── index.html
├── js/
├── package-lock.json
├── package.json
└── node_modules/

さらに、JSファイルを2つ作成します。

まず、js/hoge.jsを作成します。alert()でメッセージを表示する機能を持つ部品(モジュール)として作成します。

hoge.js
1
2
3
export function alertMessage() {
alert("from hoge.js")
}

続いて、js/entry.jsを作成します。
このファイルはモジュールを使う側のJSファイルです。

entry.js
1
2
3
import { alertMessage } from "./hoge"

alertMessage()

さて、この2つのJSファイルをバンドリングするためwebpackを使います。
./webpack.config.jsを作成します。

webpack.config.js
1
2
3
4
module.exports = {
mode: 'development',
entry: './js/entry.js'
};

これはwebpackの設定ファイルです。

上記では設定は2つ指定しています。modeでは、開発モードでビルドすることを指定しています。modedevelopment(開発モード),production(製品モード),none(指定なし)の3つあります。entryでは、エントリーポイント(一番初めの他モジュールの呼び出し元ファイル)を./js/entry.jsに指定しています。

さて、webpackの設定は終わったので実際にwebpackを実行してみましょう。

1
$./node_modules/.bin/webpack

結果は以下のように出るかと思います。

1
2
3
4
5
6
7
8
9
Hash: acbec46c248d0da2e3fb
Version: webpack 4.43.0
Time: 117ms
Built at: 06/17/2020 10:08:18 PM
Asset Size Chunks Chunk Names
main.js 4.54 KiB main [emitted] main
Entrypoint main = main.js
[./js/entry.js] 53 bytes {main} [built]
[./js/hoge.js] 63 bytes {main} [built]

さて、ここでdist/の中身を観てみましょう。
dist/main.jsが作成されているはずです。

dist/main.jsはビルド済ですが、一旦中身を見てみると

dist/main.js
1
!function(e){var t={};function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=0)}([function(e,t,r){"use strict";r.r(t),alert("from hoge.js")}]);

と、綺麗なコードが生成されているかと思います。
これがバンドル後のJSファイルです。
もう何が書いてあるのかわかりません。
正しく意図したとおり動くのか、実際に実行してみましょう。

./index.htmlを作成します。

index.html
1
2
3
4
5
6
7
<!DOCTYPE html>
<html>
<head> </head>
<body>
<script src="dist/main.js"></script>
</body>
</html>

実際にこれをブラウザで開いてみましょう。
開くと、意図したとおり以下のようなメッセージが出ます。(画像はChromeで開いた場合)

最後に、webpackのコマンドオプションを一つ紹介します。

1
$./node_modules/.bin/webpack --watch

これを指定するとJSファイルの変更を監視し、変更を検知すると自動でwebpackが走ります。
試しに、監視状態のままjs/hoge.jsで表示するメッセージを変更してみましょう。

hoge.js
1
2
3
export function alertMessage() {
alert("****from hoge.js****")
}

その後、もう一度./index.htmlをブラウザで開いてみましょう。メッセージが変更されていることが確認できるかと思います。

これで、逐次webpackを実行する手間もなくなりました。


今回はwebpack.config.jsについては必要最低限の設定しかしませんでしたが実際はたくさん設定することになります。
例えば、利用するプラグインの設定をします。
webpackではプラグインは豊富に用意されています。
ここでは、一例をご紹介します。

  • バンドル時に不要なスペースやコメント等を削除し軽量化するプラグイン:UglifyjsWebpackPlugin
  • HTMLの生成までするプラグイン:HtmlWebpackPlugin
  • --watchオプションで特定のファイルの監視を無視させるプラグイン:WatchIgnorePlugin

たくさん設定が増え複雑化するため、実際の開発では共通設定/開発環境設定/本番環境設定としてそれぞれwebpack.common.js, webpack.dev.js, webpack.prod.jsと分けて設定を記載していきます。
公式ドキュメントの例

また、./node_modules/.bin/webpackはnpm-scriptsに登録するとよりよいです。
./package.jsonにて、scriptsに"コマンド名":"タスク"を登録すると、以下のように実行できます。
例:

./package.json
1
2
3
4
5
6
7
8
{
...
"scripts": {
"build": "webpack",
"watch": "webpack --watch"
},
...
}

npm-script実行:

1
$npm run build

上記のコマンドは$./node_modules/.bin/webpackと実行内容は同じですが、こちらの方が簡潔かと思います。
watchに関しても同様です。
npm-scriptsを上手く設定することで、複雑なタスクも簡潔に実行できるようになります(これはwebpackに限りません)。

最後に

webpackの機能をすべて紹介することはできませんでしたが、webpackがどのような目的のツールなのかを知っていただき実際にwebpackを体験していただけたなら幸いです。