Files
ClassHelper/docs/serve.mjs
T
LoveChengke ded10118f5 feat(website,docs,build): 首屏改成大标题 + 整行渐变填色,官网与文档站合并发布到 GitHub Pages
官网(`website/`)

- 首屏标题放大一档(`--fs-display` 上限 3.6rem → 4rem),第二行改成**整行渐变填色**,
  照 ClassIsland 官网那种「大标题 + 中间一段渐变 + 一行副标 + 一排徽章 + 两个按钮」的写法;
- 标题下补一排 mono 芯片(版本 / Windows / Linux·Docker / 触摸屏),主按钮换成
  「立即下载」+「GitHub 仓库」;
- 顶部导航与页脚补「文档站」入口;页脚原本指向 GitHub blob 的那三个链接改成指向文档站
  —— 那几个文件已经移到 `docs/management/` 下,原链接是 404。

> ⚠ 渐变那一行**不参与逐字揭示**:`main.js` 的 `setupHeadlineReveal` 会跳过 `.reveal-grad`。
> 拆成 per-char 的 `inline-block` 之后每个字各自建一层合成,祖先的 `background-clip: text`
> 就穿不过去,渐变会整行失效 —— 所以它按整行入场(透明度 + 轻微上浮)。

站点发布(`.github/workflows/pages.yml`,取代 `docs.yml`)

- **一个仓库在 GitHub Pages 上只有一个站点**,所以官网与文档站拼成一份产物:
  官网在根、文档站在 `/docs/` 下,组装逻辑在 `scripts/build-pages.mjs`;
- 站点根 404 由 `website/404.html` 提供(含 `{{BASE}}` 占位符,由脚本与 workflow 按仓库名注入);
- 官网目录里的 `serve.mjs` 与 `tools/` 是开发用的,不发布;
- `website/serve.mjs` 把 `../docs/_site` 挂在 `/docs/` 下,让本地预览与线上同形 ——
  否则页脚那几个「文档站」链接在本地全是 404;
- 文档站模板顶栏补一个「官网」入口(`{{_rel}}../`)。

版本迭代

- `scripts/version.mjs` 补上**官网上手写的三处版本号**(顶栏徽标 / 首屏芯片 / 页脚)。
  官网是纯静态站、没有构建步骤,没有哪段代码会去读 `package.json`,漏改的后果是
  首页一直挂着旧版本号 —— 而那是别人看到的第一眼。落点从 10 处变成 13 处,
  `AGENTS.md` §4.4 与 `docs/dev/release.md` 同步。
2026-10-06 16:44:23 +08:00

70 lines
2.5 KiB
JavaScript
Raw Permalink 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.
/**
* 文档站本地预览用的最小静态服务器(构建产物 docs/_site)。
* 正式发布走 GitHub Pages(.github/workflows/pages.yml:官网在根、文档站在 /docs/),不需要这个文件。
*
* node docs/build.mjs --serve → 构建后直接预览(推荐)
* node docs/serve.mjs → http://127.0.0.1:5181(要求已经构建过)
* PORT=8080 node docs/serve.mjs
*/
import { createServer } from 'node:http';
import { readFile, stat } from 'node:fs/promises';
import { existsSync } from 'node:fs';
import { extname, join, normalize, resolve, sep } from 'node:path';
import { fileURLToPath } from 'node:url';
const ROOT = resolve(fileURLToPath(new URL('_site/', import.meta.url)));
const PORT = Number(process.env.PORT ?? 5181);
const MIME = {
'.html': 'text/html; charset=utf-8',
'.css': 'text/css; charset=utf-8',
'.js': 'text/javascript; charset=utf-8',
'.json': 'application/json; charset=utf-8',
'.svg': 'image/svg+xml',
'.png': 'image/png',
'.jpg': 'image/jpeg',
'.ico': 'image/x-icon',
'.woff': 'font/woff',
'.woff2': 'font/woff2',
'.map': 'application/json',
};
const server = createServer(async (request, response) => {
const url = new URL(request.url ?? '/', 'http://localhost');
const requested = decodeURIComponent(url.pathname);
const target = normalize(join(ROOT, requested === '/' ? 'index.html' : requested));
// 目录穿越防护:解析结果必须仍在 ROOT 里
if (target !== ROOT && !target.startsWith(ROOT + sep)) {
response.writeHead(403).end('Forbidden');
return;
}
try {
const info = await stat(target);
const file = info.isDirectory() ? join(target, 'index.html') : target;
const body = await readFile(file);
response.writeHead(200, {
'content-type': MIME[extname(file)] ?? 'application/octet-stream',
'cache-control': 'no-store',
});
response.end(body);
} catch {
// 与 GitHub Pages 行为对齐:未知路径给站点根的 404.html
const fallback = join(ROOT, '404.html');
if (existsSync(fallback)) {
response.writeHead(404, { 'content-type': MIME['.html'] }).end(await readFile(fallback));
return;
}
response.writeHead(404, { 'content-type': 'text/plain; charset=utf-8' }).end('404');
}
});
server.listen(PORT, '127.0.0.1', () => {
if (!existsSync(ROOT)) {
console.warn('还没有构建产物,先跑 `node docs/build.mjs`');
}
console.log(`文档站预览:http://127.0.0.1:${PORT}`);
});