PowerCMS X / PowerCMS 6を導入するウェブサイトのコーディング環境を11tyとViteで作成してみた

公開

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);