Files
esengine/scripts/copy-engine-modules.mjs

274 lines
8.0 KiB
JavaScript

#!/usr/bin/env node
/**
* Copy Engine Modules Script
* 复制引擎模块脚本
*
* Copies module.json and dist/index.js from each engine module package
* to packages/editor-app/dist/engine/{moduleId}/ directory.
* 将每个引擎模块包的 module.json 和 dist/index.js 复制到
* packages/editor-app/dist/engine/{moduleId}/ 目录。
*
* This ensures the same directory structure is used in development and production.
* 这确保开发和生产环境使用相同的目录结构。
*
* Usage:
* node scripts/copy-engine-modules.mjs
* pnpm run copy-modules
*
* Output structure:
* packages/editor-app/dist/
* engine/
* index.json <- Module registry index
* sprite/
* module.json
* index.js
* tilemap/
* module.json
* index.js
* sprite-editor/
* index.js
* ...
*/
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const rootDir = path.resolve(__dirname, '..');
const packagesDir = path.join(rootDir, 'packages');
const outputDir = path.join(packagesDir, 'editor-app', 'dist', 'engine');
/**
* Get all engine modules (packages with module.json)
* 获取所有引擎模块(带 module.json 的包)
*/
function getEngineModules() {
const modules = [];
let packages;
try {
packages = fs.readdirSync(packagesDir);
} catch {
console.error(`[copy-modules] Error: Cannot read packages directory: ${packagesDir}`);
return modules;
}
for (const pkg of packages) {
const pkgDir = path.join(packagesDir, pkg);
const moduleJsonPath = path.join(pkgDir, 'module.json');
// Skip if not a directory
try {
if (!fs.statSync(pkgDir).isDirectory()) continue;
} catch {
continue;
}
// Skip if no module.json
if (!fs.existsSync(moduleJsonPath)) continue;
try {
const moduleJson = JSON.parse(fs.readFileSync(moduleJsonPath, 'utf-8'));
// Only include if isEngineModule is not explicitly false
if (moduleJson.isEngineModule !== false) {
modules.push({
id: moduleJson.id || pkg,
name: moduleJson.name || `@esengine/${pkg}`,
displayName: moduleJson.displayName || pkg,
packageDir: pkgDir,
moduleJsonPath,
distPath: path.join(pkgDir, 'dist', 'index.js'),
editorPackage: moduleJson.editorPackage,
isCore: moduleJson.isCore || false,
category: moduleJson.category || 'Other'
});
}
} catch (err) {
console.warn(` ⚠ Warning: Failed to parse ${moduleJsonPath}: ${err.message}`);
}
}
return modules;
}
/**
* Copy a single runtime module to output directory
* 将单个运行时模块复制到输出目录
*/
function copyModule(module) {
const moduleOutputDir = path.join(outputDir, module.id);
// Create output directory
if (!fs.existsSync(moduleOutputDir)) {
fs.mkdirSync(moduleOutputDir, { recursive: true });
}
// Copy module.json
const destModuleJson = path.join(moduleOutputDir, 'module.json');
fs.copyFileSync(module.moduleJsonPath, destModuleJson);
// Copy dist/index.js if exists
// 如果存在则拷贝 dist/index.js
let hasRuntime = false;
let hasTypes = false;
let sizeKB = 'N/A';
if (fs.existsSync(module.distPath)) {
const destIndexJs = path.join(moduleOutputDir, 'index.js');
fs.copyFileSync(module.distPath, destIndexJs);
// Also copy source map if exists
// 如果存在则拷贝 source map
const sourceMapPath = module.distPath + '.map';
if (fs.existsSync(sourceMapPath)) {
fs.copyFileSync(sourceMapPath, destIndexJs + '.map');
}
const stats = fs.statSync(module.distPath);
sizeKB = (stats.size / 1024).toFixed(1);
hasRuntime = true;
}
// Copy type definitions (.d.ts) if exists
// 如果存在则拷贝类型定义文件 (.d.ts)
const typesPath = module.distPath.replace(/\.js$/, '.d.ts');
if (fs.existsSync(typesPath)) {
const destDts = path.join(moduleOutputDir, 'index.d.ts');
fs.copyFileSync(typesPath, destDts);
hasTypes = true;
}
return { hasRuntime, hasTypes, sizeKB };
}
/**
* Copy an editor package
* 复制编辑器包
*/
function copyEditorPackage(editorPackageName) {
// Extract package folder name from @esengine/xxx-editor
const match = editorPackageName.match(/@esengine\/(.+)/);
if (!match) return null;
const pkgName = match[1];
const pkgDir = path.join(packagesDir, pkgName);
const distPath = path.join(pkgDir, 'dist', 'index.js');
if (!fs.existsSync(distPath)) {
return null;
}
const editorOutputDir = path.join(outputDir, pkgName);
if (!fs.existsSync(editorOutputDir)) {
fs.mkdirSync(editorOutputDir, { recursive: true });
}
const destIndexJs = path.join(editorOutputDir, 'index.js');
fs.copyFileSync(distPath, destIndexJs);
// Copy source map if exists
const sourceMapPath = distPath + '.map';
if (fs.existsSync(sourceMapPath)) {
fs.copyFileSync(sourceMapPath, destIndexJs + '.map');
}
const stats = fs.statSync(distPath);
return {
name: pkgName,
sizeKB: (stats.size / 1024).toFixed(1)
};
}
/**
* Main function
*/
function main() {
console.log('\n📦 Copying engine modules to editor-app/dist/engine/\n');
// Ensure editor-app/dist exists
const editorDistDir = path.join(packagesDir, 'editor-app', 'dist');
if (!fs.existsSync(editorDistDir)) {
fs.mkdirSync(editorDistDir, { recursive: true });
}
// Clean and recreate output directory
if (fs.existsSync(outputDir)) {
fs.rmSync(outputDir, { recursive: true });
}
fs.mkdirSync(outputDir, { recursive: true });
// Get all engine modules
const modules = getEngineModules();
if (modules.length === 0) {
console.log(' No engine modules found.\n');
return;
}
// Collect editor packages
const editorPackages = new Set();
// Copy runtime modules
console.log('Runtime modules:');
const moduleInfos = [];
for (const module of modules) {
const { hasRuntime, hasTypes, sizeKB } = copyModule(module);
if (hasRuntime) {
const typesIndicator = hasTypes ? ' +types' : '';
console.log(`${module.id} (${sizeKB} KB${typesIndicator})`);
} else {
console.log(`${module.id} (config only)`);
}
moduleInfos.push({
id: module.id,
name: module.name,
displayName: module.displayName,
hasRuntime,
hasTypes,
editorPackage: module.editorPackage,
isCore: module.isCore,
category: module.category
});
if (module.editorPackage) {
editorPackages.add(module.editorPackage);
}
}
// Copy editor packages
if (editorPackages.size > 0) {
console.log('\nEditor packages:');
for (const editorPkg of editorPackages) {
const result = copyEditorPackage(editorPkg);
if (result) {
console.log(`${result.name} (${result.sizeKB} KB)`);
} else {
console.log(`${editorPkg} (not built)`);
}
}
}
// Create index.json with all module info
const indexData = {
version: '1.0.0',
generatedAt: new Date().toISOString(),
modules: moduleInfos
};
fs.writeFileSync(
path.join(outputDir, 'index.json'),
JSON.stringify(indexData, null, 2)
);
console.log(`\n✅ Copied ${modules.length} modules to dist/engine/`);
console.log(` Index file: dist/engine/index.json\n`);
}
// Run
main();