agent-Specialization/website-design/tools/serve.cjs
JOJO 2f0b970060 chore(website-demo): 新增 mock 构建/校验/本地预览工具脚本
- build-mocks.cjs:从真实对话导出演示 mock 数据
- check-mocks.cjs:mock 数据完整性校验
- rebuild-cat-html.cjs / serve.cjs:分类页重建与本地预览服务
2026-09-03 21:54:58 +08:00

34 lines
1.6 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.

#!/usr/bin/env node
/* 极简静态文件服务器(官网预览用,替代沙箱内不可用的 python3 -m http.server */
const http = require('http');
const fs = require('fs');
const path = require('path');
const ROOT = path.join(__dirname, '..', 'exp');
const PORT = Number(process.argv[2]) || 8898;
const MIME = {
html: 'text/html; charset=utf-8', js: 'text/javascript', mjs: 'text/javascript',
css: 'text/css', json: 'application/json; charset=utf-8', png: 'image/png',
jpg: 'image/jpeg', jpeg: 'image/jpeg', gif: 'image/gif', svg: 'image/svg+xml',
webp: 'image/webp', woff: 'font/woff', woff2: 'font/woff2', ttf: 'font/ttf',
pdf: 'application/pdf', docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
txt: 'text/plain; charset=utf-8', md: 'text/plain; charset=utf-8', ico: 'image/x-icon',
mp4: 'video/mp4', webm: 'video/webm',
};
http.createServer((req, res) => {
try {
let p = decodeURIComponent(new URL(req.url, 'http://x').pathname);
if (p.endsWith('/')) p += 'index.html';
const file = path.normalize(path.join(ROOT, p));
if (!file.startsWith(ROOT)) { res.writeHead(403); return res.end(); }
fs.readFile(file, (err, data) => {
if (err) { res.writeHead(404); return res.end('not found'); }
const ext = path.extname(file).slice(1).toLowerCase();
res.writeHead(200, { 'Content-Type': MIME[ext] || 'application/octet-stream' });
res.end(data);
});
} catch (e) { res.writeHead(500); res.end(String(e)); }
}).listen(PORT, '127.0.0.1', () => console.log(`preview: http://127.0.0.1:${PORT}/ (root: ${ROOT})`));