前回の記事ではwebpack v4を使用し、最低限のシンプルな構成でビルドするまでをご紹介しました。
まだこちらの内容を見ていない方は是非ご覧ください。
今回の記事では『開発環境と本番環境をわける』『webpackからhtmlを出力する』など、
より実践的な内容についてシンプルではありますが、ご紹介いたします。
開発環境では、watch機能を使用することでソースコードを自動でビルドさせることができたり、
本番環境では、圧縮した状態で出力してくれるなど便利な機能を使用することができます。
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',
})
それぞれの設定ファイルを利用できるように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を本番環境の際に自動的に削除してもらいます。
terserというプラグインを使用します。productionモードで使用されるプラグインで、ファイルを圧縮してくれます。webpackに標準で入っているプラグインですが、より使いやすくするために新しいバージョンをインストールし内容を書き換え使用します。
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をインストールします。
%npm install --save-dev clean-webpack-plugin@3.0.0
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は除外
})
]
}
手動でのファイル記述ミスや更新漏れ、ファイル名やファイルの数が変わることがあるため自動でhtmlを出力できるようにします。
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機能が便利です。
%npm install --save-dev webpack-dev-server@3.11.0
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にサーバーの設定を追加します。
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を起動します。
%npm start
webpack-dev-serverはファイルを出力しないため
publicが空になってしまうので出力する際はnpm run devやnpm run buildしましょう。
ページが複数ある場合などページごとに読み込むjavascriptファイルを変える場合に使用します。
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'], //どのファイルを読み込むか指定。していない場合はすべて読み込まれます。
})
]
}
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