host.js+entry.js:engineMode 分流。real=引擎掌帧(engineInit 五回调 engGameInit/ Update/UpdatePost/Render/RenderPost 接帧驱动+渲染)+getContext2d backing 切引擎 mainContext(setGLEnable(false) 纯2D渲进 mainContext);stub=α RAF桩原样保留(可回滚点)。 本机已验(主会话亲跑): - 155单测绿(基线持平,受控面/插件零改故计数不变) - 受控面零改实证:src/core/api.d.ts+plugin.js 未触(七项 backing 全在 host 层切换) - Q4边界:引擎 import 仅 host.js+entry.js(metafile importers 反查证),未泄进受控面/插件 - 真接线门①:esbuild metafile 实证 littlejsengine 真入产物(163691 bytesInOutput), box2d 惰性(0 wasm input),产物 205KB min 8-agent workflow(源码取证→设计→对抗复审→实现):3/3 concerns 0 fatal。 17 mustFix(P0×1/P1×9/P2×7)全采纳:P0=real像素门 overshoot(引擎追帧 N tick/RAF 墙钟抖动 污染采样帧)→改 stub 通道独占逐像素回归,real 只证掌帧;P1 源码级纠偏=debug水印每帧画 averageFPS入mainContext(setDebugWatermark(false))/clearColor默认alpha=0不铺底 (setCanvasClearColor(BLACK))/P75须读timeReal非mockNowMs(real模式退化逻辑帧钟)。 门0 G0-1~G0-7(引擎真掌帧/真渲2D mainContext/双时钟/无uncaught/水印已除)须 mini-desktop chrome 实测(6c6g 禁 chrome)——未实测不宣布 A0 完成。 新:docs/agent-specs/2026-06-13-A0-引擎掌帧接管-edit-plan.md(编辑计划+门0 runbook) +game-runtime/test/harness/gate0-engine-takeover.cjs(门0 CDP 驱动,独立闭合不复用未改造的 integration-run) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
84 lines
3.7 KiB
JavaScript
84 lines
3.7 KiB
JavaScript
/**
|
||
* scripts/build.mjs — LittleJS 增强发行版打包脚本(esbuild 锁参,core-protocol-v0)
|
||
*
|
||
* ⚠️ 运行环境纪律(执行版 §1/§5):
|
||
* **本脚本仅在「集成段(mini-desktop)」运行**,不在 lane 本机跑。lane 阶段一切测试 =
|
||
* 零依赖 `node --test`;esbuild 是工具链依赖(需 `npm i -D esbuild`),只在 mini-desktop 装与跑。
|
||
* 在无 esbuild 的本机执行本脚本会**显式报错并给出安装指引**(不静默失败)。
|
||
*
|
||
* 锁定参数(§5,不得擅改 —— 改动影响 SIZES 口径与 channel-spike 对照):
|
||
* bundle + minify + format=iife + target=es2019 + sourcemap=false
|
||
*
|
||
* 用法(集成段):
|
||
* node scripts/build.mjs <入口.js> <输出.js> [--global-name=NAME]
|
||
* 例:node scripts/build.mjs src/core/plugin.js dist/core.iife.js --global-name=GameRuntimeCore
|
||
*/
|
||
|
||
'use strict';
|
||
|
||
import { argv, exit } from 'node:process';
|
||
import { writeFileSync } from 'node:fs';
|
||
|
||
/** 锁定的 esbuild 构建参数(§5 写死,集成段与 size.mjs 必须同口径)。 */
|
||
export const LOCKED_BUILD_OPTIONS = {
|
||
bundle: true,
|
||
minify: true,
|
||
format: 'iife',
|
||
target: 'es2019',
|
||
sourcemap: false,
|
||
// legalComments:'none' 去掉许可证注释,保证 minify 后字节口径稳定(不影响合规,许可证在仓内 LICENSE 留存)。
|
||
legalComments: 'none',
|
||
};
|
||
|
||
/**
|
||
* 用锁定参数构建单个入口。集成段调用;本机无 esbuild 时抛错给指引。
|
||
* @param {string} entry 入口文件路径
|
||
* @param {string} outfile 输出文件路径
|
||
* @param {string} [globalName] iife 全局变量名(可选)
|
||
* @returns {Promise<void>}
|
||
*/
|
||
export async function build(entry, outfile, globalName) {
|
||
let esbuild;
|
||
try {
|
||
// 动态 import:仅集成段装了 esbuild 才解析得到;本机解析失败走下方指引。
|
||
esbuild = await import('esbuild');
|
||
} catch {
|
||
console.error(
|
||
'[build] 未找到 esbuild —— 本脚本仅在集成段(mini-desktop)运行。\n' +
|
||
' 请在集成段执行:npm i -D esbuild,再重跑本脚本。\n' +
|
||
' lane 本机请勿运行构建(纪律:本机零依赖、只跑 node --test)。'
|
||
);
|
||
throw new Error('esbuild 不可用(非集成段环境)');
|
||
}
|
||
|
||
// 【A0/门1① additive】metafile:true 落 <outfile>.meta.json,供 grep 核验「引擎真入包 + 被哪些 chunk 引用」。
|
||
// additive(不改 LOCKED_BUILD_OPTIONS 锁参口径):移除 metafile 不影响产物字节,仅少一份诊断文件。
|
||
const result = await esbuild.build({
|
||
...LOCKED_BUILD_OPTIONS,
|
||
entryPoints: [entry],
|
||
outfile,
|
||
metafile: true,
|
||
...(globalName ? { globalName } : {}),
|
||
});
|
||
if (result && result.metafile) {
|
||
writeFileSync(outfile + '.meta.json', JSON.stringify(result.metafile));
|
||
console.log(`[build] metafile → ${outfile}.meta.json`);
|
||
}
|
||
console.log(`[build] OK ${entry} → ${outfile} (iife/es2019/min/no-sourcemap)`);
|
||
}
|
||
|
||
// ── CLI 入口(仅集成段使用)──────────────────────────────────────────────────
|
||
// 仅当作为脚本直接运行时执行 CLI;被 import(如 size.mjs 复用 LOCKED_BUILD_OPTIONS)时不触发。
|
||
if (import.meta.url === `file://${argv[1]}`) {
|
||
const [entry, outfile, ...rest] = argv.slice(2);
|
||
if (!entry || !outfile) {
|
||
console.error('用法:node scripts/build.mjs <入口.js> <输出.js> [--global-name=NAME]');
|
||
exit(1);
|
||
}
|
||
const gn = (rest.find((a) => a.startsWith('--global-name=')) || '').split('=')[1];
|
||
build(entry, outfile, gn).catch((e) => {
|
||
console.error('[build] 失败:' + (e && e.message ? e.message : e));
|
||
exit(1);
|
||
});
|
||
}
|