webpackでjsのオプション・配置場所をカスタマイズする
既存だと出力時にbodyの下に
<script src="/assets/js/bundle-e57c2548e14548c673e0.js"></script>
headの下に
<link href="/assets/css/bundle-e57c2548e14548c673e0.css" rel="stylesheet">
のように出力されるので、出力される場所の変更・ハッシュ値の変更などを行う
既存の状態
- 変更前のhtml
<!DOCTYPE html> <html lang="ja"> <head> <link href="/assets/css/bundle-a1e0d6d9e5b3b4d09222.css" rel="stylesheet"> </head> <body> <header>ヘッダー</header> <p>テキスト</p> <footer>フッター</footer> <script src="/assets/js/bundle-a1e0d6d9e5b3b4d09222.js"></script> </body> </html>
- webpackの設定
最小限なので、一部を省略。
const { resolve, join } = require('path') const HtmlWebpackPlugin = require('html-webpack-plugin') const MiniCssExtractPlugin = require('mini-css-extract-plugin') const buildDir = resolve(__dirname, 'dist') module.exports = { entry: { bundle: './assets/js/common.js', // コンパイル前のjsファイルを指定 }, output: { path: buildDir, publicPath: '/', filename: join('assets/js', '[name]-[hash].js'), // js出力を行うファイル場所・ファイル名の指定 }, plugins: [ new HtmlWebpackPlugin({ filename: 'index.html', // 出力するhtmlのファイルの場所・ファイル名 template: 'pug/index.pug', // pugのファイル箇所を記載 }), new MiniCssExtractPlugin({ filename: join('assets/css', '[name]-[hash].css'), ignoreOrder: true, }), ], }
css, jsを出力されないように変更
inject
の設定を行う
const HtmlWebpackPlugin = require('html-webpack-plugin') module.exports = { plugins: [ new HtmlWebpackPlugin({ inject: false, // ここにinjectの設定を行う filename: 'index.html', // 出力するhtmlのファイルの場所・ファイル名 template: 'pug/index.pug', // pugのファイル箇所を記載 }), ], }
injectをfalseに設定
<!DOCTYPE html> <html lang="ja"> <head></head> <body> <header>ヘッダー</header> <p>テキスト</p> <footer>フッター</footer> </body> </html>
injectをhead
に設定
<!DOCTYPE html> <html lang="ja"> <head> <link href="/assets/css/bundle-a1e0d6d9e5b3b4d09222.css" rel="stylesheet"> <script src="/assets/js/bundle-a1e0d6d9e5b3b4d09222.js"></script> </head> <body> <header>ヘッダー</header> <p>テキスト</p> <footer>フッター</footer> </body> </html>
injectをbody
に設定
<!DOCTYPE html> <html lang="ja"> <head> <link href="/assets/css/bundle-a1e0d6d9e5b3b4d09222.css" rel="stylesheet"> </head> <body> <header>ヘッダー</header> <p>テキスト</p> <footer>フッター</footer> <script src="/assets/js/bundle-a1e0d6d9e5b3b4d09222.js"></script> </body> </html>
jsのファイルにdeferを追加したい時
scriptLoading
のオプションを「defer」に行うことでjsにdeferを追加することができる
const HtmlWebpackPlugin = require('html-webpack-plugin') module.exports = { plugins: [ new HtmlWebpackPlugin({ scriptLoading: 'defer', // deferの追記を行う filename: 'index.html', // 出力するhtmlのファイルの場所・ファイル名 template: 'pug/index.pug', // pugのファイル箇所を記載 }), ], }
<!DOCTYPE html> <html lang="ja"> <head> <script defer src="/assets/js/bundle-a1e0d6d9e5b3b4d09222.js"></script> <link href="/assets/css/bundle-a1e0d6d9e5b3b4d09222.css" rel="stylesheet"> </head> <body> <header>ヘッダー</header> <p>テキスト</p> <footer>フッター</footer> </body> </html>
jsのdeferの設定を個別に分けたい場合
「a.js」にはdeferをつけて、「b.js」にはつけないなどの設定を行いたいときに、html-webpack-injector
を使用。
インストール
$ npm i -D html-webpack-injector
or
$ yarn add -D html-webpack-injector
使い方
const { resolve, join } = require('path') const HtmlWebpackPlugin = require('html-webpack-plugin') const HtmlWebpackInjector = require('html-webpack-injector') // html-webpack-injector追加 const buildDir = resolve(__dirname, 'dist') module.exports = { entry: { bundle_head: './assets/js/common.js', // コンパイル前のjsファイルを指定(bundle_head追加) sample: './assets/js/common.js', // 検証用に追加 }, output: { path: buildDir, publicPath: '/', filename: join('assets/js', '[name].js'), // [hash]削除 }, plugins: [ new HtmlWebpackPlugin({ chunksConfig: { defer: ['bundle_head'], // deferをつけるものの名前を変更 }, filename: 'index.html', template: 'pug/index.pug', }), new HtmlWebpackInjector(), // html-webpack-injector追加 ], }
- 出力結果
<!DOCTYPE html> <html lang="ja"> <head> <script defer src="/assets/js/bundle_head.js"></script> <link href="/assets/css/bundle_head-73f6ef1c604bc2d9aa0f.css" rel="stylesheet"> </head> <body> <header>ヘッダー</header> <p>テキスト</p> <footer>フッター</footer> <script src="/assets/js/sample.js"></script> </body> </html>
html-webpack-injector
を少しだけ調整
現状だと
- jsのファイルにハッシュ値をつけるとdeferの対応ができない
ファイル名_head
にしなければ内に配置されない
ため、少し変更を行う。
対応方法
1. https://github.com/architgarg/html-webpack-injector/blob/master/index.jsのファイルを持ってくる
2. 正規表現の内容を変更
筆者の正規表現スキルがあまりないので、あんまり綺麗ではないですが、、、
- const regex = new RegExp(`(\/${name}\-\+\.)|(${name}\-\\.)`) // 既存 + const regex = /bundle\-[a-zA-Z0-9]/ // bundle-[hash]のみに反映をする
3. _head
を記載しなくてもの中に配置されるようにする
以下のような変更の方法だと全てのjsファイルが
に配置されてしまうので、注意。- if ((chunk.attributes.src && chunk.attributes.src.includes("_head")) || chunk.attributes.href) + if (chunk.attributes.src || chunk.attributes.href)
変更後のコード
webpack
const { resolve, join } = require('path') const HtmlWebpackPlugin = require('html-webpack-plugin') const HtmlWebpackInjector = require('./webpack.htmlinjector') // 上記の設定したファイルを格納したもの(webpack.htmlinjector.js)を読み込む const buildDir = resolve(__dirname, 'dist') module.exports = { entry: { bundle: './assets/js/common.js', sample: './assets/js/common.js', }, output: { path: buildDir, publicPath: '/', filename: join('assets/js', '[name].js'), }, plugins: [ new HtmlWebpackPlugin({ chunksConfig: { defer: ['bundle', 'sample'], // 出力を行うjsファイルを記載 }, filename: 'index.html', template: 'pug/index.pug', }), new HtmlWebpackInjector(), ], }
出力後のhtml
<!DOCTYPE html> <html lang="ja"> <head> <script defer src="/assets/js/bundle-4ed47f9b6282c1bead75.js"></script> <script src="/assets/js/sample-4ed47f9b6282c1bead75.js"></script> <link href="/assets/css/bundle-4ed47f9b6282c1bead75.css" rel="stylesheet"> </head> <body> <header>ヘッダー</header> <p>テキスト</p> <footer>フッター</footer> </body> </html>