🍎

Viteビルド時にファイル名を固定しつつ、キャッシュを防ぐ

に公開

Viteで普通にhtmlをビルドすると、assets/index-m32sqbn.js のように、アセットのファイル名にハッシュが付与されます。
通常はこれで問題ありませんが、ファイル名を固定したいケースもあります。

vite.config.tsの設定

まず、次のように設定します。

export default defineConfig({
    build: {
        rollupOptions: {
            output: {
                entryFileNames: `assets/[name].js`,
                chunkFileNames: `assets/[name].js`,
                assetFileNames: `assets/[name].[ext]`,
            }
        }
    },
})

これで出力ファイル名は固定されます。
しかし、jsやcssファイルのURLが変わらないため、キャッシュが邪魔をして更新したファイルが読み込まれない問題があります。
この問題を防ぐには、src="index.js?abcde" のように、URLにクエリパラメータを付与する方法があります。

プラグインを定義

ビルドのたびにhtmlを手で書き換えるのは面倒なので、プラグインを作って対処します。
やっつけなので、好きなようにカスタマイズしてください。

plugin/hash.ts
const getNow = () => {
    const now = new Date()
    return `${now.getFullYear().toString().padStart(4, "0")}${(now.getMonth() + 1).toString().padStart(2, "0")}${now.getDate().toString().padStart(2, "0")}`
}

export const hashPlugin = function (opt?: { type?: "date" | "random" }) {

    const { type } = opt || { type: "date" }
    let hash: string
    if (type === "random") {
        hash = Math.random().toString(36).slice(2, 9)
    } else if (type === "date") {
        hash = getNow()
    } else {
        hash = getNow()
    }

    return {
        name: "script-hash",
        transformIndexHtml: {
            hook: "post",
            handler: function (html, ctx) {
                //devモードであれば、何もしない
                if (ctx.server) {
                    return html
                }
                return html
                    .replace(/<script(.*?)src="(.*?)">/g, `<script$1src="$2?${hash}">`,)
                    .replace(/<link rel="stylesheet"(.*?)href="(.*?)">/g, `<link rel="stylesheet"$1href="$2?${hash}">`,)
            },
        }
    };
};

vite.config.tsに追加します。

+ import { hashPlugin } from "./plugin/hash"

  export default defineConfig({
+      plugins: [hashPlugin()],

これで目的が達成できました。

claudeに聞いたらほぼ同じ内容を出力してくれましたが、意外と情報が見つからなかったのでまとめました。

Discussion