8
9

More than 5 years have passed since last update.

Webpack Level 4: Webpack Pluginsを用いて静的サイトをS3に自動デプロイ

Posted at

こんにちは!高野です。
Webpack Level Upシリーズもついに第4回。今回はPluginの設定方法について調べていきます。
実はこのPluginを使いこなせればできることの枠が大幅に広がり、果ては ビルド結果をgzip化してS3にアップロードし、CloudFrontのinvalidationまで自動化する なんていうデプロイ自動化までできちゃったりします。夢が広がりますね。
それでは、始めましょう。

コンテンツ

設定方法

Pluginの基本的な設定方法は大体どれも同じです。仮に HtmlWebpackPlugin を追加する方法を例にとって見てみましょう。(どういう機能を持つプラグインなのかは追って解説します。)

$ npm install --save-dev html-webpack-plugin
webpack.config.js
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ファイルに全ファイルを結合することができます。
webpack.config.js
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',
    }),
  ],
};
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/ 内を削除してからバンドル結果を出力してくれます。
webpack.config.js
var WebpackCleanupPlugin = require('webpack-cleanup-plugin');

module.exports = {
  mode: 'production',
  plugins: [
    new WebpackCleanupPlugin(),
  ],
};

UglyfyjsWebpackPlugin

  • バンドル時にJSファイルをminifyしてファイルサイズを縮小してくれます。
  • webpack.config.js での設定方法が他と若干異なるので注意が必要です。
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化したくないファイルもバンドル対象に含まれる場合は適用対象を絞ることもできる
webpack.config.js
var CompressionPlugin = require('compression-webpack-plugin');

module.exports = {
  mode: 'production',
  plugins: [
    new CompressionPlugin({ test: /\.js$/, filename: '[path]' }),
  ],
};
  • '[path]' という文字列がバンドル時に対象のファイル名(拡張子含む)に置換される。

WebpackS3Plugin

  • バンドル結果のファイルをS3に自動でアップロードする
webpack.config.js
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を自動実行
webpack.config.js
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() ],
  },
};

参考

8
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
9