webpackでHTMLをいい感じにする。
お久しぶりです。
最近、Alpine.jsが気になっている、スピッカートの金山(@spicato_kana)です。
今回は、共通パーツをテンプレート化したり、階層別に分けたり、webpack で HTML をいい感じにしていきます!
そういえば、webpack って頭文字小文字だったんですね。
この記事を書くときに知りました。
webpack とプラグインの html-webpack-plugin、globule を使っています。
結論
〜
└── src
├── 〜
└── html
├── page
│ └── index.html
│ └── about
│ └── about.html
│ └── about01
│ └── about01.html
└── template
└── _header.html
npm install -D html-webpack-plugin
npm install -D globule
// モジュールの読み込み
const path = require("path");
const fs = require("fs");
const globule = require("globule");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const app = {
entry: {
index: "./src/assets/js/index.js",
about: "./src/assets/js/about.js",
about01: "./src/assets/js/about01.js",
},
~~~
}
const htmlDir = globule.find({
src: "*.html",
srcBase: "src/html/page",
matchBase: true,
prefixBase: true,
});
htmlDir.forEach((htmlFile) => {
const fileName = path.basename(htmlFile);
const chunksName = fileName.replace(".html", "");
const subDir = htmlFile.replace("src/html/page/", "").replace(fileName, "");
if (fileName.charAt(0) === "_") {
return;
} else if (fileName === "index.html") {
app.plugins.push(
new HtmlWebpackPlugin({
filename: fileName,
template: htmlFile,
chunks: [chunksName],
hash: true,
// 共通ヘッダーを読み込む
header: fs.readFileSync("./src/html/template/_header.html", "utf8"),
// ie11に対応する場合
// scriptLoading: "blocking",
})
);
} else {
app.plugins.push(
new HtmlWebpackPlugin({
filename: `${subDir}/index.html`,
template: htmlFile,
chunks: [chunksName],
hash: true,
// 共通ヘッダーを読み込む
header: fs.readFileSync("./src/html/template/_header.html", "utf8"),
// ie11に対応する場合
// scriptLoading: "blocking",
})
);
}
});
解説
今回は HTML 関連のみの解説なので、それ以外の webpack の設定は省略しています。
const htmlDir = globule.find({
src: "*.html",
srcBase: "src/html/page",
matchBase: true,
prefixBase: true,
});
ここで、src/html/page
から *.html
を探しています。
ちなみに、オプションのmatchBase: true
で、サブディレクトリからも探し、
prefixBase: true
で、src/html/page
も含むようにしています。
今回の場合だと、src/html/page/index.html
と src/html/page/about/about.html
を取得してきます。
const fileName = path.basename(htmlFile);
const chunksName = fileName.replace(".html", "");
const template = htmlFile.replace("src/html/page/", "").replace(fileName, "");
// 表示結果
{ fileName: 'about01.html', chunksName: 'about01', subDir: 'about/about01/'}
{ fileName: 'index.html', chunksName: 'index', subDir: '' }
{ fileName: 'about.html', chunksName: 'about', subDir: 'about/' }
それぞれ上記のような結果が返ってきます。
if (fileName.charAt(0) === "_") {
return;
} else if (fileName === "index.html") {
app.plugins.push(
new HtmlWebpackPlugin({
filename: fileName,
template: htmlFile,
chunks: [chunksName],
hash: true,
// 共通ヘッダーを読み込む
header: fs.readFileSync("./src/html/template/_header.html", "utf8"),
})
);
} else {
app.plugins.push(
new HtmlWebpackPlugin({
filename: `${subDir}/index.html`,
template: htmlFile,
chunks: [chunksName],
hash: true,
// 共通ヘッダーを読み込む
header: fs.readFileSync("./src/html/template/_header.html", "utf8"),
})
);
}
if (fileName.charAt(0) === "_") { return; }
は、ファイル名の最初の文字が _
だったら、除外しています。
_base.html
とか作って、コピペして使い回す時に便利です。
if (fileName === "index.html"){}
は、階層別に分けたりするための条件分岐です。
index.html
はそのまま出力し、それ以外はサブディレクトリを考慮して出力しています。
出力結果は、
─── dist
├── 〜
├── index.html
└── about
├── index.html
└── about
└── index.html
└── about01
└── index.html
ちなみに、ここのheader: fs.readFileSync("./src/html/template/_header.html", "utf8"),
で共通パーツを読み込んでいます。
readFileSync
は、ファイルの中身を読み込んでいます。
<div class="header__inner">ヘッダーだよ</div>
<body>
<div id="app">
<div class="container">
<header class="header"><%= htmlWebpackPlugin.options.header %></header>
<main class="main">
<h1>見出し</h1>
</main>
<footer class="footer"></footer>
</div>
</div>
</body>
上記のように使用します。
他にも、フッターや、メニューなど共通するものはテンプレート化しておくと便利です!
まとめ
今回は、webpack で HTML を整えていきました。
Web 制作では、HTML をサブディレクトリで分けたいとか、フレームワークを使うほどでもないけどヘッダーとかテンプレートにしたいとかあると思います。
よっぽどのことがない限りはこの設定で HTML は従分賄えるんじゃないでしょうか。。。!
ぜひ試してみてください。
宣伝
現在弊社ではエンジニアを募集しています!
少しでも興味を持っていただければ、下記リンクをご覧ください!
スピッカートについてや、募集要項がより詳しく記載されています。
参考サイト
Discussion