React等を使わずHTML/CSS/JavaScriptで昔ながらのコーディングをした後、CMSのテンプレート化を行うような案件で、イマドキのコーディングを行う環境を作る話です。フロントエンドカンファレンス北海道2024の長谷川さんの講演「小規模サイトでも使えるVite ~HTMLコーディングをよりスマートに~」を拝見して考え始めました。
「Pugを利用したHTML制作とPowerCMS Xテンプレート」に少し纏めていますが、これまではPugを利用してきました。ただ、最近は以下のような問題を感じていました。
- ファイル数が多くなるとなんだか少し重い
- Pugでウェブページのヘッダー・フッター・共通要素等を分離しても、テンプレート化の際にはPugファイルではなくビルドされたHTMLファイルを参照するので効率が悪い
- Pugは慣れると楽だけど、普通にHTMLが書ける方が楽そう(特に初見の人)
そこで、長谷川さんのスライドにあるように11tyとViteを使ってみようと考え環境を構築したところ、ビルドは速いしテンプレート化も効率よく行えそうな環境ができあがりました。
できるだけ新しい11ty v3とVite v5を使いたい
いくつかの記事を拝見すると、Viteで11tyを使用するために「vite-plugin-eleventy」を導入しているようでしたが、これがどうも古いような気がしました。できるだけ新しい11ty v3とVite v5を使うべく公式サイトを見たところ、11ty公式の「eleventy-plugin-vite」(パッケージ名がよく似ているので注意)を導入することでより新しいバージョンが利用できました。
.eleventy.jsの設定がなかなか上手くいかなかったのですが、matthiasott/eleventy-plus-vite等を参考にし、以下のようになりました。eleventy --serve --incremental
で起動してコーディングを行います。
import EleventyVitePlugin from "@11ty/eleventy-plugin-vite";
export default function (eleventyConfig) {
eleventyConfig.addPlugin(EleventyVitePlugin, {
viteOptions: {
publicDir: 'public',
appType: 'mpa',
clearScreen: false,
css: {
preprocessorOptions: {
scss: {
api: 'modern-compiler',
},
},
},
server: {
mode: 'development',
middlewareMode: true,
},
build: {
mode: 'production',
sourcemap: true,
manifest: false,
modulePreload: { polyfill: false },
rollupOptions: {
output: {
assetFileNames: (assetInfo) => {
if (/\.css$/.test(assetInfo.names)) {
return 'assets/css/[name].[hash][extname]';
}
if (assetInfo.originalFileNames && assetInfo.originalFileNames[0]) {
const filePath = assetInfo.originalFileNames[0].replace('../public/', '');
return filePath;
}
return '[name].[hash][extname]';
},
chunkFileNames: 'assets/js/[name].[hash].js',
entryFileNames: 'assets/js/[name].[hash].js',
},
},
cssCodeSplit: false,
},
plugins: [
assetHotReload(),
sassGlobImports(),
],
},
});
eleventyConfig.addGlobalData('permalink', () => {
return (data) => `${data.page.filePathStem}.${data.page.outputFileExtension}`;
});
eleventyConfig.addPassthroughCopy('src/assets/css');
eleventyConfig.addPassthroughCopy('src/assets/js');
eleventyConfig.addPassthroughCopy('public');
return {
templateFormats: ['njk', 'html'],
htmlTemplateEngine: 'njk',
passthroughFileCopy: true,
dir: {
input: 'src',
output: '_site',
includes: '_includes',
layouts: '_layouts',
data: '_data',
},
}
}
package.jsonは以下のようになっています。Reactを使う時Sassは使わないですが、静的HTMLのコーディングではまだ利用しています。vite-plugin-sass-glob-importで@use "project/*.scss";
のようなglob importを利用可能にしています。
{
"name": "skyward-next",
"private": true,
"version": "0.1.0",
"type": "module",
"scripts": {
"start": "eleventy --serve --port=3501 --incremental",
"build": "eleventy"
},
"devDependencies": {
"@11ty/eleventy": "^3.0.0",
"@11ty/eleventy-plugin-vite": "^5.0.0",
"autoprefixer": "^10.4.20",
"postcss": "^8.4.49",
"postcss-inline-svg": "^6.0.0",
"postcss-merge-at-rules": "^1.2.0",
"sass": "^1.79.4",
"vite": "^5.4.8",
"vite-plugin-sass-glob-import": "^5.0.0"
}
}
PostCSS Merge At RulesでCSSの@ルールをまとめる
少し余談ですが、CSSで@media
だけでなく@layer
や@container
もまとめたいと思いPostCSSのプラグインを探したところ、「PostCSS Merge At Rules」が良い感触でした。
ただ、PostCSS Sort Media Queriesのように@ルールがファイルの最後にまとまらないかなと思いnode_modules/postcss-merge-at-rules/index.jsに以下のコードを追加したところ、期待の結果が得られるようになりました。
const atRules = [];
root.walkAtRules(rule => {
if (rule.name === 'layer' && rule.params.indexOf(',') > -1) return;
atRules.push(rule);
rule.remove();
});
root.append(atRules);