1. はじめに
本記事では特にhtml-webpack-plugin1とmini-css-extract-plugin2を使って、entryに追加した外部cssをバンドル後のhtmlファイルのheadタグにインラインスタイルで出力する方法をご紹介します。
ユースケースとしては、以下のような環境でしょう。
- JavaScriptが実行できない環境
- style-loader3が使用できない
- 外部ファイルとしてcssをimportできない環境(htmlメールなど)
- mini-css-extract-pluginだけでは解決できない
2. 各構成
はじめに実行環境やフォルダ構成、本記事で主に使用するファイルの内容を提示します。
以下の構成や中身をそのままコピーして実行いただくと、本記事に示した内容を実現できます。
2.1 実行環境
- node: 16.14.2
- npm: 8.5.0
2.2 フォルダ構成
output/
index.html
src/
assets/
styles/
common.css
app.html
gitignore
package-lock.json
package.json
webpack.config.js
2.3 各ファイル内容
{
// ...
"scripts": {
"build": "NODE_ENV=production webpack --mode production"
},
"devDependencies": {
"css-loader": "^6.7.1",
"html-webpack-plugin": "^5.5.0",
"mini-css-extract-plugin": "^2.6.1",
"webpack": "^5.74.0",
"webpack-cli": "^4.10.0"
}
}
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><%= htmlWebpackPlugin.options.title %></title>
<style>
<%= compilation.getAsset(htmlWebpackPlugin.files.css[0]).source.source() %>
</style>
</head>
<body>
<main>
<p>メインコンテンツ</p>
</main>
</body>
</html>
p {
background-color: #333;
color: #fff;
}
const path = require("path")
const MinCssExtraPlugin = require("mini-css-extract-plugin")
const HtmlWebpackPlugin = require("html-webpack-plugin")
const projectBasePath = path.resolve(__dirname, "src")
const publicBasePath = path.resolve(__dirname, "output")
const filePath = {
css: "./src/assets/styles/common.css",
js: "./src/assets/js/[name].js",
template: `${projectBasePath}/app.html`,
html: `${publicBasePath}/index.html`
}
module.exports = {
entry: {
css: filePath.css
},
output: {
filename: filePath.js,
path: publicBasePath
},
plugins: [
new MinCssExtraPlugin({ filename: filePath.css }),
new HtmlWebpackPlugin({
template: filePath.template,
filename: filePath.html,
minify: false,
inject: false
}),
],
module: {
rules: [
{
test: /\.css$/,
use: [
MinCssExtraPlugin.loader,
"css-loader"
]
},
]
}
}
3. 説明
html-webpack-pluginの公式ドキュメントによると、template
オプションで指定したhtmlファイルからtemplateParameters
を参照することができます。
templateParameters
の型定義部分を引用すると以下のような内容です4。
interface TemplateParameter {
compilation: any;
htmlWebpackPlugin: {
tags: {
headTags: HtmlTagObject[];
bodyTags: HtmlTagObject[];
};
files: {
publicPath: string;
js: Array<string>;
css: Array<string>;
manifest?: string;
favicon?: string;
};
options: Options;
};
webpackConfig: any;
}
上記の型情報によると、htmlWebpackPlugin.files.css
でcssのファイルパスを取得することができます5。
[ './src/assets/styles/common.css' ]
また、compilation6はwebpackのcompilation
オブジェクトを指します。
今回はgetAssetメソッド7を使用します。getAsset
メソッドはentry
に指定したファイル名からファイル情報を取得するため、例えば ./src/assets/styles/common.css
を指定すると以下のような情報を取得することができます。
{
name: './src/assets/styles/common.css',
source: CachedSource {
_source: [ConcatSource],
_cachedSourceType: undefined,
_cachedSource: undefined,
_cachedBuffer: undefined,
_cachedSize: undefined,
_cachedMaps: Map(0) {},
_cachedHashUpdate: undefined
},
info: {}
}
そして、source
プロパティにあるsource()
を実行することで、cssを取得することができます。
最終的なcssを取得する指定方法は以下のようになります。
compilation.getAsset(htmlWebpackPlugin.files.css[0]).source.source()
build後、生成されたhtmlファイルでcssの内容が表示されていれば成功です。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Webpack App</title>
<style>
p {
background-color: #333;
color: #fff;
}
</style>
</head>
<body>
<main>
<p>メインコンテンツ</p>
</main>
</body>
</html>
4. 制限
html-loader8を導入している場合はJSPで記述したコードがそのまま出力されてしまい、html内でtemplateParameters
の内容に参照することができません。
5. おわりに
本記事ではwebpackを使ったcssのインライン出力の一例をご紹介しました。
すごくニッチな内容ですが、お役に立てれば幸いです。