0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

webpackを使ってhtmlファイルのheadタグにインラインスタイルのCSSを出力する方法

Last updated at Posted at 2023-01-04

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 各ファイル内容

package.json
{
	// ...
	"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"
	}
}
app.html
<!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>
common.css
p {
    background-color: #333;
    color: #fff;
}
webpack.config.js
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の内容が表示されていれば成功です。

index.html
<!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のインライン出力の一例をご紹介しました。
すごくニッチな内容ですが、お役に立てれば幸いです。

  1. https://webpack.js.org/plugins/html-webpack-plugin/

  2. https://webpack.js.org/plugins/mini-css-extract-plugin/

  3. https://webpack.js.org/loaders/style-loader/

  4. https://github.com/jantimon/html-webpack-plugin/blob/main/typings.d.ts#L186-L203

  5. https://github.com/jantimon/html-webpack-plugin#writing-your-own-templates

  6. https://webpack.js.org/api/compilation-object/

  7. https://webpack.js.org/api/compilation-object/#getasset

  8. https://webpack.js.org/loaders/html-loader/

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?