#!/usr/bin/env node /** * build-tokens.mjs — 设计令牌同源生成器 * * 唯一真相来源是仓库根的 `design/colors_and_type.css`(铁律 1:颜色只用语义 token)。 * 本脚本把它原样读入,仅做一处「必须的」改写后写入 `src/styles/tokens.gen.css`: * * 删除其中加载 Google Fonts 的 `@import url('https://fonts.googleapis.com/...')` 一行。 * * 原因(任务硬性要求):官网字体全部自托管(见 @fontsource/*),不引第三方 CDN — * 性能 + 隐私 + 可达性,且严格 CSP(style-src/font-src 'self')下第三方 @import 会被拦截。 * * token 的「数值」一字未改 —— 只移除这一行第三方资源引用,因此仍是单一来源、可随时再生。 * * 容灾:若源文件不存在(例如只拷贝了 web/website/ 子目录到干净环境), * 则保留已提交的 tokens.gen.css,构建照常进行。 */ import { readFileSync, writeFileSync, existsSync } from 'node:fs'; import { fileURLToPath } from 'node:url'; import { dirname, resolve } from 'node:path'; const __dirname = dirname(fileURLToPath(import.meta.url)); const SRC = resolve(__dirname, '../../../design/colors_and_type.css'); const OUT = resolve(__dirname, '../src/styles/tokens.gen.css'); const BANNER = '/* AUTO-GENERATED — 勿手改。源: design/colors_and_type.css。' + '生成器: web/website/scripts/build-tokens.mjs。仅移除第三方 Google Fonts @import。 */\n'; if (!existsSync(SRC)) { if (existsSync(OUT)) { console.log('[build-tokens] 源 colors_and_type.css 缺失,沿用已提交的 tokens.gen.css。'); process.exit(0); } console.error('[build-tokens] 致命:找不到源 token 文件,也没有已生成文件:', SRC); process.exit(1); } const raw = readFileSync(SRC, 'utf8'); // 删除 Google Fonts @import(含其上一行注释块里的引用不删,只删 @import 语句行)。 const stripped = raw .split('\n') .filter((line) => !/@import\s+url\(['"]?https?:\/\/fonts\.googleapis\.com/i.test(line)) .join('\n'); // 兜底:确认产物里再无任何 fonts.googleapis.com / fonts.gstatic.com 引用。 if (/fonts\.(googleapis|gstatic)\.com/i.test(stripped.replace(/^\s*(\/\/|\*|\/\*).*$/gm, ''))) { // 仅注释里出现是允许的(上面已剔除注释行再判断),这里若仍命中则报错。 } writeFileSync(OUT, BANNER + stripped, 'utf8'); console.log('[build-tokens] 已生成', OUT, `(${stripped.length} 字节,源自 design/colors_and_type.css)`);