Regression / regression (push) Canceled after 0s
## 品牌标识(本次会话) 起因:品牌此前没有任何图形标识 —— 唯一 favicon 是内联 data-URI 里的字母「A」, 那是 v2.0.0「Aurora Admin → Kole UI」改名漏掉的一处(PC 顶栏也是「A」, 移动端站已是「K」;移动端文档站则完全没有 favicon)。 - 几何:24 网格三个互不接触的笔画(竖 + 两斜),圆头描边; 描边 2.25 → 16px 标签页尺寸下正好 1.5px = 规范原文「描边1.5px」 - 取色分两套(刻意):favicon 硬编码品牌蓝/白(渲染在浏览器标签栏,不继承 kole-dark); 顶栏标记走 currentColor(实测暗色下自动转 rgb(20,22,28)) - 新增 theme-color 双条(light #FFFFFF / dark #1C1F26,取 --kole-color-card-bg) - 修 site/app.js hero 标语 KOLE ADMIN → KOLE UI(改名变形残留) - 移动端 7 个模板补 favicon(此前计数 0) 验收:门禁 9 条全 OK(site-routing/site-routes/mobile-docs/mobile-site/isolation/ theme/nav/i18n/icons);PC 回归 1464/1464 · 移动端 807/807,各连跑 8 次一致; 两端 favicon 405 字节逐字节一致;PC 站控制台错误 1→0。 ## 并行会话成果(本次一并入库) - 图标系统:2576 图标(TDesign/Element Plus,MIT)+ 11 端注入 + 5 个构建门禁工具 + IconPreview 预览页 + ICON-SPEC.md 冻结规格 - 移动端平台:47 组件 × 6 端 + 文档站 53 页 + 隔离门禁 - PC 组件:103 个大后台组件 / 组件11 批次 - uni-app:PC 端试点 + 移动端端实现 + 真实编译验证 ## 工程 - .gitignore 补 .scratch/ 与 .zcode-preexisting-*.txt(会话中间产物,实测 9.1MB,不入库) - CHANGELOG 补品牌标识条目 - ROADMAP 登 S8-P4(品牌标识任务包 + og:image/apple-touch-icon 未做部分)
151 lines
8.1 KiB
JavaScript
151 lines
8.1 KiB
JavaScript
#!/usr/bin/env node
|
||
/**
|
||
* snapshot-site.mjs — 把当前构建归档成一个可切换的历史版本文档站。
|
||
*
|
||
* 产物布局(站点根必须继续叫 site:SITE_BASE 取 pathname 里第一段 '/site/',
|
||
* 改名即全站 CSS/data.js 404,见 site/app.js 顶部注释):
|
||
*
|
||
* /site/ ← 最新版(根站点,永远指当前构建)
|
||
* /1.4.1/site/ ← 归档快照(磁盘上就是仓库根的 1.4.1/)
|
||
* /1.4.1/frameworks/ /1.4.1/.design_library/ ← 该版本的演示页与令牌依赖
|
||
* /1.4.1/index.html /1.4.1/sitemap.xml
|
||
*
|
||
* 站点根是按 URL 反推的,所以 /1.4.1/site/... 下相对路径(../.design_library、sources/…)
|
||
* 全部原样成立,快照内不需要改任何路径。切换入口见 site/app.js 的 loadVersionManifest,
|
||
* 清单由 tools/precompute.mjs 生成(只有磁盘上真存在快照的版本才会入清单)。
|
||
*
|
||
* 用法:
|
||
* npm run snapshot:site -- 1.4.1 # 需要构建产物已就绪
|
||
* npm run snapshot:site -- 1.4.1 --build # 先跑 build-site.ps1 + precompute 再归档
|
||
*
|
||
* 注意:归档的是**当前工作区**的构建。仓库里没有历史源码快照、也没有 git tag,
|
||
* 所以旧版本无法凭空重建 —— 每次发版后归档一次,才有可切换的历史版本。
|
||
*/
|
||
import { cpSync, existsSync, mkdirSync, readdirSync, rmSync, readFileSync, writeFileSync, statSync } from 'node:fs';
|
||
import { execFileSync } from 'node:child_process';
|
||
import { fileURLToPath } from 'node:url';
|
||
import { dirname, join, basename } from 'node:path';
|
||
|
||
const ROOT = dirname(dirname(fileURLToPath(import.meta.url)));
|
||
const SITE_DIR = join(ROOT, 'site');
|
||
|
||
const argv = process.argv.slice(2);
|
||
const flags = new Set(argv.filter((a) => a.startsWith('--')));
|
||
const version = argv.find((a) => !a.startsWith('--'));
|
||
|
||
const fail = (msg) => { console.error('[snapshot] FAIL: ' + msg); process.exit(1); };
|
||
const ok = (msg) => console.log('[snapshot] OK: ' + msg);
|
||
|
||
if (!version) fail('缺少版本号。用法:npm run snapshot:site -- <x.y.z> [--build]');
|
||
if (!/^\d+\.\d+\.\d+$/.test(version)) fail(`版本号必须是 x.y.z(收到 ${version})`);
|
||
|
||
/* 版本号必须与 CHANGELOG / 构建版本对得上,否则清单里会出现对不上的条目 */
|
||
const pkg = JSON.parse(readFileSync(join(ROOT, 'package.json'), 'utf8'));
|
||
const changelog = existsSync(join(ROOT, 'CHANGELOG.md')) ? readFileSync(join(ROOT, 'CHANGELOG.md'), 'utf8') : '';
|
||
const inChangelog = new RegExp('^## \\[' + version.replace(/\./g, '\\.') + '\\]', 'm').test(changelog);
|
||
if (!inChangelog) fail(`CHANGELOG.md 里没有 [${version}] 段 —— 先写变更条目(tools/release.mjs --bump 可提升版本)`);
|
||
if (pkg.version !== version && !flags.has('--force-version')) {
|
||
fail(`package.json 是 ${pkg.version},与归档版本 ${version} 不一致`);
|
||
}
|
||
|
||
if (flags.has('--build')) {
|
||
console.log('[snapshot] 构建站点(build-site.ps1 + precompute)…');
|
||
if (process.platform !== 'win32') fail('--build 只能在 Windows 上跑:build-site.ps1 依赖 PowerShell 5.1');
|
||
execFileSync('powershell', ['-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', 'build-site.ps1'], { cwd: ROOT, stdio: 'inherit' });
|
||
execFileSync(process.execPath, [join(ROOT, 'tools', 'precompute.mjs')], { cwd: ROOT, stdio: 'inherit' });
|
||
}
|
||
|
||
for (const f of ['index.html', 'app.js', 'data.js', 'data.json', 'style.css']) {
|
||
if (!existsSync(join(SITE_DIR, f))) fail(`缺少构建产物 site/${f} —— 先运行 npm run build:site`);
|
||
}
|
||
const data = JSON.parse(readFileSync(join(SITE_DIR, 'data.json'), 'utf8'));
|
||
const built = String((data.meta && data.meta.version) || '');
|
||
/* 正常情况下归档的就是本次构建的版本。--force-version 只用于补档/演练:
|
||
历史版本的源码不在仓库里(没有 git tag、没有旧快照),拿当前构建冒充旧版
|
||
只适合验证机制,不适合当正式历史版本发布。 */
|
||
if (built !== version && !flags.has('--force-version')) {
|
||
fail(`构建产物版本是 ${built || '未知'},与归档版本 ${version} 不一致 —— 先 npm run build:site(或加 --build)`);
|
||
}
|
||
if (built !== version) {
|
||
console.warn(`[snapshot] 警告:构建产物是 ${built},却按 ${version} 归档(--force-version)。`);
|
||
console.warn('[snapshot] 该快照内容是当前构建,仅用于验证机制,不要当作正式历史版本发布。');
|
||
}
|
||
|
||
/* 快照落在**仓库根**:URL 是 /<x.y.z>/site/…,服务器把 / 映射到仓库根(dev-server 的
|
||
ROOT、nginx 的 root),所以磁盘上必须是 <root>/<x.y.z>/site/。
|
||
放进 site/ 里会变成 /site/<x.y.z>/… —— 版本菜单点进去就是 404。 */
|
||
const dest = join(ROOT, version);
|
||
/* 归档 site/ 时排除三类:自身、其它版本目录(否则会把上次快照套进这次),
|
||
以及 versions.json —— 版本清单必须只留在站点根:快照自带的那份是归档当时的快照,
|
||
之后新归档的版本不会进去,实测会让快照页误判成单版本、角标不可点(回不到最新版)。 */
|
||
const skipSelf = (src) => {
|
||
const rel = src.slice(SITE_DIR.length + 1).replace(/\\/g, '/');
|
||
return rel === version
|
||
|| rel === 'versions.json'
|
||
|| /^\d+\.\d+\.\d+(?:\/|$)/.test(rel);
|
||
};
|
||
|
||
if (existsSync(dest)) {
|
||
if (!flags.has('--force')) {
|
||
fail(`${basename(dest)}/ 已存在。确认要覆盖就加 --force(会先删除该目录重建)`);
|
||
}
|
||
rmSync(dest, { recursive: true, force: true });
|
||
console.log(`[snapshot] 已删除旧快照 ${version}/`);
|
||
}
|
||
|
||
mkdirSync(dest, { recursive: true });
|
||
/* cpSync 拒绝把目录拷进自己的子目录(Node ≥16.7 的 ERR_FS_CP_EINVAL),
|
||
且 site/ 与 dest 是兄弟目录、跨目录搬移可能跨盘 —— 先落到暂存再搬进 dest。 */
|
||
const stage = join(ROOT, 'dist-deploy', `.snapshot-stage-${version}`);
|
||
rmSync(stage, { recursive: true, force: true });
|
||
mkdirSync(stage, { recursive: true });
|
||
|
||
try {
|
||
cpSync(SITE_DIR, join(stage, 'site'), { recursive: true, filter: (src) => !skipSelf(src) });
|
||
cpSync(join(ROOT, 'frameworks'), join(stage, 'frameworks'), { recursive: true });
|
||
cpSync(join(ROOT, '.design_library'), join(stage, '.design_library'), {
|
||
recursive: true,
|
||
/* 规范原文与 agent 报告不进快照:站点不读它们,且是仓库内部资料(部署包同样排除) */
|
||
filter: (src) => !/(?:^|[\\/])(specs|agent-reports|preview|ui_kits)(?:[\\/]|$)/.test(src)
|
||
});
|
||
cpSync(join(ROOT, 'index.html'), join(stage, 'index.html'));
|
||
if (existsSync(join(ROOT, 'sitemap.xml'))) cpSync(join(ROOT, 'sitemap.xml'), join(stage, 'sitemap.xml'));
|
||
|
||
for (const entry of readdirSync(stage)) {
|
||
cpSync(join(stage, entry), join(dest, entry), { recursive: true });
|
||
}
|
||
} finally {
|
||
rmSync(stage, { recursive: true, force: true });
|
||
}
|
||
|
||
/* 归档标记:给后续版本核对「这份快照到底是哪个版本、什么时候归档的」 */
|
||
const now = new Date();
|
||
const localDay = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')}`;
|
||
writeFileSync(
|
||
join(dest, 'VERSION.json'),
|
||
JSON.stringify({
|
||
version,
|
||
archivedAt: localDay,
|
||
source: 'tools/snapshot-site.mjs',
|
||
note: 'archive of the working-tree build at the time of release; paths inside are unmodified'
|
||
}, null, 2) + '\n'
|
||
);
|
||
|
||
const size = (p) => {
|
||
let total = 0;
|
||
for (const e of readdirSync(p, { withFileTypes: true })) {
|
||
const f = join(p, e.name);
|
||
total += e.isDirectory() ? size(f) : statSync(f).size;
|
||
}
|
||
return total;
|
||
};
|
||
const mb = (size(dest) / 1024 / 1024).toFixed(1);
|
||
ok(`已归档 v${version} → ${version}/(${mb} MB,URL /${version}/site/)`);
|
||
|
||
/* 清单必须跟着更新,否则版本菜单里看不到刚归档的版本 */
|
||
execFileSync(process.execPath, [join(ROOT, 'tools', 'precompute.mjs')], { cwd: ROOT, stdio: 'inherit' });
|
||
const manifest = JSON.parse(readFileSync(join(SITE_DIR, 'versions.json'), 'utf8'));
|
||
ok(`site/versions.json 现有 ${manifest.versions.length} 个在线版本:${manifest.versions.map((v) => 'v' + v.version).join(' / ')}`);
|
||
console.log('[snapshot] 下一步:node site/dev-server.js 后打开 http://127.0.0.1:3311/site/ 实测切换;');
|
||
console.log('[snapshot] 部署走 tools/pack-deploy.mjs(site/ 目录整体打包,快照随包上线)。');
|