From 6c612911b3f7e70f62973c1dd57ea4b3e739dec6 Mon Sep 17 00:00:00 2001 From: nxxy335 Date: Tue, 10 Nov 2026 11:12:25 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E5=8D=87=E7=BA=A7?= =?UTF-8?q?=E5=90=8E=E9=A6=96=E9=A1=B5=20404=EF=BC=88=E7=A9=BA=E5=A3=B3?= =?UTF-8?q?=E5=AE=89=E8=A3=85=E5=8C=85=E7=BC=BA=E5=B0=91=20templates?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 重新构建并产出含 21 个模板的完整安装包 v1.2.4 - package.mjs 增加模板/资源目录/版本号前置校验,禁止产出空壳包 - 新增 pnpm release 一键发版;修正 README、开发指南与 FAQ 的构建打包说明 --- README.md | 14 +++++++--- docs/customize/development.md | 49 ++++++++++++++++------------------- docs/faq.md | 18 +++++++++++++ package.json | 1 + scripts/package.mjs | 42 +++++++++++++++++++++++++++++- 5 files changed, 92 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 10e0472..b990d3d 100644 --- a/README.md +++ b/README.md @@ -97,6 +97,9 @@ 2. 进入 Halo 后台 → 主题管理 → 安装主题 → 上传 ZIP 包 3. 安装完成后点击「启用」 +> **升级后首页 404「资源不存在 / Template index was not found」**:说明上传的 ZIP 里没有 `templates/` +> 模板文件(从源码仓库打包时漏了构建步骤)。请换用完整安装包重新上传,详见 [FAQ 安装相关](docs/faq.md)。 +> > **升级后如果整站没了样式**:Halo 页面缓存或前置反向代理里可能还留着上一版本的 HTML, > 它引用的 CSS 文件名带内容哈希,升级后已被删除,请求会直接 500。 > 先在 Halo 后台执行一次「清理缓存」(并刷新 CDN / Nginx 缓存)即可。 @@ -112,10 +115,11 @@ git clone https://git.nxxy335.top/nxxy335/halo-theme-WarmIsland.git cd halo-theme-WarmIsland pnpm install -pnpm build +pnpm release # build → snapshot → package ``` -构建产物在 `templates/` 目录下,同时会生成 `dist/` 内的安装包。 +`pnpm build` 只生成 `templates/`(模板 + 静态资源),不会产出 ZIP; +安装包由 `pnpm package` 生成到 `dist/warm-island-.zip`。 ## 开发 @@ -139,7 +143,9 @@ pnpm package pnpm smoke ``` -发版流程:`pnpm build` → `pnpm snapshot` → `pnpm package`,并把 `compat/assets` 的新增文件一起提交。 +发版流程:`pnpm release`(等价于 `pnpm build` → `pnpm snapshot` → `pnpm package`), +并把 `compat/assets` 的新增文件一起提交。`pnpm package` 会校验模板、资源目录与版本号一致性, +产物缺失时直接报错,避免打出不含 `templates/` 的空壳安装包。 ### 目录结构 @@ -172,7 +178,7 @@ pnpm smoke ## 技术栈 - [Halo](https://halo.run) 2.26+ -- [Astro](https://astro.build) + [vite-plugin-halo-theme](https://github.com/halo-sigs/vite-plugin-halo-theme) +- [Astro](https://astro.build) 6(构建输出 Thymeleaf 模板) - [Thymeleaf](https://www.thymeleaf.org) 模板引擎 - [Sass](https://sass-lang.com/) 样式 diff --git a/docs/customize/development.md b/docs/customize/development.md index dd36f26..ff1f6b4 100644 --- a/docs/customize/development.md +++ b/docs/customize/development.md @@ -6,8 +6,8 @@ | 工具 | 最低版本 | 推荐版本 | |------|----------|----------| -| Node.js | 18.x | 20.x LTS | -| pnpm | 8.x | 9.x | +| Node.js | 22.12.x | 22.x LTS | +| pnpm | 12.x | 12.x | | Git | 2.x | 最新 | ### 安装 pnpm @@ -19,8 +19,8 @@ npm install -g pnpm ### 验证环境 ```bash -node -v # v20.x.x -pnpm -v # 9.x.x +node -v # v22.x.x(需 >= 22.12.0) +pnpm -v # 12.x.x git --version # git version 2.x.x ``` @@ -34,25 +34,10 @@ pnpm install ## 开发模式 -### 启动开发服务器 - -```bash -pnpm dev -``` - -启动后,Astro 开发服务器会在 `http://localhost:4321` 运行,支持热更新。 - -### 使用 Halo DevTools - -WarmIsland 使用 `vite-plugin-halo-theme` 插件,可以与 Halo 实例联动开发: - -1. 确保本地 Halo 实例正在运行 -2. 在 Halo 后台安装主题的开发版本 -3. 修改源码后,主题会自动重新构建并推送到 Halo - -```bash -pnpm dev:halo -``` +`pnpm dev` 用 nodemon 监听 `src/`、`public/`、`settings.yaml` 等文件的变化, +每次变化自动执行一次 `astro build`,把结果写入 `templates/`。 +本项目是「静态模板产物 + Halo 运行时渲染」模式,没有 Astro 开发服务器, +也不依赖 `vite-plugin-halo-theme`;本地预览请直接用 Halo 实例加载 `templates/`。 ## 构建 @@ -62,15 +47,24 @@ pnpm dev:halo pnpm build ``` -构建产物位于 `dist/` 目录,包含所有模板文件和静态资源。 +构建产物位于 **`templates/`**(21 个 `.html` 模板 + `assets/` 静态资源), +并由 `scripts/postbuild.mjs` 合并 `compat/assets` 中的历史哈希资源、校验资源引用。 +注意:`pnpm build` **不会**生成 ZIP 安装包。 ### 打包主题 ```bash -pnpm package +pnpm release # 推荐:build → snapshot → package +# 或分步:pnpm build && pnpm snapshot && pnpm package ``` -生成 `.zip` 主题包,可直接在 Halo 后台上传安装。 +生成 `dist/warm-island-.zip`,可直接在 Halo 后台上传安装。 +ZIP 根目录直接放 `theme.yaml` / `settings.yaml` / `templates/`,不要额外套一层目录。 + +> **`templates/` 被 `.gitignore` 忽略**,克隆仓库后默认不存在。若跳过 `pnpm build` +> 直接 `pnpm package`,过去会产出不含任何模板的空壳包,上传后 Halo 报 +> `Template index was not found.` 并让首页 404。现在打包脚本会先校验 +> `index.html` 等模板、资源目录与版本号,不满足即报错退出。 ## 项目结构 @@ -163,7 +157,8 @@ WarmIsland 使用 Astro 编写组件,构建后输出为 Thymeleaf 模板供 Ha ### Astro 组件 → Thymeleaf 模板 -Astro 组件中的前端代码会被 `vite-plugin-halo-theme` 转换为 Thymeleaf 模板: +Astro 组件里直接书写 Thymeleaf 属性(`th:*`),构建时原样保留并输出成 `.html` 模板, +由 Halo 在运行时渲染: ```astro --- diff --git a/docs/faq.md b/docs/faq.md index 998d972..fefe308 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -2,6 +2,24 @@ ## 安装相关 +### 升级主题后首页 404「资源不存在 / Template index was not found」? + +这是**安装包里没有模板文件**,不是主题代码或 Halo 版本问题。Halo 升级主题会用新包覆盖原主题目录, +ZIP 里缺少 `templates/index.html` 时,渲染首页找不到 `index` 模板,直接返回 404。 + +**如何确认**:解压待上传的 ZIP,根目录应有 `theme.yaml`、`settings.yaml` 和 `templates/` 目录, +其中有 `index.html`、`post.html` 等 20+ 个 `.html`。若只有几个 `.yaml`,就是「空壳包」—— +`templates/` 被 `.gitignore` 忽略,从源码仓库打包前没执行 `pnpm build` 就会这样。 + +**处理**: + +1. 用完整安装包(Release 里的 ZIP)在 Halo 后台 → 主题管理 → 重新上传升级 +2. 或本地执行 `pnpm release`(build → snapshot → package)重新生成 `dist/warm-island-.zip` +3. 升级完成后清理一次 Halo 页面缓存 / CDN 缓存 + +当前版本的 `pnpm package` 会校验 `templates/index.html`、模板数量、资源目录与版本号一致性, +构建产物缺失或不完整时直接报错退出,不会再产出空壳包。 + ### 主题安装后页面空白? 检查以下几点: diff --git a/package.json b/package.json index 2453369..951cca3 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "build": "astro build && node scripts/postbuild.mjs", "snapshot": "node scripts/snapshot-assets.mjs", "package": "node scripts/package.mjs", + "release": "pnpm run build && pnpm run snapshot && pnpm run package", "smoke": "node scripts/smoke-clickfx.mjs", "astro": "astro", "format": "prettier --write ." diff --git a/scripts/package.mjs b/scripts/package.mjs index 6e5cf0d..6a679d4 100644 --- a/scripts/package.mjs +++ b/scripts/package.mjs @@ -137,6 +137,33 @@ const INCLUDE_ROOT = [ const INCLUDE_DIRS = ["templates"]; const EXCLUDE_DIRS = new Set([".git", "node_modules", "src", "dist", "compat", ".astro"]); +/* ---------------- 构建产物前置校验 ---------------- + * templates/ 被 .gitignore 忽略,克隆仓库或清理工作区后默认不存在。 + * 旧逻辑里 walk() 对不存在的目录只是静默跳过,于是会打出只含 + * theme.yaml / settings.yaml 的"空壳包";上传到 Halo 后旧主题被覆盖, + * 找不到 index 模板,首页直接 404「Template index was not found.」。 + * 这里 fail fast,禁止产出这种包。 + */ +function fail(message) { + console.error(`[package] ${message}`); + console.error("[package] 请先执行 pnpm build(或直接 pnpm release)生成完整模板产物后再打包。"); + process.exit(1); +} + +const templatesDir = path.join(root, "templates"); +if (!fs.existsSync(templatesDir)) fail("未找到 templates/ 目录"); + +const htmlTemplates = fs.readdirSync(templatesDir).filter((name) => name.endsWith(".html")); +for (const required of ["index.html", "post.html", "page.html", "archives.html"]) { + if (!htmlTemplates.includes(required)) fail(`缺少必需模板 templates/${required}`); +} +if (htmlTemplates.length < 10) { + fail(`模板数量异常(仅 ${htmlTemplates.length} 个 .html),疑似构建不完整`); +} +if (!fs.existsSync(path.join(templatesDir, "assets"))) { + fail("未找到 templates/assets/ 静态资源目录"); +} + const entries = []; for (const name of INCLUDE_ROOT) { @@ -164,9 +191,22 @@ for (const dir of INCLUDE_DIRS) { if (fs.existsSync(full)) walk(full, dir); } +if (!entries.some((entry) => entry.name === "templates/index.html")) { + fail("打包清单中缺少 templates/index.html"); +} + const version = readThemeVersion(); +const pkgVersion = JSON.parse(fs.readFileSync(path.join(root, "package.json"), "utf8")).version; +if (pkgVersion !== version) { + fail(`版本号不一致:package.json=${pkgVersion},theme.yaml=${version}`); +} + const outFile = path.join(root, "dist", `warm-island-${version}.zip`); buildZip(entries, outFile); +const assetCount = entries.filter((entry) => entry.name.startsWith("templates/assets/")).length; const sizeMB = (fs.statSync(outFile).size / 1024 / 1024).toFixed(2); -console.log(`[package] dist/warm-island-${version}.zip(${entries.length} 个文件,${sizeMB}MB)`); +console.log( + `[package] dist/warm-island-${version}.zip(${entries.length} 个文件:` + + `${htmlTemplates.length} 个模板 / ${assetCount} 个资源,${sizeMB}MB)` +);