【MBTI診断】16タイプ別・フリーランスに向いてる仕事/働き方
- コラム
- フリーランス/個人事業主
- 働き方
webpackをご存知ですか?
webpackは、JavaScriptなどの複数のモジュールをひとつにまとめるツールです。
この記事では、webpackの使い方と導入するメリットについて詳しく解説します。使い方の解説では、実際にモジュールを指定してひとつにまとめる作業を実行し、ファイルに出力するまでを、コードを用いて詳しく解説しています。
後半では、コードの圧縮方法や便利なプラグインなど、より実践的な内容を説明していきます。現在、フロントエンド開発で発生した複数のjsファイルをまとめたい方や、画像ファイルを整理したい方、実践的に使いたい方におすすめです。
目次
webpackは、モジュールを束ねるツールです。
モジュールとは、プログラム内のJavaScriptファイル(以下:jsファイル)やsassファイルなどのことです。webpackを使うことで、複数のjsファイルをひとつのjsファイルにまとめたり、複数のsassファイルをひとつのsassファイルにしたりできます。
バンドル(bundle)は”束にする”という意味です。上の画像に「bundle your style」とありますが、文字どおりwebpackはモジュールを”束にする”役割を担います。
複数のファイルをスッキリひとつにまとめることで、どんなメリットがあるのでしょうか?具体的には以下のような利点が挙げられます。
また、webpackは開発側だけでなく、ユーザー側にもメリットがあります。たとえばjsファイルがまとめられ依存関係が解消されていれば、ブラウザでjsファイルを読み込む際にそれほど時間がかかりません。
スピーディな読み込み速度は、ユーザビリティ向上につながります。
ここではまず、複数のjsファイル(モジュール)を束ねてファイルを出力する方法をご紹介します。
まずはwebpackをインストールしましょう。
「グローバルインストール」と「ローカルインストール」という2通りのインストール方法があります。おすすめは後者の「ローカルインストール」です。前者は目的のプロジェクト以外の環境にも影響するので、他の環境に影響しないローカルインストールがおすすめです。
【グローバルインストール】
$ npm install webpack -g
【ローカルインストール】
$ npm install webpack --save-dev
webpackの利用を開始するには、まずwebpack.config.jsに設定を記述します。以下のように設定してみましょう。
// output.pathに絶対パスを指定する必要があるため、pathモジュールを読み込んでおく
const path = require('path');
module.exports = {
// モードの設定、v4系以降はmodeを指定しないと、webpack実行時に警告が出る
mode: 'development',
// エントリーポイントの設定
entry: './src/js/app.js',
// 出力の設定
output: {
// 出力するファイル名
filename: 'bundle.js',
// 出力先のパス(v2系以降は絶対パスを指定する必要がある)
path: path.join(__dirname, 'public/js')
}
};
ちなみに、コード中で出てきたもので覚えておいた方がいいものは以下の2つ。
ここで2つのファイルをバンドルさせます。ふたつの言葉を足して合わせるという処理ができれば成功です。
コードはこんな感じです。
import module1 from './modules/module1';
import module2 from './modules/module2';
//変数を定義します
var word1 = "This is";
var word2 = " a pen.";
//関数に変数を投入します
var returnedWord1 = module1(word1);
var returnedWord2 = module2(word2);
//結果をまとめて表示します
var addedWords = returnedWord1 + returnedWord2;
console.log(addedWords);
importを使って呼び出すのがミソです。
エントリーポイントでimportを使って呼び出すためには、モジュールを定義する必要があります。
export defaultでmodule1をモジュールとして定義しました。
export default function module1(word1) {
return word1 + "(これは)";
}
モジュール1と同様に作成していきましょう。
export default function module2(word2) {
return word2 + "(ペンです。)";
}
いwebpack.config.jsがある階層でwebpackコマンドを実行すると、ファイルがバンドルされます。ファイルが作成される場所は、先ほどconfigファイルで設定したところです。名称も設定通りになっているか確認しましょう。
作成されたファイルを開いてみると、以下のようになっています(実際のファイルはかなり長大になってしまったので、一部抜粋しています)。
/***/ "./src/js/app.js":
/*!***********************!*\
!*** ./src/js/app.js ***!
\***********************/
/*! no exports provided */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _modules_module1__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./modules/module1 */ \"./src/js/modules/module1.js\");\n/* harmony import */ var _modules_module2__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./modules/module2 */ \"./src/js/modules/module2.js\");\n\n\n//変数を定義します\nvar word1 = \"This is\";\nvar word2 = \" a pen.\";\n//関数に変数を投入します\nvar returnedWord1 = Object(_modules_module1__WEBPACK_IMPORTED_MODULE_0__[\"default\"])(word1);\nvar returnedWord2 = Object(_modules_module2__WEBPACK_IMPORTED_MODULE_1__[\"default\"])(word2);\n//結果をまとめて表示します\nvar addedWords = returnedWord1 + returnedWord2;\nconsole.log(addedWords);\n\n//# sourceURL=webpack:///./src/js/app.js?");
/***/ }),
/***/ "./src/js/modules/module1.js":
/*!***********************************!*\
!*** ./src/js/modules/module1.js ***!
\***********************************/
/*! exports provided: default */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"default\", function() { return module1; });\nfunction module1(word1) {\nreturn word1 + \"(これは)\";\n}\n\n//# sourceURL=webpack:///./src/js/modules/module1.js?");
/***/ }),
/***/ "./src/js/modules/module2.js":
/*!***********************************!*\
!*** ./src/js/modules/module2.js ***!
\***********************************/
/*! exports provided: default */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"default\", function() { return module2; });\nfunction module2(word2) {\nreturn word2 + \"(ペンです。)\";\n}\n\n//# sourceURL=webpack:///./src/js/modules/module2.js?");
/***/ })
/******/ });
バンドルされていることがお分かりでしょうか。
また、作成されたファイルを読み込んだHTMLファイルを作成し、ブラウザで開いてみてください。コンソールを確認し、正常にjsファイルが動作していることを確かめてみましょう。
module1の(これは)を足す処理と、module2の(ペンです)を足す処理が正しくおこなわれていることがわかります。
ここからは少し実践的になります。
webサイトでは多くの画像やcssファイル、jsファイルが使われており、多くの容量を占めています。webpackを使うと、それらをすベてまとめられ、容量を節約できます。
ファイルを圧縮するときは、元のソースファイルとの関連が分かるよう、ソースマップも有効にしましょう。
先ほどのconfigファイルのmodeという項目に注目してみてください。これはwebpack 4から導入された項目で、3つのモードが存在します。
development | ソースマップが有効になる |
production | ファイルを圧縮する |
none | 特にない |
deveropmentに設定すると、容量は大きくなりますがビルド時間が短くなります。そこで、開発時はdevelopment、サイト公開時はproductionに設定するのが良いでしょう。
ファイルの変更を検知する機能のことです。オプション指定でwebpackコマンドを実行するか、configファイルに設定を記述すれば使用できます。
ビルド時間を短縮する効果があるので、ぜひwatchモードは活用しましょう
webpack --watch
または、
const path = require('path');
module.exports = {
// watchモードを有効にする
watch: true,
mode: 'development',
entry: "./app.js",
output: {
filename: "bundle.js",
path: path.join(__dirname, 'public/js')
}
}
ローダーとは、imageやcssなどjs以外のファイルを変換したり、バンドル前にそれらのモジュールに何かしら働きかける機能のことです。ローダーによってその機能はさまざまです。開発で役立ちそうなローダーをいくつかご紹介しましょう。
$ npm install babel-loader babel-core --save-dev
インストールできたら、configファイルにloaderの設定を追記しましょう。
// output.pathに絶対パスを指定する必要があるため、pathモジュールを読み込んでおく
const path = require('path');
module.exports = {
// モードの設定、v4系以降はmodeを指定しないと、webpack実行時に警告が出る
mode: 'development',
// エントリーポイントの設定
entry: './src/js/app.js',
// 出力の設定
output: {
// 出力するファイル名
filename: 'bundle.js',
// 出力先のパス(v2系以降は絶対パスを指定する必要がある)
path: path.join(__dirname, 'public/js')
},
// ローダーの設定
module: {
rules: [
{
// ローダーの処理対象ファイル
test: /\.js$/,
// ローダーの処理対象から外すディレクトリ
exclude: /node_modules/,
use: [
{
// 利用するローダー
loader: 'babel-loader',
// ローダーのオプション
// 今回はbabel-loaderを利用しているため
// babelのオプションを指定しているという認識で問題ない
options: {
presets: [['env', { modules: false }]]
}
}
]
}
]
},
};
これでwebpackコマンドを実行すると、どのブラウザでもES2015で書かれたコードが動作するようになります。
$ npm install webpack webpack-cli style-loader css-loader --save-dev
configファイルに以下のように追記しましょう。module.exports = {
// モード値を production に設定すると最適化された状態で、
// development に設定するとソースマップ有効でJSファイルが出力される
mode: 'production',
module: {
rules: [
{
test: /\.css/,
use: [
'style-loader',
{loader: 'css-loader', options: {url: false}},
],
},
]
}
};
この場合、cssを読み込んでjsにバンドルするcss-loaderが先に実行され、続いて<link>タグにcssを展開するstyle-loaderが機能します。コード内に登場するuseについては次に説明します。useを使用すると、複数のローダーを使うことができます。
module: {
rules: [{ test: /\.js$/,
exclude: /node_modules/,
use: [{
loader: 'babel-loader',
options: {
presets: [['env', { modules: false }]]}
},
{
loader: 'jshint-loader'
}
]}
]
これは便利な機能ですよね!
注意してほしいのは「後ろから順番に適用される」ということです。
便利なプラグインの名前と用途を3つご紹介します。
プラグインを追加すると、ビルド実行時にさまざまな機能を使えます。
機能を追加する点でローダーと似ているようにみえますが、ローダーはバンドル前、プラグインはビルド実行時に追加されるという違いがあります。
webpackでは、最新版へのバージョンアップが絶えずおこなわれています。
webpack3からwebpack4などにバージョンを変更する場合、移行後の環境ではこれまで使えていたローダーやプラグインが利用できないことがあります。事前に確認しておきましょう。
移行に失敗した場合は、node_modulesフォルダを削除してから以下のようにコマンドを叩き、最新版をインストールしてみましょう。
$ npm install
いかがでしたか?
webpackを使用すると、煩雑なファイルをスッキリまとめることができます。それによってコードが読みやすくなり、メンテナンスもしやすくなるでしょう。
また、cssや画像ファイルなどもまとめられ、ブラウザ依存を解決したり、UXを向上させる効果もあります。
基本的にファイルをまとめる(バンドルする)のがwebpackの役割ですが、ローダーやプラグインと呼ばれる外部機能と連携させることでフロントエンド開発の幅が広がります。
みなさんもぜひwebpackを試してみてください!