#!/usr/bin/env node /** * build-uniapp.mjs — PC 平台 × uni-app 端构建 * * 与 tools/build-mobile.mjs 的关系(两个轴要分清): * 平台(platform)= pc | mobile —— 决定组件清单与命名空间 * 端(end) = css | html | jsx | vue2 | vue3 | uniapp * - 移动端 × uni-app 由 build-mobile.mjs 产出 → dist/mobile/uniapp/ * - **PC 端 × uni-app 由本脚本产出** → dist/uniapp-pc/ * * 输入:.design_library/kole-ui-uniapp/index.json(只登记已实现的 PC 组件; * 完整 79 个 PC 组件的 uni-app 覆盖见 ROADMAP S7-P26) * 输出:dist/uniapp-pc/.uniapp.vue + index.js + manifest.json + README.md * * 隔离硬约束:**只能写 dist/uniapp-pc/**;PC 的 dist/{components,react,vue3,vue2}/、 * frameworks/、site/、tests/ 一概不碰。 * * 零依赖:只用 Node 内置模块。 */ import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs'; import { fileURLToPath } from 'node:url'; import { dirname, join, relative, sep } from 'node:path'; const __dirname = dirname(fileURLToPath(import.meta.url)); const ROOT = join(__dirname, '..'); const INDEX = join(ROOT, '.design_library', 'kole-ui-uniapp', 'index.json'); const SRC = join(ROOT, 'frameworks-uniapp-pc'); const DIST = join(ROOT, 'dist', 'uniapp-pc'); const ALLOWED_PREFIXES = ['dist/uniapp-pc/']; function guard(absPath) { const rel = relative(ROOT, absPath).split(sep).join('/'); if (!ALLOWED_PREFIXES.some((p) => rel.startsWith(p))) { throw new Error( `[FATAL] 越界写入被拒绝:${rel}\n 本脚本只允许写 ${ALLOWED_PREFIXES.join(' / ')}` ); } return absPath; } function write(absPath, content) { guard(absPath); mkdirSync(dirname(absPath), { recursive: true }); writeFileSync(absPath, String(content).replace(/\r\n/g, '\n'), 'utf8'); } function read(p) { return readFileSync(p, 'utf8').replace(/^\uFEFF/, ''); } const pkg = JSON.parse(read(join(ROOT, 'package.json'))); const index = JSON.parse(read(INDEX)); const problems = []; for (const c of index.components) { if (!existsSync(join(SRC, c.file))) problems.push(`实现文件不存在:frameworks-uniapp-pc/${c.file}`); const contractPath = join(ROOT, '.design_library', 'kole-ui-uniapp', c.contract); if (!existsSync(contractPath)) problems.push(`${c.slug} 契约不可解析:${c.contract}`); } if (problems.length) { console.error('[FATAL] PC × uni-app 索引校验失败:'); problems.forEach((p) => console.error(' - ' + p)); process.exit(1); } const files = []; for (const c of index.components) { const content = read(join(SRC, c.file)); write(join(DIST, c.file), content); files.push({ slug: c.slug, prefix: c.frameworksPrefix, file: c.file, contract: c.contract }); } write( join(DIST, 'index.js'), [ '/* Kole UI — PC 平台 × uni-app 端入口', ` * 版本 ${pkg.version} · ${files.length} 个组件(试点集,见 ROADMAP S7-P26)`, ' * 目标产物:H5(PC 浏览器)与 PC 容器;类名与 PC 端 frameworks/*.css 逐字一致,', ' * 令牌取 PC 的 --kole-*,尺寸保持 px(不做 rpx 化 —— rpx 是移动端语义)。', ' * 令牌需在宿主工程全局引入一次:', " * import 'kole-ui/dist/tokens/tokens.css'; // 或已有 PC 端的令牌引入方式", " * 用法:import KoleButton from 'kole-ui/uniapp-pc/Button.uniapp.vue';", ' */', '', ...files.map((f) => `export { default as Kole${f.prefix} } from './${f.file}';`), '', ].join('\n') ); write( join(DIST, 'manifest.json'), JSON.stringify( { name: 'kole-ui-uniapp-pc', platform: 'pc', end: 'uniapp', version: pkg.version, generated: new Date().toISOString().slice(0, 19).replace('T', ' '), classPolicy: index.classPolicy, tokenPolicy: index.tokenPolicy, pilotSet: true, coverage: { implemented: files.length, total: 79, roadmap: 'S7-P26' }, components: files, }, null, 2 ) ); write( join(DIST, 'README.md'), `# Kole UI — PC × uni-app 端(试点集) 版本 ${pkg.version} · ${files.length} / 79 个 PC 组件已实现 uni-app 端 - **平台 = PC**:组件清单来自 PC 的 79 个中后台组件,类名与 \`frameworks/*.css\` **逐字一致** (\`btn\` / \`kole-input\` / \`kole-card\`),不使用移动端的 \`kole-m-\` 前缀。 - **端 = uni-app**:结构用 uni 基础组件,无 DOM 依赖;令牌取 PC 的 \`--kole-*\`;尺寸保持 **px** (\`rpx\` 是移动端语义,PC 端不使用)。 - 目标产物:H5(PC 浏览器)与 PC 容器。\`:hover\` 只在 H5 产物生效。 ## 用法 \`\`\`vue \`\`\` ## 组件 ${files.map((f) => `- \`${f.slug}\` → \`${f.file}\`(契约 ${f.contract})`).join('\n')} 生成:\`node tools/build-uniapp.mjs\` | 门禁:\`node tools/verify-uniapp.mjs\` ` ); console.log(`[build-uniapp] dist/uniapp-pc/ ← ${files.length} 个组件 SFC + index.js + manifest.json + README.md`); console.log('[build-uniapp] 完成(PC 的 dist/components|react|vue3|vue2 与移动端产物未触碰)');