diff --git a/.github/workflows/release-editor.yml b/.github/workflows/release-editor.yml index 10059c11..8d3f4e5c 100644 --- a/.github/workflows/release-editor.yml +++ b/.github/workflows/release-editor.yml @@ -73,7 +73,8 @@ jobs: path: | packages/core/bin packages/editor-core/dist - key: ${{ runner.os }}-ts-build-${{ hashFiles('packages/core/src/**', 'packages/editor-core/src/**') }} + packages/behavior-tree/bin + key: ${{ runner.os }}-ts-build-${{ hashFiles('packages/core/src/**', 'packages/editor-core/src/**', 'packages/behavior-tree/src/**') }} restore-keys: | ${{ runner.os }}-ts-build- @@ -85,6 +86,11 @@ jobs: cd packages/editor-core npm run build + - name: Build behavior-tree package + run: | + cd packages/behavior-tree + npm run build + - name: Build Tauri app uses: tauri-apps/tauri-action@v0.5 env: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index aa5893b2..05139ef5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,30 +1,34 @@ -name: Release +name: Release NPM Packages on: workflow_dispatch: inputs: - dry_run: - description: 'Dry run (仅预览,不实际发布)' - type: boolean - default: false - required: false + package: + description: '选择要发布的包' + required: true + type: choice + options: + - core + - behavior-tree + version: + description: '版本号 (例如: 2.2.9 或 1.0.1)' + required: true + type: string permissions: contents: write - issues: write pull-requests: write id-token: write jobs: - release-core: - name: Release Core Package + release-package: + name: Release ${{ github.event.inputs.package }} Package runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 - persist-credentials: false token: ${{ secrets.GITHUB_TOKEN }} - name: Setup Node.js @@ -37,32 +41,54 @@ jobs: - name: Install dependencies run: npm ci - - name: Run tests + - name: Build core package (if needed) + if: ${{ github.event.inputs.package == 'behavior-tree' }} run: | cd packages/core + npm run build + + - name: Run tests + run: | + cd packages/${{ github.event.inputs.package }} npm run test:ci + - name: Update version + run: | + cd packages/${{ github.event.inputs.package }} + npm version ${{ github.event.inputs.version }} --no-git-tag-version + - name: Build package run: | - cd packages/core + cd packages/${{ github.event.inputs.package }} npm run build:npm - - name: Release (Dry Run) - if: ${{ github.event.inputs.dry_run == 'true' }} + - name: Publish to npm env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - NPM_TOKEN: ${{ secrets.NPM_TOKEN }} NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} run: | - cd packages/core - npx semantic-release --dry-run + cd packages/${{ github.event.inputs.package }}/dist + npm publish - - name: Release - if: ${{ github.event.inputs.dry_run != 'true' }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - NPM_TOKEN: ${{ secrets.NPM_TOKEN }} - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - run: | - cd packages/core - npx semantic-release + - name: Create Pull Request + uses: peter-evans/create-pull-request@v6 + with: + token: ${{ secrets.GITHUB_TOKEN }} + commit-message: "chore(${{ github.event.inputs.package }}): release v${{ github.event.inputs.version }}" + branch: release/${{ github.event.inputs.package }}-v${{ github.event.inputs.version }} + delete-branch: true + title: "chore(${{ github.event.inputs.package }}): Release v${{ github.event.inputs.version }}" + body: | + ## 🚀 Release v${{ github.event.inputs.version }} + + 此 PR 更新 `@esengine/${{ github.event.inputs.package }}` 包的版本号 + + ### 变更 + - ✅ 已发布到 npm: [@esengine/${{ github.event.inputs.package }}@${{ github.event.inputs.version }}](https://www.npmjs.com/package/@esengine/${{ github.event.inputs.package }}/v/${{ github.event.inputs.version }}) + - ✅ 更新 `packages/${{ github.event.inputs.package }}/package.json` → `${{ github.event.inputs.version }}` + + --- + *此 PR 由发布工作流自动创建* + labels: | + release + ${{ github.event.inputs.package }} + automated pr diff --git a/.releaserc.json b/.releaserc.json deleted file mode 100644 index 7b16f183..00000000 --- a/.releaserc.json +++ /dev/null @@ -1,58 +0,0 @@ -{ - "branches": ["master", "main"], - "plugins": [ - [ - "@semantic-release/commit-analyzer", - { - "preset": "angular", - "releaseRules": [ - { "type": "feat", "release": "minor" }, - { "type": "fix", "release": "patch" }, - { "type": "perf", "release": "patch" }, - { "type": "revert", "release": "patch" }, - { "type": "docs", "release": false }, - { "type": "chore", "release": false }, - { "type": "refactor", "release": "patch" }, - { "type": "test", "release": false }, - { "type": "build", "release": false }, - { "type": "ci", "release": false } - ] - } - ], - [ - "@semantic-release/release-notes-generator", - { - "preset": "angular", - "writerOpts": { - "commitsSort": ["subject", "scope"] - } - } - ], - [ - "@semantic-release/changelog", - { - "changelogFile": "CHANGELOG.md", - "changelogTitle": "# Changelog\n\nAll notable changes to this project will be documented in this file." - } - ], - [ - "@semantic-release/npm", - { - "npmPublish": false - } - ], - [ - "@semantic-release/git", - { - "assets": ["CHANGELOG.md", "package.json", "package-lock.json"], - "message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}" - } - ], - [ - "@semantic-release/github", - { - "assets": [] - } - ] - ] -} diff --git a/packages/behavior-tree/build-rollup.cjs b/packages/behavior-tree/build-rollup.cjs new file mode 100644 index 00000000..74b68205 --- /dev/null +++ b/packages/behavior-tree/build-rollup.cjs @@ -0,0 +1,128 @@ +const fs = require('fs'); +const path = require('path'); +const { execSync } = require('child_process'); + +console.log('🚀 使用 Rollup 构建npm包...'); + +async function main() { + try { + // 清理旧的dist目录 + if (fs.existsSync('./dist')) { + console.log('🧹 清理旧的构建文件...'); + execSync('rimraf ./dist', { stdio: 'inherit' }); + } + + // 执行Rollup构建 + console.log('📦 执行 Rollup 构建...'); + execSync('npx rollup -c rollup.config.cjs', { stdio: 'inherit' }); + + // 生成package.json + console.log('📋 生成 package.json...'); + generatePackageJson(); + + // 复制其他文件 + console.log('📁 复制必要文件...'); + copyFiles(); + + // 输出构建结果 + showBuildResults(); + + console.log('✅ 构建完成!'); + console.log('\n🚀 发布命令:'); + console.log('cd dist && npm publish'); + + } catch (error) { + console.error('❌ 构建失败:', error.message); + process.exit(1); + } +} + +function generatePackageJson() { + const sourcePackage = JSON.parse(fs.readFileSync('./package.json', 'utf8')); + + const distPackage = { + name: sourcePackage.name, + version: sourcePackage.version, + description: sourcePackage.description, + main: 'index.cjs', + module: 'index.mjs', + unpkg: 'index.umd.js', + types: 'index.d.ts', + exports: { + '.': { + import: './index.mjs', + require: './index.cjs', + types: './index.d.ts' + } + }, + files: [ + 'index.mjs', + 'index.mjs.map', + 'index.cjs', + 'index.cjs.map', + 'index.umd.js', + 'index.umd.js.map', + 'index.es5.js', + 'index.es5.js.map', + 'index.d.ts' + ], + keywords: [ + 'ecs', + 'behavior-tree', + 'ai', + 'game-ai', + 'entity-component-system', + 'typescript', + 'cocos-creator', + 'laya', + 'rollup' + ], + author: sourcePackage.author, + license: sourcePackage.license, + repository: sourcePackage.repository, + bugs: sourcePackage.bugs, + homepage: sourcePackage.homepage, + peerDependencies: sourcePackage.peerDependencies, + engines: { + node: '>=16.0.0' + }, + sideEffects: false + }; + + fs.writeFileSync('./dist/package.json', JSON.stringify(distPackage, null, 2)); +} + +function copyFiles() { + const filesToCopy = [ + // 如果有 README 或其他文件需要复制,可以在这里添加 + ]; + + filesToCopy.forEach(({ src, dest }) => { + if (fs.existsSync(src)) { + fs.copyFileSync(src, dest); + console.log(` ✓ 复制: ${path.basename(dest)}`); + } else { + console.log(` ⚠️ 文件不存在: ${src}`); + } + }); + + if (filesToCopy.length === 0) { + console.log(' ℹ️ 没有需要复制的文件'); + } +} + +function showBuildResults() { + const distDir = './dist'; + const files = ['index.mjs', 'index.cjs', 'index.umd.js', 'index.es5.js', 'index.d.ts']; + + console.log('\n📊 构建结果:'); + files.forEach(file => { + const filePath = path.join(distDir, file); + if (fs.existsSync(filePath)) { + const size = fs.statSync(filePath).size; + console.log(` ${file}: ${(size / 1024).toFixed(1)}KB`); + } + }); +} + +main().catch(console.error); diff --git a/packages/behavior-tree/package.json b/packages/behavior-tree/package.json index 8b680c61..699e2316 100644 --- a/packages/behavior-tree/package.json +++ b/packages/behavior-tree/package.json @@ -31,8 +31,10 @@ "build": "npm run build:ts", "build:watch": "tsc --watch", "rebuild": "npm run clean && npm run build", + "build:npm": "npm run build && node build-rollup.cjs", "test": "jest --config jest.config.cjs", - "test:watch": "jest --watch --config jest.config.cjs" + "test:watch": "jest --watch --config jest.config.cjs", + "test:ci": "jest --ci --coverage --config jest.config.cjs" }, "author": "yhh", "license": "MIT", @@ -40,10 +42,20 @@ "@esengine/ecs-framework": "^2.2.8" }, "devDependencies": { + "@babel/core": "^7.28.3", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.27.1", + "@babel/plugin-transform-optional-chaining": "^7.27.1", + "@babel/preset-env": "^7.28.3", + "@rollup/plugin-babel": "^6.0.4", + "@rollup/plugin-commonjs": "^28.0.3", + "@rollup/plugin-node-resolve": "^16.0.1", + "@rollup/plugin-terser": "^0.4.4", "@types/jest": "^29.5.14", "@types/node": "^20.19.17", "jest": "^29.7.0", "rimraf": "^5.0.0", + "rollup": "^4.42.0", + "rollup-plugin-dts": "^6.2.1", "ts-jest": "^29.4.0", "typescript": "^5.8.3" }, diff --git a/packages/behavior-tree/rollup.config.cjs b/packages/behavior-tree/rollup.config.cjs new file mode 100644 index 00000000..4c140502 --- /dev/null +++ b/packages/behavior-tree/rollup.config.cjs @@ -0,0 +1,186 @@ +const resolve = require('@rollup/plugin-node-resolve'); +const commonjs = require('@rollup/plugin-commonjs'); +const terser = require('@rollup/plugin-terser'); +const babel = require('@rollup/plugin-babel'); +const dts = require('rollup-plugin-dts').default; +const { readFileSync } = require('fs'); + +const pkg = JSON.parse(readFileSync('./package.json', 'utf8')); + +const banner = `/** + * @esengine/behavior-tree v${pkg.version} + * 完全ECS化的行为树系统 + * + * @author ${pkg.author} + * @license ${pkg.license} + */`; + +const external = ['@esengine/ecs-framework']; + +const commonPlugins = [ + resolve({ + browser: true, + preferBuiltins: false + }), + commonjs({ + include: /node_modules/ + }), + babel({ + babelHelpers: 'bundled', + exclude: 'node_modules/**', + extensions: ['.js', '.ts'] + }) +]; + +module.exports = [ + // ES模块构建 + { + input: 'bin/index.js', + output: { + file: 'dist/index.mjs', + format: 'es', + banner, + sourcemap: true, + exports: 'named' + }, + plugins: [ + ...commonPlugins, + terser({ + format: { + comments: /^!/ + } + }) + ], + external, + treeshake: { + moduleSideEffects: false, + propertyReadSideEffects: false, + unknownGlobalSideEffects: false + } + }, + + // CommonJS构建 + { + input: 'bin/index.js', + output: { + file: 'dist/index.cjs', + format: 'cjs', + banner, + sourcemap: true, + exports: 'named' + }, + plugins: [ + ...commonPlugins, + terser({ + format: { + comments: /^!/ + } + }) + ], + external, + treeshake: { + moduleSideEffects: false + } + }, + + // UMD构建 + { + input: 'bin/index.js', + output: { + file: 'dist/index.umd.js', + format: 'umd', + name: 'BehaviorTree', + banner, + sourcemap: true, + exports: 'named', + globals: { + '@esengine/ecs-framework': 'ECS' + } + }, + plugins: [ + ...commonPlugins, + terser({ + format: { + comments: /^!/ + } + }) + ], + external, + treeshake: { + moduleSideEffects: false + } + }, + + // ES5兼容构建 + { + input: 'bin/index.js', + output: { + file: 'dist/index.es5.js', + format: 'cjs', + banner: banner + '\n// ES5 Compatible Build for legacy JavaScript environments', + sourcemap: true, + exports: 'named' + }, + plugins: [ + resolve({ + browser: true, + preferBuiltins: false + }), + commonjs({ + include: /node_modules/ + }), + babel({ + babelHelpers: 'bundled', + exclude: 'node_modules/**', + extensions: ['.js', '.ts'], + presets: [ + ['@babel/preset-env', { + targets: { + browsers: ['ie >= 9', 'chrome >= 30', 'firefox >= 30', 'safari >= 8'] + }, + modules: false, + loose: true, + forceAllTransforms: true + }] + ], + plugins: [ + '@babel/plugin-transform-optional-chaining', + '@babel/plugin-transform-nullish-coalescing-operator' + ] + }), + terser({ + ecma: 5, + format: { + comments: /^!/ + }, + compress: { + drop_console: false, + drop_debugger: false + } + }) + ], + external, + treeshake: { + moduleSideEffects: false + } + }, + + // 类型定义构建 + { + input: 'bin/index.d.ts', + output: { + file: 'dist/index.d.ts', + format: 'es', + banner: `/** + * @esengine/behavior-tree v${pkg.version} + * TypeScript definitions + */` + }, + plugins: [ + dts({ + respectExternal: true + }) + ], + external: ['@esengine/ecs-framework'] + } +]; diff --git a/packages/core/.releaserc.json b/packages/core/.releaserc.json deleted file mode 100644 index f22ca108..00000000 --- a/packages/core/.releaserc.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "branches": ["master", "main"], - "tagFormat": "core-v${version}", - "plugins": [ - [ - "@semantic-release/commit-analyzer", - { - "preset": "angular", - "releaseRules": [ - { "type": "feat", "release": "minor" }, - { "type": "fix", "release": "patch" }, - { "type": "perf", "release": "patch" }, - { "type": "revert", "release": "patch" }, - { "type": "docs", "release": false }, - { "type": "chore", "release": false }, - { "type": "refactor", "release": "patch" }, - { "type": "test", "release": false }, - { "type": "build", "release": false }, - { "type": "ci", "release": false } - ], - "parserOpts": { - "noteKeywords": ["BREAKING CHANGE", "BREAKING CHANGES"] - } - } - ], - [ - "@semantic-release/release-notes-generator", - { - "preset": "angular", - "writerOpts": { - "commitsSort": ["subject", "scope"] - } - } - ], - [ - "@semantic-release/changelog", - { - "changelogFile": "CHANGELOG.md", - "changelogTitle": "# @esengine/ecs-framework Changelog\n\nAll notable changes to the core package will be documented in this file." - } - ], - [ - "@semantic-release/npm", - { - "pkgRoot": "dist", - "tarballDir": "release" - } - ], - [ - "@semantic-release/git", - { - "assets": ["CHANGELOG.md", "package.json", "package-lock.json"], - "message": "chore(core): release v${nextRelease.version} [skip ci]\n\n${nextRelease.notes}" - } - ], - [ - "@semantic-release/github", - { - "assets": [ - { - "path": "release/*.tgz", - "label": "npm package" - } - ] - } - ] - ] -} diff --git a/packages/core/package.json b/packages/core/package.json index cccdf9a3..5bea1e83 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -34,11 +34,6 @@ "build:watch": "tsc --watch", "rebuild": "npm run clean && npm run build", "build:npm": "npm run build && node build-rollup.cjs", - "publish:npm": "npm run build:npm && cd dist && npm publish", - "publish:patch": "npm version patch && npm run build:npm && cd dist && npm publish", - "publish:minor": "npm version minor && npm run build:npm && cd dist && npm publish", - "publish:major": "npm version major && npm run build:npm && cd dist && npm publish", - "preversion": "npm run rebuild", "test": "jest --config jest.config.cjs", "test:watch": "jest --watch --config jest.config.cjs", "test:performance": "jest --config jest.performance.config.cjs",