NOANAVI

BLOG

【webpack v4】様々な機能やプラグインの使用方法

前回の記事ではwebpack v4を使用し、最低限のシンプルな構成でビルドするまでをご紹介しました。
まだこちらの内容を見ていない方は是非ご覧ください。

今回の記事では『開発環境と本番環境をわける』『webpackからhtmlを出力する』など、
より実践的な内容についてシンプルではありますが、ご紹介いたします。

開発環境と本番環境の設定ファイルを分ける

開発環境では、watch機能を使用することでソースコードを自動でビルドさせることができたり、
本番環境では、圧縮した状態で出力してくれるなど便利な機能を使用することができます。

webpack-mergeをインストール

webpack-mergeをインストールします。

%npm install --save-dev webpack-merge@5.0.9

設定ファイルを追加

では設定ファイルを『共通ファイル』『開発用ファイル』『本番用ファイル』に分けていきます。

共通ファイル

webpack.config.jsをリネイムし、webpack.common.jsに変更します。

modeの指定は開発用と環境用で異なるので削除します。

const path = require('path');

module.exports = {
  ; modeは開発用と本番で異なるので削除
  entry:'./src/js/app.js',
  output:{
     path: path.resolve(__dirname,'public'), //絶対パスを指定
     filename:'js/bundle.js',
  },
}

開発用ファイルを作成

webpack.dev.jsを作成し下記を記述します。

const { merge } = require('webpack-merge');
const commonConfig = require('./webpack.common.js')

module.exports = merge(commonConfig,{
  mode:'development',
  watch:true //ファイルを更新したら自動更新されるため自分でビルド不要
})

本番用ファイルを作成

webpack.prod.jsを作成し下記を記述

const { merge } = require('webpack-merge');
const commonConfig = require('./webpack.common.js')

module.exports = merge(commonConfig,{
  mode:'production',
})

それぞれの設定ファイルを利用できるようにnpm scriptsを書き換え

それぞれの設定ファイルを利用できるようにpackage.jsonのnpm scriptsを書き換えます。

–config ファイル名でファイルを指定しwebpackを実行できます。

  {
  "name": "test",
  "scripts": {
    "dev":"webpack --config webpack.dev.js", //開発用
    "build":"webpack --config webpack.prod.js" //本番用
  },
  "devDependencies": {
    "webpack": "^4.43.0",
    "webpack-cli": "^3.3.11",
    "webpack-merge": "^5.0.9"
  },
  "dependencies": {
    "jquery": "^3.5.1",
    "velocity-animate": "^1.5.2"
  }
}

開発用と本番用を実行

こちらが開発用ファイルの実行になります。
開発用ではwatchがtrueなのでエンドポイントを更新すると自動で再ビルドされます。

%npm run dev

こちらが本番用ファイルの実行になります。

本番用ではpublic/js/bundle.jsが圧縮されて出力されますので確認しましょう。

%npm run build

補足:modeによって有効になる設定がかわるので公式ドキュメントを確認してください。

ご自身で設定したwebpackの設定が優先されるので確認し変更など行ってください。

console.logを削除し本番用ファイルを出力する

開発中に確認のため使用した(している)console.logを本番環境の際に自動的に削除してもらいます。

terserというプラグインを使用します。productionモードで使用されるプラグインで、ファイルを圧縮してくれます。webpackに標準で入っているプラグインですが、より使いやすくするために新しいバージョンをインストールし内容を書き換え使用します。

terser-webpack-pluginをインストール

terser-webpack-plugin@3.0.8をインストールします。

webpackに入っている(node_modules/webpack/lib/WebpackOptionsDefaulter.jsの311行目あたり)がバージョンが古いのでinstallしこちらを使用します。

%npm install --save-dev terser-webpack-plugin@3.0.8

設定ファイルを変更します。

本番用のbuildでconsole.logを削除したいのでwebpack.prod.jsを更新します。

const { merge } = require('webpack-merge');
const commonConfig = require('./webpack.common.js')
const TerserPlugin = require('terser-webpack-plugin') //追加

module.exports = merge(commonConfig,{
  mode:'production',
  optimization:{ //追加
    minimizer:[
      new TerserPlugin({
        extractComments: false, //ライセンスコメントファイル不要
        terserOptions:{
          compress:{
            drop_console: true, //console.log削除
          }
        }
      })
    ]
  }
})

こちらでnpm run buildを行うとconsole.logが削除され圧縮されたファイルが出力されます。

ソースマップを作成する

ソースマップが含まれたファイルを出力できるようにします。ソースマップはバンドル後のファイルとバンドル前のファイルを関連付けコードを確認できるのでデバックしやすくなります。

開発環境のみ使用しますので(一般ユーザーがソースマップにアクセスされると良くないため)webpack.dev.jsを更新します。

const { merge } = require('webpack-merge');
const commonConfig = require('./webpack.common.js');

module.exports = merge(commonConfig, {
  mode: 'development',
  watch: true,
  devtool: 'cheap-module-eval-source-map'
});

エラーが起きるとgooglechromeのconsoleを確認するとエラーの場所がわかりやすくなります。

出力先をクリーンアップしてからファイルを出力

不要なファイルの消し忘れ、ファイル名が変わる場合、ファイルの一部が不要になる場合がありますので出力先をクリーンアップしファイルを出力します。

clean-webpack-pluginをインストール

まずはclean-webpack-pluginをインストールします。

%npm install --save-dev clean-webpack-plugin@3.0.0

webpack.common.jsを更新します

outputのpathに設定したディレクトリ(public)を削除しますので、

html以外のファイルやディレクトリを削除する設定(htmlはwebpackで出力していないため)を行います。

const path = require('path');
const {CleanWebpackPlugin} = require('clean-webpack-plugin') //ここ追加

module.exports = {
  entry:'./src/js/app.js',
  output:{
    path: path.resolve(__dirname,'public'), //絶対パスを指定
    filename:'js/bundle.js',
  },
  plugins:[  //追加
    new CleanWebpackPlugin({
      cleanOnceBeforeBuildPatterns: ['**/*', '!**.html'], //htmlは除外
    })
  ]
}

webpackから出力されたファイルを読み込んだhtmlを出力する

手動でのファイル記述ミスや更新漏れ、ファイル名やファイルの数が変わることがあるため自動でhtmlを出力できるようにします。

html-webpack-pluginをインストール

html-webpack-pluginをインストールをインストールします

%npm install --save-dev html-webpack-plugin@4.3.0

設定ファイルを書き換える

htmlに関しても、webpackから出力するためCleanWebpackPluginではoutputディレクトリ内をすべてクリーンアップする設定に変更しています。

htmlの出力は./src/html/index.htmlを作成しこのテンプレートを出力します。

  const path = require('path');
  const {CleanWebpackPlugin} = require('clean-webpack-plugin')
  const HtmlWebpackPlugin = require('html-webpack-plugin') //追加

  module.exports = {
    entry:'./src/js/app.js',
    output:{
      path: path.resolve(__dirname,'public'), //絶対パスを指定
      filename:'js/bundle.js',
    },
    plugins:[
      new CleanWebpackPlugin(), //htmlもwebpackから出力するので削除している
      new HtmlWebpackPlugin({
        template:'./src/html/index.html' //htmlのテンプレート先
      })
    ]
  }

開発用サーバーの使用

webpack-dev-serverはソースコードを書き換えると自動反映されるlivereload機能が便利です。

webpack-dev-serverをインストール

%npm install --save-dev webpack-dev-server@3.11.0

npm scriptsでwebpack-dev-serverを使える設定

npm scriptsでwebpack-dev-serverを使える設定を行います。

  {
  "name": "test",
  "scripts": {
    "start": "webpack-dev-server --config webpack.dev.js" //開発用サーバー
    "dev":"webpack --config webpack.dev.js", //開発用
    "build":"webpack --config webpack.prod.js" //本番用
  },
  "devDependencies": {
    "webpack": "^4.43.0",
    "webpack-cli": "^3.3.11",
    "webpack-merge": "^5.0.9"
  },
  "dependencies": {
    "jquery": "^3.5.1",
    "velocity-animate": "^1.5.2"
  }
}

webpack.dev.jsにserverの設定を追加

開発用サーバーですので、webpack.dev.jsにサーバーの設定を追加します。

  const { merge } = require('webpack-merge');
  const commonConfig = require('./webpack.common.js');
  const path = require('path') //追加

  module.exports = merge(commonConfig, {
    mode: 'development',
    watch: true,
    devtool: 'cheap-module-eval-source-map',
    devServer:{ //追加
      open:true, //ブラウザ自動で開く設定
      port:9000, //portの指定
      contentBase:path.resolve(__dirname, 'public') //ディレクトリの指定
    }
  });

webpack-dev-serverを起動

webpack-dev-serverを起動します。

%npm start

webpack-dev-serverはファイルを出力しないため
publicが空になってしまうので出力する際はnpm run devやnpm run buildしましょう。

複数のエントリーポイントから複数のファイルを出力する

ページが複数ある場合などページごとに読み込むjavascriptファイルを変える場合に使用します。

webpack.common.jsを書き換え

const path = require('path');
const {CleanWebpackPlugin} = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
  entry:{  //エントリーポイントを複数指定
    app:'./src/js/app.js', 
    another: './src/js/another.js'
  },
  output:{
    path: path.resolve(__dirname,'public'), //絶対パスを指定
    filename:'js/[name].bundle.js', //filenameをエントリーポイントの名前に
  },
  plugins:[
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({  //1つ目のファイル指定
      template:'./src/html/index.html',
      chunks: ['app'] 
    }),
    new HtmlWebpackPlugin({  //2つ目のファイル指定
      filename: 'another.html',
      template: './src/html/another.html',
      chunks:['another'], //どのファイルを読み込むか指定。していない場合はすべて読み込まれます。
    })
  ]
}

another.htmlとanother.jsを作成

src/html/another.htmlとsrc/js/another.jsを作成する。
確認のためなのでindex.htmlとapp.jsとほぼ同じで大丈夫です。

実行する

npm run buildやnpm run devを行うと、app.jsとpublic.js、index.htmlとpublic.htmlが出力されます。

わかりやすいように関係のない箇所は省いていますが下記のような形で出力されます。

├── package-lock.json
├── package.json
├── public
│   ├── another.html //bundle後
│   ├── index.html  //bundle後
│   └── js
│        ├── app.bundle.js  //bundle後
│        └── another.bundle.js  //bundle後
├── src
│   ├── html
│   │    ├── index.html
│   │    └── another.html
│   └── js
│        ├── app.js
│        └── another.js
├── webpack.common.js
├── webpack.dev.js
└── webpack.prod.js