こんにちは!高野です。
Webpack Level Upシリーズもついに第4回。今回はPluginの設定方法について調べていきます。
実はこのPluginを使いこなせればできることの枠が大幅に広がり、果ては ビルド結果をgzip化してS3にアップロードし、CloudFrontのinvalidationまで自動化する なんていうデプロイ自動化までできちゃったりします。夢が広がりますね。
それでは、始めましょう。
コンテンツ
- Webpack Level 1: 裸のWebpackのデフォルト動作を理解する
- Webpack Level 2: 設定ファイルをカスタマイズする
- Webpack Level 3: loadersを追加して.js以外のファイルを結合する
- Webpack Level 4: Webpack Pluginsを用いて静的サイトをS3に自動デプロイ <- 今ここ
設定方法
Pluginの基本的な設定方法は大体どれも同じです。仮に HtmlWebpackPlugin
を追加する方法を例にとって見てみましょう。(どういう機能を持つプラグインなのかは追って解説します。)
$ npm install --save-dev html-webpack-plugin
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
mode: 'production',
// ...
plugins: [
new HtmlWebpackPlugin(),
],
};
上記のように、(1) パッケージをインストールして (2) 設定ファイルの中で呼び出し (3) plugins の配列の中に初期化したオブジェクトを入れれば完了です。
オプションを付与したい場合は、大抵は初期化時の引数にオプションを指定するオブジェクトを渡せばOKです。めちゃめちゃ簡単ですね。
では、実際どのようなプラグインがあって、どのように使えるのかについて見ていきましょう。
紹介
HtmlWebpackPlugin
-
index.html
を用意しなくても、最低限のHTMLテンプレートを用意してくれるプラグインですが、ファイル名を指定することでHTMLファイルをエントリーポイントとしてバンドルしてくれるので、LP制作時などに重宝します。 -
html-loader
等、HTMLファイルを読み込むためのローダーと併用します。 -
url-loader
等と併用することで、1枚のHTMLファイルに全ファイルを結合することができます。
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
mode: 'production',
module: {
rules: [
{ test: /\.(gif|png|jpe?g|)$/, use: 'url-loader' },
{ test: /\.html?$/, use: 'html-loader' },
],
},
plugins: [
new HtmlWebpackPlugin({
template: './src/page.html',
}),
],
};
<!DOCTYPE HTML>
<html lang="ja">
<head>
<meta charset="utf-8" />
<title>Webpack Level Up 5</title>
</head>
<body>
<h1>Webpack Level Up 5</h1>
<img src="./assets/person.png" alt="person image" />
</body>
</html>
-
src/assets/person.png
に適当な画像ファイルを置いてからバンドルを実行すると、url-loader
によって画像ファイルがバンドルされた結果がdist/index.html
内に出力されていることが分かります。
WebpackCleanupPlugin
- 不要なファイルを削除した後にバンドルを実行すると、
dist/
内に不要なファイルが残ってしまうことがあります。そんな時、WebpackCleanupPlugin
を追加しておけばバンドルを実行する度にdist/
内を削除してからバンドル結果を出力してくれます。
var WebpackCleanupPlugin = require('webpack-cleanup-plugin');
module.exports = {
mode: 'production',
plugins: [
new WebpackCleanupPlugin(),
],
};
UglyfyjsWebpackPlugin
- バンドル時にJSファイルをminifyしてファイルサイズを縮小してくれます。
-
webpack.config.js
での設定方法が他と若干異なるので注意が必要です。
var UglyfyjsWebpackPlugin = require('uglifyjs-webpack-plugin');
module.exports = {
mode: 'production',
optimization: {
minimizer: [ new UglyfyjsWebpackPlugin() ],
},
};
CompressionPlugin
- バンドル時にファイルをgzip化してファイルサイズを圧縮してくれます。
- 単純に plugins に追加しただけの場合 main.js に加えて main.js.gz を出力しますが、ファイル名を設定することでgzip化したファイルを main.js として出力するといったことも可能です。
- 画像ファイル等、gzip化したくないファイルもバンドル対象に含まれる場合は適用対象を絞ることもできる
var CompressionPlugin = require('compression-webpack-plugin');
module.exports = {
mode: 'production',
plugins: [
new CompressionPlugin({ test: /\.js$/, filename: '[path]' }),
],
};
-
'[path]'
という文字列がバンドル時に対象のファイル名(拡張子含む)に置換される。
WebpackS3Plugin
- バンドル結果のファイルをS3に自動でアップロードする
var WebpackS3Plugin = require('webpack-s3-plugin');
module.exports = {
mode: 'production',
plugins: [
new WebpackS3Plugin({
s3Options: {
accessKeyId: '<YOUR AWS ACCESS KEY ID>',
secretAccessKey: '<YOUR AWS SECRET ACCESS KEY>',
region: '<YOUR BUCKET REGION NAME>',
},
s3UploadOptions: {
Bucket: '<YOUR BUCKET NAME>',
ContentEncoding: 'gzip',
},
cloudfrontInvalidateOptions: {
DistributionId: '<YOUR CLOUDFRONT DISTRIBUTION ID>',
Items: ['/*'],
},
}),
],
};
-
s3UploadOptions.ContentEncoding: 'gzip'
を指定することで、S3がアップロードされたオブジェクトを返す時にContent-Encoding: gzip
ヘッダーを付与してくれる -
cloudfrontInvalidateOptions
を指定することで、アップロード完了後に CloudFrontの指定パスに対して invalidation を実行してくれる
まとめ
以上のプラグインを組み合わせると、下記のような自動デプロイ体制を構築できる。
- HTMLファイルに画像ファイルをBase64エンコードして結合
- JavaScriptファイルはminifyしてファイルサイズを縮小
- 全ファイルをgzip化してファイルサイズを圧縮
- S3に自動でアップロードして
Content-Encoding: gzip
ヘッダを付与 - アップロードしたファイルについてCloudFront invalidationを自動実行
var HtmlWebpackPlugin = require('html-webpack-plugin');
var WebpackCleanupPlugin = require('webpack-cleanup-plugin');
var UglyfyjsWebpackPlugin = require('uglifyjs-webpack-plugin');
var CompressionPlugin = require('compression-webpack-plugin');
var WebpackS3Plugin = require('webpack-s3-plugin');
module.exports = {
mode: 'production',
module: {
rules: [
{ test: /\.css$/, use: ['style-loader', 'css-loader'] },
{ test: /\.scss$/, use: ['style-loader', 'css-loader', 'sass-loader'] },
{ test: /\.(gif|png|jpe?g|)$/, use: 'url-loader' },
{ test: /\.html?$/, use: 'html-loader' },
],
},
plugins: [
new HtmlWebpackPlugin({ template: './src/page.html' }),
new WebpackCleanupPlugin(),
new CompressionPlugin({ test: /\.js$/, filename: '[path]' }),
new WebpackS3Plugin({
s3Options: {
accessKeyId: '<YOUR AWS ACCESS KEY ID>',
secretAccessKey: '<YOUR AWS SECRET ACCESS KEY>',
region: '<YOUR BUCKET REGION NAME>',
},
s3UploadOptions: {
Bucket: '<YOUR BUCKET NAME>',
ContentEncoding: 'gzip',
},
cloudfrontInvalidateOptions: {
DistributionId: '<YOUR CLOUDFRONT DISTRIBUTION ID>',
Items: ['/*'],
},
}),
],
optimization: {
minimizer: [ new UglyfyjsWebpackPlugin() ],
},
};