🍆

Viteで下層ページのビルドをどうやればいいか分からなかったので力技で解決した

2023/02/10に公開約3,700字

この記事で触れている内容の原因は判然としていません。
vite-plugin-handlebars を使っている影響なのか、何なのかはわかりません。

遭遇した事象は下記の通りです。

  • /public に置いたHTMLファイルでは vite-plugin-handlebars が動いてくれない。
  • JSの自作関数を import したものの、更新してもホットリロードが効かない。
  • Github Workflowでビルドに失敗してしまう。

今思い返すと、defineConfigのrootを適切に変更していないのが原因だったかもしれません。
とはいえ、解決したのでディレクトリ構造と設定ファイルを晒します。

ディレクトリ構造

.
├── pages/
│   ├── acccess/
│   │   └── index.html
│   ├── company/
│   │   └── index.html
│   ├── contact/
│   │   └── index.html
│   ├── service/
│   │   ├── index.html
│   │   ├── hoge.html
│   │   └── fuga.html
│   ├── index.html
│   ├── app.scss
│   └── app.js
├── public/
│   └── images/
│       ├── sample-image-1.jpg
│       ├── sample-image-2.png
│       └── sample-image-3.gif
└── src/
    ├── includes/
    │   ├── components/
    │   │   ├── section-a.html
    │   │   ├── section-b.html
    │   │   └── section-c.html
    │   └── globals/
    │       ├── header.html
    │       ├── footer.html
    │       └── sidebar.html
    ├── js/
    │   ├── ContactForm.js
    │   ├── MenuToggle.js
    │   └── SwipeSwiper.js
    └── scss/
        ├── components/
        │   └── コンポーネント系のSCSS
        ├── libs/
        │   └── 外部から拾ってきたSCSS
        └── _env.scss(...色々ありますが省略)

pages ディレクトリにはHTMLファイルを格納しています。
このディレクトリがビルドの対象となります。
また、app.jsやapp.scssがこのディレクトリに入っているのもポイントです。ここに入っていないとホットリロードが効きません。app.jsやapp.scssはビルド時には assetsディレクトリに入ってくれます。

src/js ディレクトリのファイルをimportしたり、src/scssに入ってるファイルをuseしたりしています。ちゃんと動きます。

vite.config.js

vite.config.js
import { defineConfig } from "vite";
import autoprefixer from "autoprefixer";
import fs from "fs";
import { resolve } from "path";
import handlebars from "vite-plugin-handlebars";
import { findAllFiles } from "./CustomBuildFunctions";

const root = resolve(__dirname, "pages");

export default defineConfig(async () => {
  const rollupOptionsInput = await findAllFiles("./pages", ".html");

  return {
    root: root,
    base: "/",
    server: {
      port: 8080,
      https: {
        key: fs.readFileSync("./localhost-key.pem"),
        cert: fs.readFileSync("./localhost.pem"),
      },
    },
    publicDir: resolve(__dirname, "public"),
    build: {
      outDir: resolve(__dirname, "dist"),
      rollupOptions: {
        input: rollupOptionsInput,
      },
    },
    css: {
      devSourcemap: true,
      postcss: {
        plugins: [autoprefixer({})],
      },
    },
    assetsInclude: [resolve(__dirname, "public")],
    plugins: [
      handlebars({
        partialDirectory: [
          resolve(__dirname, "src/includes/globals"),
          resolve(__dirname, "src/includes/modules"),
          resolve(__dirname, "src/includes/components"),
        ],
      }),
    ],
  };
});

findAllFiles という関数は自作のものです。
ビルド時に rollupOptions にビルド対象のHTMLファイルを書いていく必要があるらしく、手作業では面倒なので自動でリストアップしてくれるような関数を書きました。

下記がその内容です。

npm install randomstring directory-crawler
CustomBuildFunctions.js
import { resolve } from "path";
import randomstring from "randomstring";
import { crawlingDirStream } from "directory-crawler";

const pathResolve = resolve;

const findAllFiles = (dirName, ext) => {
  return new Promise(async (resolve) => {
    const extRegex = new RegExp(ext);
    const results = {};
    for await (const d of crawlingDirStream(Infinity, Infinity, dirName)) {
      if (d.isFile() && d.name.match(extRegex)) {
        const keyIndex = randomstring.generate();
        results[keyIndex] = pathResolve(d.path, "");
      }
    }
    resolve(results);
  });
};

export { findAllFiles };

これで冒頭で挙げた3つとも問題解決されました。
なお、リンクを指定するときは href="/contact/index.html" のように書いています。

Viteって簡単だという噂を聞いていたのですが、細かいところが結構辛かったです。
僕の使い方が正しくないのかもしませんが...笑

この記事とは関係ないですし、超メジャーですが、 rimraf がめちゃくちゃ便利だなーと感じました。ビルド時に dist 消してくれるん助かる。

Discussion

ログインするとコメントできます