Feature/editor optimization (#251)

* refactor: 编辑器/运行时架构拆分与构建系统升级

* feat(core): 层级系统重构与UI变换矩阵修复

* refactor: 移除 ecs-components 聚合包并修复跨包组件查找问题

* fix(physics): 修复跨包组件类引用问题

* feat: 统一运行时架构与浏览器运行支持

* feat(asset): 实现浏览器运行时资产加载系统

* fix: 修复文档、CodeQL安全问题和CI类型检查错误

* fix: 修复文档、CodeQL安全问题和CI类型检查错误

* fix: 修复文档、CodeQL安全问题、CI类型检查和测试错误

* test: 补齐核心模块测试用例,修复CI构建配置

* fix: 修复测试用例中的类型错误和断言问题

* fix: 修复 turbo build:npm 任务的依赖顺序问题

* fix: 修复 CI 构建错误并优化构建性能
This commit is contained in:
YHH
2025-12-01 22:28:51 +08:00
committed by GitHub
parent 189714c727
commit b42a7b4e43
468 changed files with 18301 additions and 9075 deletions

View File

@@ -0,0 +1,109 @@
/**
* Editor-Only Package Preset
* 纯编辑器包预设
*
* 用于仅在编辑器环境使用的包
* For packages only used in the editor environment
*
* Examples: editor-core, node-editor
*/
import { resolve } from 'path';
import { defineConfig, type UserConfig } from 'vite';
import dts from 'vite-plugin-dts';
import react from '@vitejs/plugin-react';
import { STANDARD_EXTERNALS } from '../types';
import { cssInjectPlugin } from '../plugins/css-inject';
export interface EditorOnlyOptions {
/** 包根目录 (通常是 __dirname) */
root: string;
/** 入口文件 (默认: src/index.ts) */
entry?: string;
/** 是否包含 React 组件 (默认: true) */
hasReact?: boolean;
/** 是否包含 CSS (默认: false) */
hasCSS?: boolean;
/** 额外的外部依赖 */
external?: (string | RegExp)[];
/** 额外的 Vite 配置 */
viteConfig?: Partial<UserConfig>;
}
/**
* 创建纯编辑器包的 Vite 配置
*
* @example
* ```typescript
* // vite.config.ts
* import { editorOnlyPreset } from '@esengine/build-config/presets';
*
* export default editorOnlyPreset({
* root: __dirname,
* hasReact: true,
* hasCSS: true
* });
* ```
*/
export function editorOnlyPreset(options: EditorOnlyOptions): UserConfig {
const {
root,
entry = 'src/index.ts',
hasReact = true,
hasCSS = false,
external = [],
viteConfig = {}
} = options;
const plugins: any[] = [];
// React 支持
if (hasReact) {
plugins.push(react());
}
// DTS 生成
plugins.push(
dts({
include: ['src'],
outDir: 'dist',
rollupTypes: false
})
);
// CSS 注入
if (hasCSS) {
plugins.push(cssInjectPlugin());
}
return defineConfig({
plugins,
esbuild: hasReact ? { jsx: 'automatic' } : undefined,
build: {
lib: {
entry: resolve(root, entry),
formats: ['es'],
fileName: () => 'index.js'
},
rollupOptions: {
external: [
...STANDARD_EXTERNALS,
...external
],
output: {
exports: 'named',
preserveModules: false
}
},
target: 'es2020',
minify: false,
sourcemap: true
},
...viteConfig
});
}

View File

@@ -0,0 +1,10 @@
/**
* Build Presets
* 构建预设
*
* 提供不同类型包的标准化 Vite 配置
*/
export { runtimeOnlyPreset, type RuntimeOnlyOptions } from './runtime-only';
export { pluginPreset, standaloneRuntimeConfig, type PluginPackageOptions, type StandaloneRuntimeOptions } from './plugin';
export { editorOnlyPreset, type EditorOnlyOptions } from './editor-only';

View File

@@ -0,0 +1,157 @@
/**
* Plugin Package Preset (tsup)
* 插件包预设 - 基于 tsup/esbuild
*
* 用于同时包含运行时和编辑器模块的插件包
* For plugin packages with both runtime and editor modules
*
* 生成三个入口点:
* - index.js - 完整导出(编辑器环境)
* - runtime.js - 纯运行时(游戏运行时环境,不含 React
* - editor/index.js - 编辑器模块
*
* Examples: ui, tilemap, behavior-tree, physics-rapier2d
*/
import type { Options } from 'tsup';
import { STANDARD_EXTERNALS } from '../types';
export interface PluginPackageOptions {
/** 入口点配置 */
entries?: {
/** 主入口 (默认: src/index.ts) */
main?: string;
/** 运行时入口 (默认: src/runtime.ts) */
runtime?: string;
/** 编辑器入口 (默认: src/editor/index.ts) */
editor?: string;
};
/** 额外的外部依赖 */
external?: (string | RegExp)[];
/** 额外的 tsup 配置 */
tsupConfig?: Partial<Options>;
}
/**
* 创建插件包的 tsup 配置
*
* @example
* ```typescript
* // tsup.config.ts
* import { defineConfig } from 'tsup';
* import { pluginPreset } from '@esengine/build-config/presets';
*
* export default defineConfig(pluginPreset());
* ```
*/
export function pluginPreset(options: PluginPackageOptions = {}): Options {
const {
entries = {},
external = [],
tsupConfig = {}
} = options;
const mainEntry = entries.main ?? 'src/index.ts';
const runtimeEntry = entries.runtime ?? 'src/runtime.ts';
const editorEntry = entries.editor ?? 'src/editor/index.ts';
// 合并外部依赖
const allExternal = [
...STANDARD_EXTERNALS,
...external
];
return {
entry: {
index: mainEntry,
runtime: runtimeEntry,
'editor/index': editorEntry
},
format: ['esm'],
dts: true,
splitting: false, // 禁用代码分割
sourcemap: true,
clean: true,
external: allExternal,
esbuildOptions(options) {
options.jsx = 'automatic';
},
...tsupConfig
};
}
/**
* 创建纯运行时包的 tsup 配置
*/
export interface RuntimeOnlyOptions {
/** 入口文件 (默认: src/index.ts) */
entry?: string;
/** 额外的外部依赖 */
external?: (string | RegExp)[];
/** 额外的 tsup 配置 */
tsupConfig?: Partial<Options>;
}
export function runtimeOnlyPreset(options: RuntimeOnlyOptions = {}): Options {
const {
entry = 'src/index.ts',
external = [],
tsupConfig = {}
} = options;
return {
entry: [entry],
format: ['esm'],
dts: true,
splitting: false,
sourcemap: true,
clean: true,
external: [
...STANDARD_EXTERNALS,
...external
],
...tsupConfig
};
}
/**
* 创建纯编辑器包的 tsup 配置
*/
export interface EditorOnlyOptions {
/** 入口文件 (默认: src/index.ts) */
entry?: string;
/** 额外的外部依赖 */
external?: (string | RegExp)[];
/** 额外的 tsup 配置 */
tsupConfig?: Partial<Options>;
}
export function editorOnlyPreset(options: EditorOnlyOptions = {}): Options {
const {
entry = 'src/index.ts',
external = [],
tsupConfig = {}
} = options;
return {
entry: [entry],
format: ['esm'],
dts: true,
splitting: false,
sourcemap: true,
clean: true,
// 将 CSS 内联到 JS 中,运行时自动注入到 DOM
// Inline CSS into JS, auto-inject to DOM at runtime
injectStyle: true,
external: [
...STANDARD_EXTERNALS,
...external
],
esbuildOptions(options) {
options.jsx = 'automatic';
},
...tsupConfig
};
}

View File

@@ -0,0 +1,176 @@
/**
* Plugin Package Preset
* 插件包预设
*
* 用于同时包含运行时和编辑器模块的插件包
* For plugin packages with both runtime and editor modules
*
* 生成三个入口点:
* - index.js - 完整导出(编辑器环境)
* - runtime.js - 纯运行时(游戏运行时环境,不含 React
* - editor/index.js - 编辑器模块
*
* Examples: ui, tilemap, behavior-tree, physics-rapier2d
*/
import { resolve } from 'path';
import { defineConfig, type UserConfig } from 'vite';
import dts from 'vite-plugin-dts';
import { STANDARD_EXTERNALS, EDITOR_ONLY_EXTERNALS } from '../types';
import { cssInjectPlugin } from '../plugins/css-inject';
export interface PluginPackageOptions {
/** 包根目录 (通常是 __dirname) */
root: string;
/** 入口点配置 */
entries?: {
/** 主入口 (默认: src/index.ts) */
main?: string;
/** 运行时入口 (默认: src/runtime.ts) */
runtime?: string;
/** 编辑器入口 (默认: src/editor/index.ts) */
editor?: string;
};
/** 是否包含 CSS (默认: false) */
hasCSS?: boolean;
/** 是否生成 plugin.json 导出 (默认: true) */
hasPluginJson?: boolean;
/** 额外的外部依赖 */
external?: (string | RegExp)[];
/** 额外的 Vite 配置 */
viteConfig?: Partial<UserConfig>;
}
/**
* 创建插件包的 Vite 配置
*
* @example
* ```typescript
* // vite.config.ts
* import { pluginPreset } from '@esengine/build-config/presets';
*
* export default pluginPreset({
* root: __dirname,
* hasCSS: true
* });
* ```
*/
export function pluginPreset(options: PluginPackageOptions): UserConfig {
const {
root,
entries = {},
hasCSS = false,
external = [],
viteConfig = {}
} = options;
const mainEntry = entries.main ?? 'src/index.ts';
const runtimeEntry = entries.runtime ?? 'src/runtime.ts';
const editorEntry = entries.editor ?? 'src/editor/index.ts';
// 构建入口点映射
const entryPoints: Record<string, string> = {
index: resolve(root, mainEntry),
runtime: resolve(root, runtimeEntry),
'editor/index': resolve(root, editorEntry)
};
const plugins: any[] = [
dts({
include: ['src'],
outDir: 'dist',
rollupTypes: false
})
];
// CSS 注入插件
if (hasCSS) {
plugins.push(cssInjectPlugin());
}
return defineConfig({
plugins,
esbuild: {
jsx: 'automatic',
},
build: {
lib: {
entry: entryPoints,
formats: ['es'],
fileName: (_format: string, entryName: string) => `${entryName}.js`
},
rollupOptions: {
external: [
...STANDARD_EXTERNALS,
...external
],
output: {
exports: 'named',
preserveModules: false,
// 禁用自动代码分割,所有共享代码内联到各入口
manualChunks: () => undefined
}
},
target: 'es2020',
minify: false,
sourcemap: true
},
...viteConfig
});
}
/**
* 创建独立运行时构建配置
* 用于 platform-web 等需要生成独立 IIFE 运行时的场景
*
* @example
* ```typescript
* // rollup.runtime.config.js
* import { standaloneRuntimeConfig } from '@esengine/build-config/presets';
*
* export default standaloneRuntimeConfig({
* root: __dirname,
* entry: 'src/runtime.ts',
* globalName: 'ECSRuntime'
* });
* ```
*/
export interface StandaloneRuntimeOptions {
/** 包根目录 */
root: string;
/** 入口文件 */
entry: string;
/** 全局变量名 (IIFE 格式) */
globalName: string;
/** 额外的外部依赖 */
external?: (string | RegExp)[];
}
export function standaloneRuntimeConfig(options: StandaloneRuntimeOptions) {
const { root, entry, globalName, external = [] } = options;
// 返回 Rollup 配置(而非 Vite因为需要 IIFE 格式)
return {
input: resolve(root, entry),
output: {
file: 'dist/runtime.browser.js',
format: 'iife' as const,
name: globalName,
sourcemap: true,
exports: 'default' as const
},
external: [
...STANDARD_EXTERNALS,
...EDITOR_ONLY_EXTERNALS,
...external
],
plugins: [
// 需要在使用时传入 rollup 插件
]
};
}

View File

@@ -0,0 +1,78 @@
/**
* Runtime-Only Package Preset
* 纯运行时包预设
*
* 用于不包含任何编辑器代码的基础库
* For basic libraries without any editor code
*
* Examples: core, math, components, asset-system
*/
import { resolve } from 'path';
import { defineConfig, type UserConfig } from 'vite';
import dts from 'vite-plugin-dts';
import { STANDARD_EXTERNALS } from '../types';
export interface RuntimeOnlyOptions {
/** 包根目录 (通常是 __dirname) */
root: string;
/** 入口文件 (默认: src/index.ts) */
entry?: string;
/** 额外的外部依赖 */
external?: (string | RegExp)[];
/** 额外的 Vite 配置 */
viteConfig?: Partial<UserConfig>;
}
/**
* 创建纯运行时包的 Vite 配置
*
* @example
* ```typescript
* // vite.config.ts
* import { runtimeOnlyPreset } from '@esengine/build-config/presets';
*
* export default runtimeOnlyPreset({
* root: __dirname
* });
* ```
*/
export function runtimeOnlyPreset(options: RuntimeOnlyOptions): UserConfig {
const {
root,
entry = 'src/index.ts',
external = [],
viteConfig = {}
} = options;
return defineConfig({
plugins: [
dts({
include: ['src'],
outDir: 'dist',
rollupTypes: false
})
],
build: {
lib: {
entry: resolve(root, entry),
formats: ['es'],
fileName: () => 'index.js'
},
rollupOptions: {
external: [
...STANDARD_EXTERNALS,
...external
],
output: {
exports: 'named',
preserveModules: false
}
},
target: 'es2020',
minify: false,
sourcemap: true
},
...viteConfig
});
}