Files
halo-theme-WarmIsland/scripts/postbuild.mjs
T
nxxy335 125d0592c9 fix: 修复升级后整站无样式与点击特效失效
- 旧哈希静态资源随版本升级被删除,被缓存的 HTML 仍请求旧文件名导致
  FileNotFoundException 500,补 compat/assets 历史资源并在构建时合并
- postbuild 增加静态资源引用校验,缺失即构建失败
- ClickEffect 改为常驻配置节点 + data 属性驱动,避免配置未落库时静默失效;
  强制回流修正 transition 不触发;特效层挂到 body 下避免被导航栏遮挡
- 新增 scripts: postbuild/snapshot-assets/package/smoke-clickfx
- 版本 1.2.1
2026-09-27 16:27:51 +08:00

81 lines
2.8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 构建后置处理:
* 1. 复制 logo.png 到 assets(保留历史行为)
* 2. 合并 compat/assets 下的历史版本静态资源,避免站点/代理缓存中的旧 HTML
* 仍然引用上一版本的哈希文件名时出现 500(FileNotFoundException)
* 3. 校验所有 templates/*.html 引用的静态资源真实存在,缺失即构建失败
*/
import fs from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
const assetsDir = path.join(root, "templates", "assets");
const compatDir = path.join(root, "compat", "assets");
const templatesDir = path.join(root, "templates");
fs.mkdirSync(assetsDir, { recursive: true });
// 1. logo
const logoSrc = path.join(templatesDir, "logo.png");
if (fs.existsSync(logoSrc)) {
fs.copyFileSync(logoSrc, path.join(assetsDir, "logo.png"));
}
// 2. 历史资源合并(已存在的同名文件以当前构建为准,不覆盖)
if (fs.existsSync(compatDir)) {
let copied = 0;
let skipped = 0;
for (const entry of fs.readdirSync(compatDir, { withFileTypes: true })) {
if (!entry.isFile()) continue;
const src = path.join(compatDir, entry.name);
const dst = path.join(assetsDir, entry.name);
if (fs.existsSync(dst)) {
skipped++;
continue;
}
fs.copyFileSync(src, dst);
copied++;
}
console.log(`[compat] 历史静态资源:复制 ${copied} 个,当前构建已覆盖 ${skipped} 个`);
}
// 3. 资源引用校验
const missing = [];
const checked = new Set();
/** 主题静态资源前缀,必须与 astro.config.mjs 的 base 保持一致 */
const prefixes = ["/themes/warm-island/assets/"];
/** Thymeleaf 的 @{...} 链接表达式同样需要校验 */
const REFERENCE_RE =
/(?:href|src)=["']([^"']*?\/(?:themes\/[^/]+)\/assets\/[^"']+?)["']/g;
for (const file of fs.readdirSync(templatesDir)) {
if (!file.endsWith(".html")) continue;
const html = fs.readFileSync(path.join(templatesDir, file), "utf8");
REFERENCE_RE.lastIndex = 0;
let match;
while ((match = REFERENCE_RE.exec(html)) !== null) {
let ref = match[1];
if (ref.includes("@{")) continue; // 由 Halo 运行时解析,跳过
for (const prefix of prefixes) {
if (!ref.startsWith(prefix)) continue;
const rel = ref.slice(prefix.length).split("#")[0].split("?")[0];
const key = `${file}:${rel}`;
if (checked.has(key)) continue;
checked.add(key);
if (!fs.existsSync(path.join(assetsDir, rel))) {
missing.push(`${file} -> ${ref}`);
}
}
}
}
if (missing.length > 0) {
console.error(`[verify] 发现 ${missing.length} 处静态资源缺失:`);
for (const item of missing) console.error(` - ${item}`);
process.exit(1);
}
console.log(`[verify] 静态资源引用校验通过(${checked.size} 条引用)`);