webpackとは何か
JavaScript の モジュールバンドラです。
モジュールバンドラとは、
複数のファイルを1つにまとめて出力してくれるツールのことです。
(複数ファイルをまとめることを「バンドル」と呼びます。)
なぜ使うのか
-
たくさんのjsファイルを1ページで読み込もうとすると、リクエストがその数だけ発生し、時間がかかってしまう→1つのファイルにまとめることで、リクエストも1回だけできる
-
外部モジュールを利用するときにリクエスト数を減らせる
-
モジュールに切り分けた開発可能→開発効率アップ
-
依存関係を解決してくれる
<!-- app.jsはjQueryに依存しているため、jQueryを読み込んだ後に読み込む必要がある。 -->
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script src="js/app.js"></script>
上記のような依存関係が増えれば増えるほど依存関係がわからなくなってしまいます。
→webpackを利用すれば依存関係を解決してファイルをバンドルするため、スクリプトの順番を考慮する必要はなくなります!
webpackの設定ファイルの書き方
webpack.config.js
という名前のファイルを作成し設定を書きます
webpack設定の基本はmode, entry, output, loader, pluginの5つです。
const path = require('path');
module.exports = {
mode: "production",
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
},
module: {
rules: [
{
test: /\.m?js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
}
]
}
plugins: [
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
new webpack.DefinePlugin({
'process.env.NODE_ENV': '"production"',
}),],
};
Mode
none, development, productionのいずれかを設定できるパラメータです。値別に設定を切り分けたい時に設定します。デフォルトではproductionが設定されています。
Entry
処理の開始となるポイントを記述します。
Output
生成されたバンドルされたファイルの出力先を記述します。
Loader
webpackコアだけではjsファイルしか扱えません。そこでJavaScript以外のファイルでもwebpackでバンドルできるようにするものです。
例:css-loader(CSSファイルを読み込む) file-loader(画像を読み込む)
Plugins
バンドルの仕方に作用するものです。バンドル自体の作成方法も変更できます。プラグインはローダーよりも細かい設定ができます。
例:MiniCssExtractPlugin(CSSを別バンドルで出力する)
webpack ハンズオン
1. webpackの導入
1.webpackのインストール
まずはwebpackをnpmでインストールします。
npm init -y
npm install webpack
npm install webpack-cli
2. bundleできているか確認しよう
ここからは二つのjsファイルを作成し、片方からもう片方をimportしている時、webpackでbundleするとどうなるのか実践していきます。
1. src/index.jsの作成
まずはsrcディレクトリを作成してそこにindex.js
ファイルを作成します。
このファイルでは配下のnameファイルを読み込んでconsole.logで出力するという簡単なものです。
const name = require("./name");
console.log("Hello " + name);
2. src/name.jsの作成
こちらではname.js
で任意の名前をexportsするファイルを作成します。
module.exports = "John";
3. webpack.config.jsの作成
ここで今回の主役となるwebpackの設定ファイルである
webpack.config.js
を次のように定義します。
const path = require("path");
module.exports = {
mode: "development",
entry: "./src/index.js",
output: {
path: path.resolve(__dirname, "dist"),
filename: "bundle.js",
},
};
この設定はdecelopモードで./src/index.js
を起点としてjsファイルをまとめて
dist
配下のbundle.js
というファイルに出力してください。
ということを意味しています。
4. webpack build
設定ファイルができたので実際にwebpackを下記コマンドで動作してみましょう
npx webpack build
dist
配下にbundle.js
というファイルができたのを確認できたでしょうか?
5. 動作確認
実際にnodeでbundle.js
を動作させてみると
Hello Johnが出力されて2ファイルを1ファイルにまとめることができたことがわかると思います。
node ./dist/bundle.js
// Hello John
3. loaderを作成してみよう
ここからはtxtファイル作成した後index.js
で呼び出し
txtファイルはloaderなしではbundleされないことを確認した後
loaderを作成してtxtファイルをbundleできるようにしたいと思います。
1.src/hello.txtの作成
こんにちは
2. src/index.jsで呼び出す
// src/index.js
const name = require("./name");
const hello = require("./hello.txt");
console.log("Hello" + name + hello);
3. webpack build
npx webpack build
4.動作確認
node ./dist/bundle.js
// ReferenceError: こんにちは is not defined
エラーが出てうまくバンドルできていないことが
確認できると思います。
webpackではjsファイルしかbundleすることができず
js以外のファイルをbundleするためにはloaderが必要になります。
5. loaders/textLoader.jsの作成
textファイルをwebpackでbundleできるようにするために
loaders
ディレクトリを作りその配下にtextLoader.js
を作成します。
module.exports = function (contents) {
return `module.exports = ${JSON.stringify(contents)};`; // Node.js で扱えるようにテキストファイルを変換
}
6. webpack.config.jsの修正
webpack.config.js
を修正して.txt
で終わるファイルには先ほど作成した
textLoader.js
を適応するようにします。
const path = require("path");
module.exports = {
mode: "development",
entry: "./src/index.js",
output: {
path: path.resolve(__dirname, "dist"),
filename: "bundle.js",
},
// 以下を追加
module: {
rules: [
{
// 正規表現で適応したいファイル名を書く
test: /\.txt$/,
// 正規表現に合致したファイルに対して適応するloaderを書く
use: [{ loader: path.resolve(__dirname, "loaders/textLoader.js") }],
},
],
},
};
7. webpack build
npx webpack build
8. 動作確認
node ./dist/bundle.js
// Hello John こんにちは
loaderによってtxtファイルをbundleすることができ
先ほどのエラーは消えていることがわかります。
4. pluginを作ってみよう
ここからはpluginを作成しhello.txt
の代わりに新しく作成するoverwrite.txt
を上書きするpluginを作成したいと思います。
plugin/overwrite.txtの作成
上書きしたよ
2. plugin/textplugin.jsの作成
ここではtxtファイルが読み込まれるときに作用してoverwrite.txtに置換してしまうというpluginを作成します。
const path = require("path");
module.exports = class MessagePlugin {
apply(compiler) {
compiler.hooks.normalModuleFactory.tap("messagePlugin", (factory) => {
// ファイルのインポートのための名前解決の手前でフック
factory.hooks.beforeResolve.tapAsync(
"messagePlugin",
(resolve, callback) => {
// 特定のファイル名のとき読み込むファイルを変える
if (/\.txt$/.test(resolve.request)) {
resolve.request = path.resolve(__dirname, "overwrite.txt");
}
callback();
}
);
});
}
};
3. webpack.config.jsの修正
webpack.config.js
を修正して先ほど作成した
textplugin.js
を読み込むようにします。
const path = require("path");
//下記を追加
const MessagePlugin = require("./plugin/textplugin")
module.exports = {
mode: "development",
entry: "./src/index.js",
output: {
path: path.resolve(__dirname, "dist"),
filename: "bundle.js",
},
//下記を追加
plugins: [
new MessagePlugin()
],
module: {
rules: [
{
test: /\.txt$/i,
use: [{ loader: path.resolve(__dirname, "loaders/textLoader.js") }],
},
],
},
};
4. webpack build
npx webpack build
5. 動作確認
node ./dist/bundle.js
// Hello John 上書きしたよ
pluginによってファイルの読み込み時に置換されて
「こんにちは」が「上書きしたよ」になっていることが確認できたと思います。