Files
halo-theme-WarmIsland/scripts/postbuild.mjs
T
nxxy335 dda86294b0 fix: 按 Halo 应用市场审核意见整改外部资源与隐私(v1.2.5 修订)
- 默认零第三方自动请求:移除 21 个模板的 preconnect/dns-prefetch、PrismJS+autoloader、qrcode-generator 及内置一言/IP 定位 API
- 一言与代码高亮配色改为自托管;欢迎弹窗自定义 IP 接口改为 opt-in;微信分享改为复制链接;LightGallery 按 GPLv3 使用
- README 新增「外部资源与隐私」「验证与回归测试」章节,修正无效链接并补充字体 OFL 来源;同步 docs 与修正虚构的目录树
- friends 等 12 处 #strings.substring 加空值保护;logo 由两份 1.5MB 压缩去重为单份 146KB
- 新增 pnpm audit:external 与打包前置合规审计;制品补齐 34 个 docs 文档与预览图
2026-11-11 14:37:09 +08:00

83 lines
3.2 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 存在且只保留一份(public/assets/logo.png → templates/assets/logo.png)
* 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:旧实现把 templates/logo.png 再复制一份到 assets,安装包里会有两份 1.5MB 大图。
// 现在源文件统一放在 public/assets/logo.png(256x256 压缩版),这里只做存在性校验。
if (!fs.existsSync(path.join(assetsDir, "logo.png"))) {
console.error("[postbuild] 未找到 templates/assets/logo.png(public/assets/logo.png 应随构建复制)");
process.exit(1);
}
console.log("[postbuild] logo.png 已去重,仅保留 templates/assets/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} 条引用)`);