279 lines
7.6 KiB
JavaScript
279 lines
7.6 KiB
JavaScript
|
|
#!/usr/bin/env node
|
|||
|
|
|
|||
|
|
const esbuild = require('esbuild');
|
|||
|
|
const fs = require('fs');
|
|||
|
|
const path = require('path');
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* ECS Framework 单文件构建脚本
|
|||
|
|
* 专门用于npm包发布的单文件版本
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
const config = {
|
|||
|
|
// 输入配置
|
|||
|
|
entryPoint: './bin/index.js',
|
|||
|
|
|
|||
|
|
// 输出配置
|
|||
|
|
outputDir: './dist',
|
|||
|
|
outputFile: 'index.js',
|
|||
|
|
|
|||
|
|
// 压缩配置
|
|||
|
|
minify: true,
|
|||
|
|
sourcemap: true,
|
|||
|
|
|
|||
|
|
// 目标环境 - 适配更多平台
|
|||
|
|
target: ['es2017'],
|
|||
|
|
format: 'esm',
|
|||
|
|
|
|||
|
|
// npm包配置
|
|||
|
|
generatePackageJson: true,
|
|||
|
|
generateTypes: true
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
async function buildSingleFile() {
|
|||
|
|
console.log('🚀 构建单文件npm包...');
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
// 确保输出目录存在
|
|||
|
|
if (!fs.existsSync(config.outputDir)) {
|
|||
|
|
fs.mkdirSync(config.outputDir, { recursive: true });
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 第一步:使用esbuild打包
|
|||
|
|
console.log('📦 使用 esbuild 打包...');
|
|||
|
|
|
|||
|
|
const result = await esbuild.build({
|
|||
|
|
entryPoints: [config.entryPoint],
|
|||
|
|
bundle: true,
|
|||
|
|
minify: config.minify,
|
|||
|
|
sourcemap: config.sourcemap,
|
|||
|
|
target: config.target,
|
|||
|
|
format: config.format,
|
|||
|
|
outfile: path.join(config.outputDir, config.outputFile),
|
|||
|
|
platform: 'neutral', // 支持多平台
|
|||
|
|
|
|||
|
|
// 外部依赖
|
|||
|
|
external: [],
|
|||
|
|
|
|||
|
|
// 定义全局变量
|
|||
|
|
define: {
|
|||
|
|
'process.env.NODE_ENV': '"production"'
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 元信息
|
|||
|
|
metafile: true,
|
|||
|
|
|
|||
|
|
// 日志级别
|
|||
|
|
logLevel: 'info',
|
|||
|
|
|
|||
|
|
// 保持类名(便于调试)
|
|||
|
|
keepNames: true,
|
|||
|
|
|
|||
|
|
// 生成更兼容的代码
|
|||
|
|
legalComments: 'none'
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 显示打包结果
|
|||
|
|
if (result.metafile) {
|
|||
|
|
const analysis = await esbuild.analyzeMetafile(result.metafile);
|
|||
|
|
console.log('📊 打包分析:');
|
|||
|
|
console.log(analysis);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 第二步:生成类型定义文件
|
|||
|
|
if (config.generateTypes) {
|
|||
|
|
console.log('📝 生成类型定义文件...');
|
|||
|
|
await generateTypeDefinitions();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 第三步:生成package.json
|
|||
|
|
if (config.generatePackageJson) {
|
|||
|
|
console.log('📋 生成package.json...');
|
|||
|
|
await generatePackageJson();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 第四步:复制必要文件
|
|||
|
|
await copyEssentialFiles();
|
|||
|
|
|
|||
|
|
console.log('✅ 单文件构建完成!');
|
|||
|
|
console.log(`📄 主文件: ${path.join(config.outputDir, config.outputFile)}`);
|
|||
|
|
|
|||
|
|
// 显示文件大小
|
|||
|
|
const stats = fs.statSync(path.join(config.outputDir, config.outputFile));
|
|||
|
|
console.log(`📏 文件大小: ${(stats.size / 1024).toFixed(2)} KB`);
|
|||
|
|
|
|||
|
|
console.log('\n🚀 发布到npm:');
|
|||
|
|
console.log('cd dist && npm publish');
|
|||
|
|
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('❌ 构建失败:', error);
|
|||
|
|
process.exit(1);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 生成类型定义文件
|
|||
|
|
*/
|
|||
|
|
async function generateTypeDefinitions() {
|
|||
|
|
const sourceTypesFile = './bin/index.d.ts';
|
|||
|
|
const targetTypesFile = path.join(config.outputDir, 'index.d.ts');
|
|||
|
|
|
|||
|
|
if (fs.existsSync(sourceTypesFile)) {
|
|||
|
|
// 读取原始类型定义
|
|||
|
|
let typesContent = fs.readFileSync(sourceTypesFile, 'utf8');
|
|||
|
|
|
|||
|
|
// 处理相对路径导入,将其转换为绝对导入
|
|||
|
|
typesContent = typesContent.replace(/from ['"]\.\//g, "from './");
|
|||
|
|
typesContent = typesContent.replace(/from ['"]\.\.\//g, "from './");
|
|||
|
|
|
|||
|
|
// 添加版本信息注释
|
|||
|
|
const header = `/**
|
|||
|
|
* @esengine/ecs-framework
|
|||
|
|
* 高性能ECS框架 - 适用于Cocos Creator和Laya引擎
|
|||
|
|
* 版本: ${require('../package.json').version}
|
|||
|
|
* 构建时间: ${new Date().toISOString()}
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
`;
|
|||
|
|
|
|||
|
|
fs.writeFileSync(targetTypesFile, header + typesContent);
|
|||
|
|
console.log(` ✓ 生成: ${targetTypesFile}`);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 生成npm包的package.json
|
|||
|
|
*/
|
|||
|
|
async function generatePackageJson() {
|
|||
|
|
const sourcePackage = require('../package.json');
|
|||
|
|
|
|||
|
|
// 创建完全干净的package.json,只包含发布必需的字段
|
|||
|
|
const distPackage = {};
|
|||
|
|
|
|||
|
|
// 按顺序添加字段,确保没有任何开发相关字段
|
|||
|
|
distPackage.name = sourcePackage.name;
|
|||
|
|
distPackage.version = sourcePackage.version;
|
|||
|
|
distPackage.description = sourcePackage.description;
|
|||
|
|
distPackage.main = 'index.js';
|
|||
|
|
distPackage.types = 'index.d.ts';
|
|||
|
|
distPackage.module = 'index.js';
|
|||
|
|
distPackage.type = 'module';
|
|||
|
|
|
|||
|
|
// 导出配置
|
|||
|
|
distPackage.exports = {
|
|||
|
|
".": {
|
|||
|
|
"import": "./index.js",
|
|||
|
|
"types": "./index.d.ts"
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 文件配置
|
|||
|
|
distPackage.files = [
|
|||
|
|
'index.js',
|
|||
|
|
'index.js.map',
|
|||
|
|
'index.d.ts',
|
|||
|
|
'wasm/**/*',
|
|||
|
|
'README.md',
|
|||
|
|
'LICENSE'
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
// 关键词
|
|||
|
|
distPackage.keywords = [
|
|||
|
|
...sourcePackage.keywords,
|
|||
|
|
'single-file',
|
|||
|
|
'bundled',
|
|||
|
|
'minified'
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
// 元信息
|
|||
|
|
distPackage.author = sourcePackage.author;
|
|||
|
|
distPackage.license = sourcePackage.license;
|
|||
|
|
|
|||
|
|
// Repository信息
|
|||
|
|
distPackage.repository = {
|
|||
|
|
type: 'git',
|
|||
|
|
url: 'git+https://github.com/esengine/ecs-framework.git'
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 发布配置
|
|||
|
|
distPackage.publishConfig = {
|
|||
|
|
access: 'public'
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 引擎兼容性
|
|||
|
|
distPackage.engines = {
|
|||
|
|
node: '>=16.0.0'
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
const packagePath = path.join(config.outputDir, 'package.json');
|
|||
|
|
fs.writeFileSync(packagePath, JSON.stringify(distPackage, null, 2));
|
|||
|
|
console.log(` ✓ 生成: ${packagePath}`);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 复制必要文件
|
|||
|
|
*/
|
|||
|
|
async function copyEssentialFiles() {
|
|||
|
|
console.log('📁 复制必要文件...');
|
|||
|
|
|
|||
|
|
const filesToCopy = [
|
|||
|
|
{ src: '../README.md', dest: 'README.md' },
|
|||
|
|
{ src: '../LICENSE', dest: 'LICENSE', optional: true }
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
for (const file of filesToCopy) {
|
|||
|
|
const srcPath = path.resolve(file.src);
|
|||
|
|
const destPath = path.join(config.outputDir, file.dest);
|
|||
|
|
|
|||
|
|
if (fs.existsSync(srcPath)) {
|
|||
|
|
fs.copyFileSync(srcPath, destPath);
|
|||
|
|
console.log(` ✓ 复制: ${file.dest}`);
|
|||
|
|
} else if (!file.optional) {
|
|||
|
|
console.warn(` ⚠️ 文件不存在: ${srcPath}`);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 复制WASM文件
|
|||
|
|
await copyWasmFiles();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 复制WASM文件
|
|||
|
|
*/
|
|||
|
|
async function copyWasmFiles() {
|
|||
|
|
const wasmSrcDir = './bin/wasm';
|
|||
|
|
const wasmDestDir = path.join(config.outputDir, 'wasm');
|
|||
|
|
|
|||
|
|
if (fs.existsSync(wasmSrcDir)) {
|
|||
|
|
console.log('📦 复制WASM文件...');
|
|||
|
|
|
|||
|
|
// 创建目标目录
|
|||
|
|
if (!fs.existsSync(wasmDestDir)) {
|
|||
|
|
fs.mkdirSync(wasmDestDir, { recursive: true });
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 复制所有WASM相关文件
|
|||
|
|
const wasmFiles = fs.readdirSync(wasmSrcDir);
|
|||
|
|
for (const file of wasmFiles) {
|
|||
|
|
// 排除.gitignore文件
|
|||
|
|
if (file === '.gitignore') continue;
|
|||
|
|
|
|||
|
|
const srcPath = path.join(wasmSrcDir, file);
|
|||
|
|
const destPath = path.join(wasmDestDir, file);
|
|||
|
|
|
|||
|
|
if (fs.statSync(srcPath).isFile()) {
|
|||
|
|
fs.copyFileSync(srcPath, destPath);
|
|||
|
|
console.log(` ✓ 复制WASM: ${file}`);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
console.warn(' ⚠️ WASM目录不存在: ' + wasmSrcDir);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 运行构建
|
|||
|
|
if (require.main === module) {
|
|||
|
|
buildSingleFile();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
module.exports = { buildSingleFile, config };
|