こんな人へ
- PugとかHandlebarsとか使い慣れてないし、普通にNodeJSで書きたい
- HtmlWebpackPluginに関する処理を
webpack.config.js
に入れたくない
https://github.com/nju33-qiita/example-templatejs-of-html-webpack-template
HtmlWebpackPlugin
そのWebpackで作られるファイルを、<body/>
の最後で読み込むHTMLを作るプラグイン。
{
plugins: [new HtmlWebpackPlugin()]
}
これで、特に何もしなくてもバンドルファイルを埋め込んだ.html
が作れる。
webpack.output.filename
を'bundle.js?[hash]'
な感じにしてるとCacheBustingな感じで埋め込んでくれていいです。
Templateを設定
pug-loaderをインストールすれば、./template.pug
ファイルをテンプレートに設定できる。(最後にバンドルファイルが挿入されるのは一緒)
{
plugins: [
new HtmlWebpackPlugin({template: './template.pug'})
]
}
ただオプション多いし引数で何渡ってるのか全然分からない😇
あとググるのに疲れてる。
(なのであんまり詳しくないので、オプションでいいじゃんという話かも)
Templateに.js
を指定
Templateのオプションだと分かんなかったんですが.js
が指定できます。
{
plugins: [
new HtmlWebpackPlugin({template: './template.js'})
]
}
template.js
はこんな感じにHTMLの文字列を返すようにします。
// (params: {[string]: any}) => stirng | Promise<string>
module.exports = () => '<html>...</html>';
ちなみにTypescriptなルールがあるなら./template.ts
も渡せます。
HTMLは別ファイルに
別に.js
に書いちゃっていいんですが、分けたいと思ったのでhtmlは同じディレクトリのtemplate.html
というファイルに記述したいとします。
const fs = require('fs');
const path = require('path');
const {promisify} = require('util');
module.exports = async params => {
// __dirname === '/'
// process.cwd() === '/'
// webpack.context
const {context} = params.compilation.options;
const htmlFilename = path.resolve(context, 'path/to/template.html');
const html = await promisify(fs.readFile)(htmlFilename, 'utf-8');
return html;
}
同じディレクトリなので./template.html
でいいような感じがしますが、それは/template.html
を見てしまうのでエラーになります。かといって絶対パスを指定すると、他の人も関係するプロジェクトの場合問題になるので、webpack.context
の基準パスを使います。
webpack.context
は、そのWebpackの基準パスが入ってます。
Templateに値を入れて展開
このTemplateでしか使ってないとかなら、ここでPugとか使えばいいんです。
例えば.css
をCacheBustingな感じにして埋め込むみたいなのとか。何でもいいんですが、ちっさいのでいいのでpupaを使ってやってみます。
HTMLにこんな感じで追記して、
<link rel="stylesheet" href="{href}">
glob
で探して、Hash取って、pupa
で展開したHTMLを返します。
// ...
const crypto = requrie('crypto');
const glob = require('glob');
module.exports = async params => {
// ...
const [filename] = await promisify(glob)(path.resolve(context, 'base/foo.css'));
const css = await promisify(fs.readFile)(filename, 'utf-8');
const basename = path.basename(filename);
const md5hash = crypto.createHash('md5')
const md5hash.update(css);
return pupa(html, {
href: '/' + basename + '?' + md5hash.digest('hex').slice(0, 20)
});
};
これでこんな感じ。
<link rel="stylesheet" href="/foo.css?11985b07e3121564a73d">
これで埋め込めました。
バンドルファイルに含ませたくないんだ的なファイルに使うといいと思います。(本番のdllとかcssとか)
注意
babel-loaderとかを.js
が経由する感じだと、template:
で読み込む時にシンタックスで怒られたりするので注意です。(Runtime
とかあのへん)