feat: make mode creation preview-only and cache-safe

This commit is contained in:
Miayui
2026-09-20 19:32:03 +08:00
parent bfff1b515c
commit 89707a42e2
28 changed files with 1375 additions and 165 deletions
+79 -2
View File
@@ -1,5 +1,13 @@
import { cpSync, copyFileSync, existsSync, mkdirSync } from "node:fs";
import { dirname, resolve } from "node:path";
import { createHash } from "node:crypto";
import {
cpSync,
copyFileSync,
existsSync,
mkdirSync,
readFileSync,
writeFileSync,
} from "node:fs";
import { basename, dirname, extname, resolve } from "node:path";
import { fileURLToPath } from "node:url";
import vue from "@vitejs/plugin-vue";
@@ -45,6 +53,74 @@ const runtimeFiles = [
"codepen-glass-theme.css",
"vue-ui.js"
];
const fingerprintedRuntimeFiles = runtimeFiles.filter((file) => (
/\.(?:css|js)$/.test(file)
&& !["service-worker.js", "speech-audio-worklet.js"].includes(file)
));
const rewrittenHtmlFiles = [
"index.html",
"login.html",
"hardware-control.html",
"firmware-workbench.html",
];
function contentHash(value) {
return createHash("sha256").update(value).digest("hex").slice(0, 12);
}
function hashedRuntimeName(file, hash) {
const extension = extname(file);
return `${basename(file, extension)}.${hash}${extension}`;
}
function rewriteRuntimeReferences(value, manifest) {
let rewritten = value;
for (const [source, target] of Object.entries(manifest)) {
const escaped = source.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
rewritten = rewritten.replace(
new RegExp(`/${escaped}(?:\\?[^\\s\"'<>)]*)?`, "g"),
`/${target}`,
);
}
return rewritten;
}
function fingerprintRuntimeAssets() {
const manifest = {};
for (const file of fingerprintedRuntimeFiles) {
const source = resolve(outputRoot, file);
if (!existsSync(source)) continue;
const contents = readFileSync(source);
const hashedName = hashedRuntimeName(file, contentHash(contents));
writeFileSync(resolve(outputRoot, hashedName), contents);
manifest[file] = hashedName;
}
for (const file of rewrittenHtmlFiles) {
const target = resolve(outputRoot, file);
if (!existsSync(target)) continue;
const source = readFileSync(target, "utf8");
writeFileSync(target, rewriteRuntimeReferences(source, manifest), "utf8");
}
const serviceWorkerPath = resolve(outputRoot, "service-worker.js");
const buildHash = contentHash(JSON.stringify(manifest));
if (existsSync(serviceWorkerPath)) {
const serviceWorker = rewriteRuntimeReferences(
readFileSync(serviceWorkerPath, "utf8"),
manifest,
).replace(
/const CACHE_VERSION = "[^"]+";/,
`const CACHE_VERSION = "cognitive-agent-pad-build-${buildHash}";`,
);
writeFileSync(serviceWorkerPath, serviceWorker, "utf8");
}
writeFileSync(
resolve(outputRoot, "runtime-assets.json"),
`${JSON.stringify({ build_hash: buildHash, assets: manifest }, null, 2)}\n`,
"utf8",
);
}
function copyRuntimeAssets() {
return {
@@ -64,6 +140,7 @@ function copyRuntimeAssets() {
mkdirSync(dirname(target), { recursive: true });
copyFileSync(source, target);
}
fingerprintRuntimeAssets();
}
};
}