refactor(plugin): 重构插件系统架构,统一类型导入路径 (#296)
* refactor(plugin): 重构插件系统架构,统一类型导入路径 ## 主要更改 ### 新增 @esengine/plugin-types 包 - 提供打破循环依赖的最小类型定义 - 包含 ServiceToken, createServiceToken, PluginServiceRegistry, IEditorModuleBase ### engine-core 类型统一 - IPlugin<T> 泛型参数改为 T = unknown - 所有运行时类型(IRuntimeModule, ModuleManifest, SystemContext)在此定义 - 新增 PluginServiceRegistry.ts 导出服务令牌相关类型 ### editor-core 类型优化 - 重命名 IPluginLoader.ts 为 EditorModule.ts - 新增 IEditorPlugin = IPlugin<IEditorModuleLoader> 类型别名 - 移除弃用别名 IPluginLoader, IRuntimeModuleLoader ### 编辑器插件更新 - 所有 9 个编辑器插件使用 IEditorPlugin 类型 - 统一从 editor-core 导入编辑器类型 ### 服务令牌规范 - 各模块在 tokens.ts 中定义自己的服务接口和令牌 - 遵循"谁定义接口,谁导出 Token"原则 ## 导入规范 | 场景 | 导入来源 | |------|---------| | 运行时模块 | @esengine/engine-core | | 编辑器插件 | @esengine/editor-core | | 服务令牌 | @esengine/engine-core | * refactor(plugin): 完善服务令牌规范,统一运行时模块 ## 更改内容 ### 运行时模块优化 - particle: 使用 PluginServiceRegistry 获取依赖服务 - physics-rapier2d: 通过服务令牌注册/获取物理查询接口 - tilemap: 使用服务令牌获取物理系统依赖 - sprite: 导出服务令牌 - ui: 导出服务令牌 - behavior-tree: 使用服务令牌系统 ### 资产系统增强 - IAssetManager 接口扩展 - 加载器使用服务令牌获取依赖 ### 运行时核心 - GameRuntime 使用 PluginServiceRegistry - 导出服务令牌相关类型 ### 编辑器服务 - EngineService 适配新的服务令牌系统 - AssetRegistryService 优化 * fix: 修复 editor-app 和 behavior-tree-editor 中的类型引用 - editor-app/PluginLoader.ts: 使用 IPlugin 替代 IPluginLoader - behavior-tree-editor: 使用 IEditorPlugin 替代 IPluginLoader * fix(ui): 添加缺失的 ecs-engine-bindgen 依赖 UIRuntimeModule 使用 EngineBridgeToken,需要声明对 ecs-engine-bindgen 的依赖 * fix(type): 解决 ServiceToken 跨包类型兼容性问题 - 在 engine-core 中直接定义 ServiceToken 和 PluginServiceRegistry 而不是从 plugin-types 重新导出,确保 tsup 生成的类型声明 以 engine-core 作为类型来源 - 移除 RuntimeResolver.ts 中的硬编码模块 ID 检查, 改用 module.json 中的 name 配置 - 修复 pnpm-lock.yaml 中的依赖记录 * refactor(arch): 改进架构设计,移除硬编码 - 统一类型导出:editor-core 从 engine-core 导入 IEditorModuleBase - RuntimeResolver: 将硬编码路径改为配置常量和搜索路径列表 - 添加跨平台安装路径支持(Windows/macOS/Linux) - 使用 ENGINE_WASM_CONFIG 配置引擎 WASM 文件信息 - IBundlePackOptions 添加 preloadBundles 配置项 * fix(particle): 添加缺失的 ecs-engine-bindgen 依赖 ParticleRuntimeModule 导入了 @esengine/ecs-engine-bindgen 的 tokens, 但 package.json 中未声明该依赖,导致 CI 构建失败。 * fix(physics-rapier2d): 移除不存在的 PhysicsSystemContext 导出 PhysicsRuntimeModule 中不存在该类型,导致 type-check 失败
This commit is contained in:
47
packages/plugin-types/package.json
Normal file
47
packages/plugin-types/package.json
Normal file
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"name": "@esengine/plugin-types",
|
||||
"version": "1.0.0",
|
||||
"description": "Plugin system type definitions for ES Engine",
|
||||
"type": "module",
|
||||
"main": "dist/index.js",
|
||||
"module": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"import": "./dist/index.js"
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "tsup",
|
||||
"build:watch": "tsup --watch",
|
||||
"clean": "rimraf dist",
|
||||
"type-check": "tsc --noEmit"
|
||||
},
|
||||
"keywords": [
|
||||
"ecs",
|
||||
"plugin",
|
||||
"types",
|
||||
"typescript"
|
||||
],
|
||||
"author": "yhh",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@esengine/ecs-framework": "workspace:*",
|
||||
"@esengine/build-config": "workspace:*",
|
||||
"rimraf": "^5.0.0",
|
||||
"tsup": "^8.0.0",
|
||||
"typescript": "^5.8.3"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/esengine/ecs-framework.git",
|
||||
"directory": "packages/plugin-types"
|
||||
}
|
||||
}
|
||||
202
packages/plugin-types/src/index.ts
Normal file
202
packages/plugin-types/src/index.ts
Normal file
@@ -0,0 +1,202 @@
|
||||
/**
|
||||
* 插件系统基础类型定义
|
||||
* Plugin system base type definitions
|
||||
*
|
||||
* 这个包只提供用于打破循环依赖的基础接口。
|
||||
* 完整的类型定义在 engine-core 中。
|
||||
*
|
||||
* This package only provides base interfaces to break circular dependencies.
|
||||
* Complete type definitions are in engine-core.
|
||||
*
|
||||
* 导出内容 | Exports:
|
||||
* - ServiceToken / createServiceToken / PluginServiceRegistry: 服务令牌系统
|
||||
* - IEditorModuleBase: 编辑器模块基础接口(用于 IPlugin.editorModule 类型)
|
||||
*
|
||||
* 不导出(在 engine-core 中定义)| Not exported (defined in engine-core):
|
||||
* - IPlugin, IRuntimeModule, SystemContext: 完整的插件类型
|
||||
* - ModuleManifest: 完整的模块清单类型
|
||||
* - LoadingPhase: 加载阶段类型
|
||||
*/
|
||||
|
||||
import type { ServiceContainer } from '@esengine/ecs-framework';
|
||||
|
||||
// ============================================================================
|
||||
// 服务令牌 | Service Token
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* 服务令牌接口
|
||||
* Service token interface
|
||||
*
|
||||
* 用于类型安全的服务注册和获取。
|
||||
* For type-safe service registration and retrieval.
|
||||
*
|
||||
* 注意:__phantom 是必需属性(使用 declare 避免运行时开销),
|
||||
* 这确保 TypeScript 在跨包类型解析时保留泛型类型信息。
|
||||
*
|
||||
* Note: __phantom is a required property (using declare to avoid runtime overhead),
|
||||
* which ensures TypeScript preserves generic type information across packages.
|
||||
*/
|
||||
export interface ServiceToken<T> {
|
||||
readonly id: symbol;
|
||||
readonly name: string;
|
||||
/**
|
||||
* Phantom type 标记(强制类型推断)
|
||||
* Phantom type marker (enforces type inference)
|
||||
*
|
||||
* 使用 declare 声明,不会在运行时占用内存。
|
||||
* Declared with 'declare', no runtime memory overhead.
|
||||
*/
|
||||
readonly __phantom: T;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建服务令牌
|
||||
* Create a service token
|
||||
*
|
||||
* @param name 令牌名称 | Token name
|
||||
* @returns 服务令牌 | Service token
|
||||
*/
|
||||
export function createServiceToken<T>(name: string): ServiceToken<T> {
|
||||
// __phantom 仅用于类型推断,不需要实际值
|
||||
// __phantom is only for type inference, no actual value needed
|
||||
return {
|
||||
id: Symbol(name),
|
||||
name
|
||||
} as ServiceToken<T>;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 插件服务注册表 | Plugin Service Registry
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* 插件服务注册表
|
||||
* Plugin service registry
|
||||
*
|
||||
* 用于跨插件共享服务的类型安全注册表。
|
||||
* Type-safe registry for sharing services between plugins.
|
||||
*/
|
||||
export class PluginServiceRegistry {
|
||||
private _services = new Map<symbol, unknown>();
|
||||
|
||||
/**
|
||||
* 注册服务
|
||||
* Register a service
|
||||
*/
|
||||
register<T>(token: ServiceToken<T>, service: T): void {
|
||||
this._services.set(token.id, service);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取服务(可选)
|
||||
* Get a service (optional)
|
||||
*/
|
||||
get<T>(token: ServiceToken<T>): T | undefined {
|
||||
return this._services.get(token.id) as T | undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取服务(必需)
|
||||
* Get a service (required)
|
||||
*
|
||||
* @throws 如果服务未注册 | If service is not registered
|
||||
*/
|
||||
require<T>(token: ServiceToken<T>): T {
|
||||
const service = this._services.get(token.id);
|
||||
if (service === undefined) {
|
||||
throw new Error(`Service not found: ${token.name}`);
|
||||
}
|
||||
return service as T;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查服务是否已注册
|
||||
* Check if a service is registered
|
||||
*/
|
||||
has<T>(token: ServiceToken<T>): boolean {
|
||||
return this._services.has(token.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 注销服务
|
||||
* Unregister a service
|
||||
*/
|
||||
unregister<T>(token: ServiceToken<T>): boolean {
|
||||
return this._services.delete(token.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空所有服务
|
||||
* Clear all services
|
||||
*/
|
||||
clear(): void {
|
||||
this._services.clear();
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 编辑器模块基础接口 | Editor Module Base Interface
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* 编辑器模块基础接口
|
||||
* Base editor module interface
|
||||
*
|
||||
* 定义编辑器模块的核心生命周期方法。
|
||||
* 这个接口用于 IPlugin.editorModule 的类型定义,避免 engine-core 依赖 editor-core。
|
||||
* 完整的 IEditorModuleLoader 接口在 editor-core 中扩展此接口。
|
||||
*
|
||||
* Defines core lifecycle methods for editor modules.
|
||||
* This interface is used for IPlugin.editorModule type to avoid engine-core depending on editor-core.
|
||||
* Full IEditorModuleLoader interface extends this in editor-core.
|
||||
*/
|
||||
export interface IEditorModuleBase {
|
||||
/**
|
||||
* 安装编辑器模块
|
||||
* Install editor module
|
||||
*/
|
||||
install(services: ServiceContainer): Promise<void>;
|
||||
|
||||
/**
|
||||
* 卸载编辑器模块
|
||||
* Uninstall editor module
|
||||
*/
|
||||
uninstall?(): Promise<void>;
|
||||
|
||||
/**
|
||||
* 编辑器就绪回调
|
||||
* Editor ready callback
|
||||
*/
|
||||
onEditorReady?(): void | Promise<void>;
|
||||
|
||||
/**
|
||||
* 项目打开回调
|
||||
* Project open callback
|
||||
*/
|
||||
onProjectOpen?(projectPath: string): void | Promise<void>;
|
||||
|
||||
/**
|
||||
* 项目关闭回调
|
||||
* Project close callback
|
||||
*/
|
||||
onProjectClose?(): void | Promise<void>;
|
||||
|
||||
/**
|
||||
* 场景加载回调
|
||||
* Scene loaded callback
|
||||
*/
|
||||
onSceneLoaded?(scenePath: string): void;
|
||||
|
||||
/**
|
||||
* 场景保存前回调
|
||||
* Before scene save callback
|
||||
*/
|
||||
onSceneSaving?(scenePath: string): boolean | void;
|
||||
|
||||
/**
|
||||
* 设置语言
|
||||
* Set locale
|
||||
*/
|
||||
setLocale?(locale: string): void;
|
||||
}
|
||||
8
packages/plugin-types/tsconfig.build.json
Normal file
8
packages/plugin-types/tsconfig.build.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"declaration": true,
|
||||
"declarationMap": true
|
||||
},
|
||||
"exclude": ["node_modules", "dist", "**/*.test.ts", "**/*.spec.ts"]
|
||||
}
|
||||
17
packages/plugin-types/tsconfig.json
Normal file
17
packages/plugin-types/tsconfig.json
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"lib": ["ES2020", "DOM"],
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"outDir": "./dist",
|
||||
"rootDir": "./src",
|
||||
"declaration": true,
|
||||
"declarationMap": true
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["node_modules", "dist"]
|
||||
}
|
||||
14
packages/plugin-types/tsup.config.ts
Normal file
14
packages/plugin-types/tsup.config.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { defineConfig } from 'tsup';
|
||||
|
||||
export default defineConfig({
|
||||
entry: ['src/index.ts'],
|
||||
format: ['esm'],
|
||||
dts: true,
|
||||
splitting: false,
|
||||
sourcemap: true,
|
||||
clean: true,
|
||||
tsconfig: 'tsconfig.build.json',
|
||||
external: [
|
||||
'@esengine/ecs-framework'
|
||||
]
|
||||
});
|
||||
Reference in New Issue
Block a user