feat(worker): 添加微信小游戏 Worker 支持和 Worker Generator CLI (#297)

* feat(worker): 添加微信小游戏 Worker 支持和 Worker Generator CLI

- 新增 @esengine/worker-generator 包,用于从 WorkerEntitySystem 生成 Worker 文件
- WorkerEntitySystem 添加 workerScriptPath 配置项,支持预编译 Worker 脚本
- CLI 工具支持 --wechat 模式,自动转换 ES6+ 为 ES5 语法
- 修复微信小游戏 Worker 消息格式差异(res 直接是数据,无需 .data)
- 更新中英文文档,添加微信小游戏支持章节

* docs: 更新 changelog,添加 v2.3.1 说明并标注 v2.3.0 为废弃

* fix: 修复 CI 检查问题

- 移除 cli.ts 中未使用的 toKebabCase 函数
- 修复 generator.ts 中正则表达式的 ReDoS 风险(使用 [ \t] 替代 \s*)
- 更新 changelog 版本号(2.3.1 -> 2.3.2)

* docs: 移除未发布版本的 changelog 条目

* fix(worker-generator): 使用 TypeScript 编译器替代手写正则进行 ES5 转换

- 修复 CodeQL 检测的 ReDoS 安全问题
- 使用 ts.transpileModule 进行安全可靠的代码转换
- 移除所有可能导致回溯的正则表达式
This commit is contained in:
YHH
2025-12-08 17:02:11 +08:00
committed by GitHub
parent 52bbccd53c
commit dfd0dfc7f9
18 changed files with 2595 additions and 546 deletions

View File

@@ -34,6 +34,20 @@ export interface WorkerSystemConfig {
entityDataSize?: number;
/** 最大实体数量用于预分配SharedArrayBuffer */
maxEntities?: number;
/**
* 预编译 Worker 脚本路径(微信小游戏等不支持动态脚本的平台必需)
* Pre-compiled Worker script path (required for platforms like WeChat Mini Game that don't support dynamic scripts)
*
* @example
* ```typescript
* // 微信小游戏使用方式:
* // 1. 创建 Worker 文件: workers/physics-worker.js
* // 2. 在 game.json 配置 "workers": "workers"
* // 3. 指定路径:
* workerScriptPath: 'workers/physics-worker.js'
* ```
*/
workerScriptPath?: string;
}
@@ -188,9 +202,10 @@ export type SharedArrayBufferProcessFunction = (
* ```
*/
export abstract class WorkerEntitySystem<TEntityData = any> extends EntitySystem {
protected config: Required<Omit<WorkerSystemConfig, 'systemConfig' | 'entitiesPerWorker'>> & {
protected config: Required<Omit<WorkerSystemConfig, 'systemConfig' | 'entitiesPerWorker' | 'workerScriptPath'>> & {
systemConfig?: any;
entitiesPerWorker?: number;
workerScriptPath?: string;
};
private workerPool: PlatformWorkerPool | null = null;
private isProcessing = false;
@@ -222,7 +237,8 @@ export abstract class WorkerEntitySystem<TEntityData = any> extends EntitySystem
...(config.entitiesPerWorker !== undefined && { entitiesPerWorker: config.entitiesPerWorker }),
useSharedArrayBuffer: config.useSharedArrayBuffer ?? this.isSharedArrayBufferSupported(),
entityDataSize: config.entityDataSize ?? this.getDefaultEntityDataSize(),
maxEntities: config.maxEntities ?? 10000
maxEntities: config.maxEntities ?? 10000,
...(config.workerScriptPath !== undefined && { workerScriptPath: config.workerScriptPath })
};
@@ -300,16 +316,34 @@ export abstract class WorkerEntitySystem<TEntityData = any> extends EntitySystem
*/
private initializeWorkerPool(): void {
try {
const script = this.createWorkerScript();
// 在WorkerEntitySystem中处理平台相关逻辑
const workers: PlatformWorker[] = [];
const platformConfig = this.platformAdapter.getPlatformConfig();
const fullScript = (platformConfig.workerScriptPrefix || '') + script;
const workers: PlatformWorker[] = [];
// 判断使用外部脚本路径还是动态生成脚本
// Determine whether to use external script path or dynamically generated script
let scriptOrPath: string;
if (this.config.workerScriptPath) {
// 使用预编译的外部 Worker 文件(微信小游戏等平台)
// Use pre-compiled external Worker file (for WeChat Mini Game, etc.)
scriptOrPath = this.config.workerScriptPath;
this.logger.info(`${this.systemName}: 使用外部Worker文件: ${scriptOrPath}`);
} else if (platformConfig.limitations?.noEval) {
// 平台不支持动态脚本,且未提供外部脚本路径
// Platform doesn't support dynamic scripts and no external script path provided
this.logger.error(`${this.systemName}: 当前平台不支持动态Worker脚本请配置 workerScriptPath 指定预编译的Worker文件`);
this.config.enableWorker = false;
return;
} else {
// 动态生成 Worker 脚本(浏览器等支持的平台)
// Dynamically generate Worker script (for browsers and other supported platforms)
const script = this.createWorkerScript();
scriptOrPath = (platformConfig.workerScriptPrefix || '') + script;
}
for (let i = 0; i < this.config.workerCount; i++) {
try {
const worker = this.platformAdapter.createWorker(fullScript, {
const worker = this.platformAdapter.createWorker(scriptOrPath, {
name: `WorkerEntitySystem-${i}`
});
workers.push(worker);