@playcraft/devkit 1.0.31-beta.11 → 1.0.31-beta.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli/bin/playable-scripts.js +6 -53
- package/cli/commands/build.js +32 -241
- package/cli/commands/builds.js +2 -13
- package/cli/commands/dev.js +1 -22
- package/cli/commands/pack.js +40 -320
- package/cli/commands/vite-dev.js +1 -7
- package/core/artifacts/emit-fonts.test.js +1 -0
- package/core/artifacts/emit.js +4 -98
- package/core/artifacts/fflate.js +1 -31
- package/core/artifacts/zip.js +1 -39
- package/core/batch-build.js +147 -1261
- package/core/constants.js +2 -20
- package/core/cos-uploader.js +23 -289
- package/core/engines/cocos/adapter-vfs-path.test.js +1 -0
- package/core/engines/cocos/clean-cache.js +5 -179
- package/core/engines/cocos/clean-cache.test.js +1 -75
- package/core/engines/cocos/cli-build.js +2 -116
- package/core/engines/cocos/cli.js +11 -38
- package/core/engines/cocos/constants.js +1 -21
- package/core/engines/cocos/creator-cli.js +1 -108
- package/core/engines/cocos/dev-server.js +4 -412
- package/core/engines/cocos/fs.js +1 -105
- package/core/engines/cocos/injects/3x/init.js +19 -438
- package/core/engines/cocos/injects/3x/main.js +2 -52
- package/core/engines/cocos/injects/libs/pako.js +1 -2
- package/core/engines/cocos/mcp-refresh.js +2 -76
- package/core/engines/cocos/merge-inline.test.js +1 -0
- package/core/engines/cocos/merge.js +9 -148
- package/core/engines/cocos/omit-playable-weight.js +10 -0
- package/core/engines/cocos/omit-playable-weight.test.js +2 -0
- package/core/engines/cocos/pack.js +1 -187
- package/core/engines/cocos/preview-cache.js +2 -48
- package/core/engines/cocos/preview-cache.test.js +1 -32
- package/core/engines/cocos/preview-concat.js +6 -189
- package/core/engines/cocos/preview-concat.test.js +1 -73
- package/core/engines/cocos/preview-json-hook.js +1 -200
- package/core/engines/cocos/preview-json-pack.js +3 -376
- package/core/engines/cocos/preview-json-pack.test.js +2 -226
- package/core/engines/cocos/preview-proxy.js +1 -132
- package/core/engines/cocos/rebundle-preview.js +2 -54
- package/core/engines/cocos/strip-social-share.js +3 -115
- package/core/engines/cocos/theme-assets.js +2 -161
- package/core/engines/cocos/theme-levels.js +1 -0
- package/core/engines/cocos/writable-cli.js +2 -248
- package/core/engines/cocos/writable-cli.test.js +1 -112
- package/core/engines/web/index.js +1 -20
- package/core/engines/web/vite.dev.js +17 -322
- package/core/engines/web/webpack.build.js +37 -522
- package/core/engines/web/webpack.common.js +11 -177
- package/core/engines/web/webpack.dev.js +6 -88
- package/core/index.js +7 -101
- package/core/injectors/apply.js +1 -94
- package/core/injectors/check-channel-matrix.js +2 -130
- package/core/injectors/spec.js +10 -217
- package/core/loaders/gltf-loader.js +28 -74
- package/core/options.js +16 -353
- package/core/plugins/AdikteevInjectorPlugin.js +4 -26
- package/core/plugins/BigoAdsInjectorPlugin.js +4 -21
- package/core/plugins/DAPIInjectorPlugin.js +2 -25
- package/core/plugins/DebuggerInjectionPlugin.js +3 -31
- package/core/plugins/ExitAPIInjectorPlugin.js +3 -56
- package/core/plugins/FflateCompressionPlugin.js +160 -307
- package/core/plugins/FflateCompressionPlugin.test.js +13 -0
- package/core/plugins/FontInjectionWebpackPlugin.js +4 -46
- package/core/plugins/LiftoffInjectorPlugin.js +4 -26
- package/core/plugins/MRAIDInjectorPlugin.js +2 -24
- package/core/plugins/MintegralInjectorPlugin.js +2 -25
- package/core/plugins/PangleInjectorPlugin.js +2 -24
- package/core/plugins/PlaycraftOrientationInjectorPlugin.js +3 -29
- package/core/plugins/SnapchatInjectorPlugin.js +4 -26
- package/core/plugins/SocialMediaInjectorPlugin.js +7 -119
- package/core/plugins/TikTokInjectorPlugin.js +2 -24
- package/core/plugins/UnityInjectorPlugin.js +8 -37
- package/core/plugins/ZipPlugin.js +20 -154
- package/core/plugins/socialMediaVitePlugin.js +2 -108
- package/core/utils/buildDefines.js +2 -30
- package/core/utils/buildTemplateString.js +5 -39
- package/core/utils/date.js +1 -16
- package/core/utils/fontRegistry.js +13 -81
- package/core/utils/fontResolver.js +37 -335
- package/core/utils/generateAdikteevHtmlWebpackPluginConfig.js +8 -42
- package/core/utils/generateBigabidHtmlWebpackPluginConfig.js +3 -30
- package/core/utils/generateInMobiHtmlWebpackPluginConfig.js +7 -43
- package/core/utils/getPlaycraftOrientationSuffix.js +2 -9
- package/core/utils/injectSDKPlugins.js +13 -68
- package/core/utils/logOptions.js +5 -46
- package/core/utils/mergeOptions.js +2 -21
- package/core/utils/obfuscateLevels.js +14 -0
- package/core/utils/obfuscateLevels.test.js +10 -0
- package/core/utils/parseArgvOptions.js +5 -125
- package/core/utils/resolveChannelFold2Zip.js +3 -15
- package/core/utils/validateThemeData.js +26 -227
- package/core/validators/pre-build-checker.js +25 -287
- package/core/validators/tracking-validator.js +40 -441
- package/core/validators/tracking-validator.test.js +2 -84
- package/core/vite.dev.js +1 -1
- package/core/webpack.build.js +1 -1
- package/core/webpack.common.js +1 -1
- package/core/webpack.dev.js +1 -1
- package/package.json +2 -3
- package/README.md +0 -262
|
@@ -1,54 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
});
|
|
8
|
-
|
|
9
|
-
const spawn = require('cross-spawn');
|
|
10
|
-
|
|
11
|
-
const args = process.argv.slice(2);
|
|
12
|
-
|
|
13
|
-
const scriptIndex = args.findIndex((x) => x === 'build' || x === 'dev' || x === 'vite-dev' || x === 'builds' || x === 'pack');
|
|
14
|
-
|
|
15
|
-
const script = scriptIndex === -1 ? args[0] : args[scriptIndex];
|
|
16
|
-
const nodeArgs = scriptIndex > 0 ? args.slice(0, scriptIndex) : [];
|
|
17
|
-
|
|
18
|
-
if (['build', 'dev', 'vite-dev', 'builds', 'pack'].includes(script)) {
|
|
19
|
-
const result = spawn.sync(
|
|
20
|
-
process.execPath,
|
|
21
|
-
nodeArgs.concat(require.resolve('../commands/' + script)).concat(args.slice(scriptIndex + 1)),
|
|
22
|
-
{
|
|
23
|
-
stdio: 'inherit',
|
|
24
|
-
env: {
|
|
25
|
-
...process.env,
|
|
26
|
-
// 兜底:重度混淆(obfuscateLevel=4,controlFlowFlattening + deadCodeInjection
|
|
27
|
-
// + LimitChunkCountPlugin 单chunk)叠加较大规模源码时,单次 webpack 编译可能
|
|
28
|
-
// 占用数 GB 堆内存,默认的 V8 堆上限不足以支撑,会崩溃为
|
|
29
|
-
// "JavaScript heap out of memory"。此处提高上限做防御
|
|
30
|
-
// (不覆盖用户已自行设置的 NODE_OPTIONS)
|
|
31
|
-
NODE_OPTIONS: process.env.NODE_OPTIONS || '--max-old-space-size=8192'
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
);
|
|
35
|
-
if (result.signal) {
|
|
36
|
-
if (result.signal === 'SIGKILL') {
|
|
37
|
-
console.log(
|
|
38
|
-
'The build failed because the process exited too early. ' +
|
|
39
|
-
'This probably means the system ran out of memory or someone called ' +
|
|
40
|
-
'`kill -9` on the process.'
|
|
41
|
-
);
|
|
42
|
-
} else if (result.signal === 'SIGTERM') {
|
|
43
|
-
console.log(
|
|
44
|
-
'The build failed because the process exited too early. ' +
|
|
45
|
-
'Someone might have called `kill` or `killall`, or the system could ' +
|
|
46
|
-
'be shutting down.'
|
|
47
|
-
);
|
|
48
|
-
}
|
|
49
|
-
process.exit(1);
|
|
50
|
-
}
|
|
51
|
-
process.exit(result.status);
|
|
52
|
-
} else {
|
|
53
|
-
console.log('Unknown script "' + script + '".');
|
|
54
|
-
}
|
|
2
|
+
"use strict";process.on("unhandledRejection",err=>{throw err});const spawn=require("cross-spawn");const args=process.argv.slice(2);const scriptIndex=args.findIndex(x=>x==="build"||x==="dev"||x==="vite-dev"||x==="builds"||x==="pack");const script=scriptIndex===-1?args[0]:args[scriptIndex];const nodeArgs=scriptIndex>0?args.slice(0,scriptIndex):[];if(["build","dev","vite-dev","builds","pack"].includes(script)){const result=spawn.sync(process.execPath,nodeArgs.concat(require.resolve("../commands/"+script)).concat(args.slice(scriptIndex+1)),{stdio:"inherit",env:{...process.env,// 兜底:重度混淆(obfuscateLevel=4,controlFlowFlattening + deadCodeInjection
|
|
3
|
+
// + LimitChunkCountPlugin 单chunk)叠加较大规模源码时,单次 webpack 编译可能
|
|
4
|
+
// 占用数 GB 堆内存,默认的 V8 堆上限不足以支撑,会崩溃为
|
|
5
|
+
// "JavaScript heap out of memory"。此处提高上限做防御
|
|
6
|
+
// (不覆盖用户已自行设置的 NODE_OPTIONS)
|
|
7
|
+
NODE_OPTIONS:process.env.NODE_OPTIONS||"--max-old-space-size=8192"}});if(result.signal){if(result.signal==="SIGKILL"){console.log("The build failed because the process exited too early. "+"This probably means the system ran out of memory or someone called "+"`kill -9` on the process.")}else if(result.signal==="SIGTERM"){console.log("The build failed because the process exited too early. "+"Someone might have called `kill` or `killall`, or the system could "+"be shutting down.")}process.exit(1)}process.exit(result.status)}else{console.log("Unknown script \""+script+"\".")}
|
package/cli/commands/build.js
CHANGED
|
@@ -1,67 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
process.env.BABEL_ENV = 'production';
|
|
4
|
-
process.env.NODE_ENV = 'production';
|
|
5
|
-
|
|
6
|
-
const fs = require('fs');
|
|
7
|
-
const path = require('path');
|
|
8
|
-
const { runBuild } = require('../../core/webpack.build.js');
|
|
9
|
-
const { runThemeValidation, restoreSchema } = require('../../core/utils/validateThemeData');
|
|
10
|
-
const { runPreBuildChecks } = require('../../core/validators/pre-build-checker.js');
|
|
11
|
-
const { FontInjectionWebpackPlugin } = require('../../core/plugins/FontInjectionWebpackPlugin.js');
|
|
12
|
-
const { SocialMediaInjectorPlugin } = require('../../core/plugins/SocialMediaInjectorPlugin.js');
|
|
13
|
-
const { getPlaycraftOrientationSuffix } = require('../../core/utils/getPlaycraftOrientationSuffix.js');
|
|
14
|
-
const { options } = require('../../core/options.js');
|
|
15
|
-
const { isWebEngine } = require('../../core/utils/parseArgvOptions.js');
|
|
16
|
-
const { prepareCocosTemplate, emitCocosChannel } = require('../../core/engines/cocos/pack.js');
|
|
17
|
-
|
|
18
|
-
/**
|
|
1
|
+
"use strict";process.env.BABEL_ENV="production";process.env.NODE_ENV="production";const fs=require("fs");const path=require("path");const{runBuild}=require("../../core/webpack.build.js");const{runThemeValidation,restoreSchema}=require("../../core/utils/validateThemeData");const{runPreBuildChecks}=require("../../core/validators/pre-build-checker.js");const{FontInjectionWebpackPlugin}=require("../../core/plugins/FontInjectionWebpackPlugin.js");const{SocialMediaInjectorPlugin}=require("../../core/plugins/SocialMediaInjectorPlugin.js");const{getPlaycraftOrientationSuffix}=require("../../core/utils/getPlaycraftOrientationSuffix.js");const{options}=require("../../core/options.js");const{isWebEngine}=require("../../core/utils/parseArgvOptions.js");const{prepareCocosTemplate,emitCocosChannel}=require("../../core/engines/cocos/pack.js");/**
|
|
19
2
|
* 从主题入口文件中检测当前主题名称。
|
|
20
3
|
* 支持以下模式:
|
|
21
4
|
* export { default } from './themeName';
|
|
22
5
|
* import Theme from './themeName';
|
|
23
|
-
*/
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
if (fs.existsSync(buildsConfigPath)) {
|
|
30
|
-
try {
|
|
31
|
-
delete require.cache[buildsConfigPath];
|
|
32
|
-
const config = require(buildsConfigPath);
|
|
33
|
-
if (config.themes) {
|
|
34
|
-
themeConfig = { ...themeConfig, ...config.themes };
|
|
35
|
-
}
|
|
36
|
-
} catch (e) {
|
|
37
|
-
// 忽略错误
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const entryPath = path.join(projectRoot, themeConfig.entryFile);
|
|
42
|
-
if (!fs.existsSync(entryPath)) {
|
|
43
|
-
return { themeName: null, themeConfig };
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const content = fs.readFileSync(entryPath, 'utf8');
|
|
47
|
-
|
|
48
|
-
// 匹配: export { default } from './themeName' 或 import ... from './themeName'
|
|
49
|
-
const match = content.match(/from\s+['"]\.\/([^'"]+)['"]/);
|
|
50
|
-
if (match) {
|
|
51
|
-
return { themeName: match[1], themeConfig };
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
return { themeName: null, themeConfig };
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// --- 主流程 ---
|
|
58
|
-
const projectRoot = process.cwd();
|
|
59
|
-
const { themeName, themeConfig } = detectCurrentTheme(projectRoot);
|
|
60
|
-
|
|
61
|
-
let schemaPathToRestore = null;
|
|
62
|
-
let isExiting = false;
|
|
63
|
-
|
|
64
|
-
// ============================================================
|
|
6
|
+
*/function detectCurrentTheme(projectRoot){// 尝试加载 builds.config.js 获取主题配置
|
|
7
|
+
const buildsConfigPath=path.join(projectRoot,"builds.config.js");let themeConfig={sourceDir:"src/theme",entryFile:"src/theme/index.ts"};if(fs.existsSync(buildsConfigPath)){try{delete require.cache[buildsConfigPath];const config=require(buildsConfigPath);if(config.themes){themeConfig={...themeConfig,...config.themes}}}catch(e){// 忽略错误
|
|
8
|
+
}}const entryPath=path.join(projectRoot,themeConfig.entryFile);if(!fs.existsSync(entryPath)){return{themeName:null,themeConfig}}const content=fs.readFileSync(entryPath,"utf8");// 匹配: export { default } from './themeName' 或 import ... from './themeName'
|
|
9
|
+
const match=content.match(/from\s+['"]\.\/([^'"]+)['"]/);if(match){return{themeName:match[1],themeConfig}}return{themeName:null,themeConfig}}// --- 主流程 ---
|
|
10
|
+
const projectRoot=process.cwd();const{themeName,themeConfig}=detectCurrentTheme(projectRoot);let schemaPathToRestore=null;let isExiting=false;// ============================================================
|
|
65
11
|
// 📌 中断信号处理(Ctrl+C / kill)
|
|
66
12
|
// ============================================================
|
|
67
13
|
// 单主题构建过程中,theme.schema.json5 可能已被 runThemeValidation()
|
|
@@ -69,190 +15,35 @@ let isExiting = false;
|
|
|
69
15
|
// 避免文件被强制中断而遗留在“已覆写”状态。
|
|
70
16
|
// 注意:SIGKILL(kill -9)无法被捕获,属于无法规避的极端情况,
|
|
71
17
|
// 此时依赖 validateThemeData.js 中的兜底检测(下次构建自动识别并降级处理)。
|
|
72
|
-
function handleInterrupt() {
|
|
73
|
-
if (isExiting) return;
|
|
74
|
-
isExiting = true;
|
|
75
|
-
|
|
76
|
-
console.log('\n\x1b[33m收到中断信号,正在清理...\x1b[0m');
|
|
77
|
-
|
|
78
|
-
if (schemaPathToRestore) {
|
|
79
|
-
try {
|
|
80
|
-
restoreSchema(schemaPathToRestore);
|
|
81
|
-
console.log('\x1b[36m已恢复 theme.schema.json5\x1b[0m');
|
|
82
|
-
} catch (e) {
|
|
83
|
-
console.error(`\x1b[31m恢复 theme.schema.json5 失败: ${e.message}\x1b[0m`);
|
|
84
|
-
}
|
|
85
|
-
schemaPathToRestore = null;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
process.exit(1);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
process.on('SIGINT', handleInterrupt);
|
|
92
|
-
process.on('SIGTERM', handleInterrupt);
|
|
93
|
-
|
|
94
|
-
// ============================================================
|
|
18
|
+
function handleInterrupt(){if(isExiting)return;isExiting=true;console.log("\n\x1B[33m\u6536\u5230\u4E2D\u65AD\u4FE1\u53F7\uFF0C\u6B63\u5728\u6E05\u7406...\x1B[0m");if(schemaPathToRestore){try{restoreSchema(schemaPathToRestore);console.log("\x1B[36m\u5DF2\u6062\u590D theme.schema.json5\x1B[0m")}catch(e){console.error(`\x1b[31m恢复 theme.schema.json5 失败: ${e.message}\x1b[0m`)}schemaPathToRestore=null}process.exit(1)}process.on("SIGINT",handleInterrupt);process.on("SIGTERM",handleInterrupt);// ============================================================
|
|
95
19
|
// 📌 编译前检查(埋点验证等)
|
|
96
20
|
// ============================================================
|
|
97
21
|
// 支持通过环境变量控制是否跳过检查
|
|
98
22
|
// - SKIP_PRE_BUILD_CHECKS=1: 强制跳过检查
|
|
99
23
|
// - PLAYABLE_BATCH_MODE=1: 批量构建模式,子进程自动跳过检查(主进程已执行)
|
|
100
|
-
const isBatchMode
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
if (!checkResult.success) {
|
|
119
|
-
console.error('\n❌ 编译前检查失败,终止构建。');
|
|
120
|
-
console.error('提示:如需跳过检查,可设置环境变量: SKIP_PRE_BUILD_CHECKS=1\n');
|
|
121
|
-
process.exit(1);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// 执行编译前检查(异步)
|
|
126
|
-
runPreChecks().then(() => {
|
|
127
|
-
// 检查通过后继续原有流程
|
|
128
|
-
continueWithBuild();
|
|
129
|
-
}).catch((err) => {
|
|
130
|
-
console.error('\n❌ 编译前检查出错:', err);
|
|
131
|
-
process.exit(1);
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
function continueWithBuild() {
|
|
135
|
-
// 当前广告渠道(用于决定是否启用 social_media 的 OG meta 注入)
|
|
136
|
-
const adNetwork = options['network'] || '';
|
|
137
|
-
|
|
138
|
-
// In batch mode (PLAYABLE_BATCH_MODE=1), the parent process has already
|
|
139
|
-
// executed runThemeValidation and overwritten theme.schema.json5 with merged data.
|
|
140
|
-
// Running it again in child processes would cause a race condition:
|
|
141
|
-
// 1. Child reads the already-overwritten schema (pure data, no "properties"/"default")
|
|
142
|
-
// 2. extractDefaultsFromSchema returns {} (empty)
|
|
143
|
-
// 3. Child overwrites schema with {} → file becomes empty object
|
|
144
|
-
const isBatchMode = process.env.PLAYABLE_BATCH_MODE === '1';
|
|
145
|
-
|
|
146
|
-
if (themeName && !isBatchMode) {
|
|
147
|
-
const buildLog = (msg, level) => {
|
|
148
|
-
const colors = { info: '\x1b[36m', success: '\x1b[32m', error: '\x1b[31m' };
|
|
149
|
-
const reset = '\x1b[0m';
|
|
150
|
-
const color = colors[level] || '';
|
|
151
|
-
console.log(`${color}[build] ${msg}${reset}`);
|
|
152
|
-
};
|
|
153
|
-
|
|
154
|
-
const { valid, schemaPath } = runThemeValidation(themeName, projectRoot, themeConfig, { log: buildLog });
|
|
155
|
-
schemaPathToRestore = schemaPath;
|
|
156
|
-
|
|
157
|
-
if (!valid) {
|
|
158
|
-
// 校验失败时恢复 schema(备份可能已创建)
|
|
159
|
-
if (schemaPathToRestore) restoreSchema(schemaPathToRestore);
|
|
160
|
-
process.exit(1);
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
// ============================================================
|
|
165
|
-
// 📌 横竖屏方向多版本构建
|
|
166
|
-
// ============================================================
|
|
167
|
-
// playcraftOrientationChannel 中指定的渠道,需要按 playcraftOrientation
|
|
168
|
-
// 列出的每个方向版本分别打一个包(渠道_L / 渠道_P / 渠道,即 both 无后缀);
|
|
169
|
-
// 不在列表中的渠道始终只按 both(自适应)打一个包。
|
|
170
|
-
const orientationChannels = options['playcraftOrientationChannel'] || [];
|
|
171
|
-
const orientationVersions =
|
|
172
|
-
Array.isArray(options['playcraftOrientation']) && options['playcraftOrientation'].length > 0
|
|
173
|
-
? options['playcraftOrientation']
|
|
174
|
-
: ['both'];
|
|
175
|
-
const buildOrientations = orientationChannels.includes(adNetwork) ? orientationVersions : ['both'];
|
|
176
|
-
|
|
177
|
-
/**
|
|
24
|
+
const isBatchMode=process.env.PLAYABLE_BATCH_MODE==="1";const shouldSkipChecks=process.env.SKIP_PRE_BUILD_CHECKS==="1"||isBatchMode;async function runPreChecks(){if(shouldSkipChecks){console.log("\n\u26A0\uFE0F \u8DF3\u8FC7\u7F16\u8BD1\u524D\u68C0\u67E5\uFF08SKIP_PRE_BUILD_CHECKS=1\uFF09\n");return}const checkResult=await runPreBuildChecks(projectRoot,{verbose:false,showDetails:true,failFast:false,themes:themeName?[themeName]:undefined,channels:options["network"]?[options["network"]]:undefined,engine:options.engine});if(!checkResult.success){console.error("\n\u274C \u7F16\u8BD1\u524D\u68C0\u67E5\u5931\u8D25\uFF0C\u7EC8\u6B62\u6784\u5EFA\u3002");console.error("\u63D0\u793A\uFF1A\u5982\u9700\u8DF3\u8FC7\u68C0\u67E5\uFF0C\u53EF\u8BBE\u7F6E\u73AF\u5883\u53D8\u91CF: SKIP_PRE_BUILD_CHECKS=1\n");process.exit(1)}}// 执行编译前检查(异步)
|
|
25
|
+
runPreChecks().then(()=>{// 检查通过后继续原有流程
|
|
26
|
+
continueWithBuild()}).catch(err=>{console.error("\n\u274C \u7F16\u8BD1\u524D\u68C0\u67E5\u51FA\u9519:",err);process.exit(1)});function continueWithBuild(){// 当前广告渠道(用于决定是否启用 social_media 的 OG meta 注入)
|
|
27
|
+
const adNetwork=options["network"]||"";// In batch mode (PLAYABLE_BATCH_MODE=1), the parent process has already
|
|
28
|
+
// executed runThemeValidation and overwritten theme.schema.json5 with merged data.
|
|
29
|
+
// Running it again in child processes would cause a race condition:
|
|
30
|
+
// 1. Child reads the already-overwritten schema (pure data, no "properties"/"default")
|
|
31
|
+
// 2. extractDefaultsFromSchema returns {} (empty)
|
|
32
|
+
// 3. Child overwrites schema with {} → file becomes empty object
|
|
33
|
+
const isBatchMode=process.env.PLAYABLE_BATCH_MODE==="1";if(themeName&&!isBatchMode){const buildLog=(msg,level)=>{const colors={info:"\x1B[36m",success:"\x1B[32m",error:"\x1B[31m"};const reset="\x1B[0m";const color=colors[level]||"";console.log(`${color}[build] ${msg}${reset}`)};const{valid,schemaPath}=runThemeValidation(themeName,projectRoot,themeConfig,{log:buildLog});schemaPathToRestore=schemaPath;if(!valid){// 校验失败时恢复 schema(备份可能已创建)
|
|
34
|
+
if(schemaPathToRestore)restoreSchema(schemaPathToRestore);process.exit(1)}}// ============================================================
|
|
35
|
+
// 📌 横竖屏方向多版本构建
|
|
36
|
+
// ============================================================
|
|
37
|
+
// playcraftOrientationChannel 中指定的渠道,需要按 playcraftOrientation
|
|
38
|
+
// 列出的每个方向版本分别打一个包(渠道_L / 渠道_P / 渠道,即 both 无后缀);
|
|
39
|
+
// 不在列表中的渠道始终只按 both(自适应)打一个包。
|
|
40
|
+
const orientationChannels=options["playcraftOrientationChannel"]||[];const orientationVersions=Array.isArray(options["playcraftOrientation"])&&options["playcraftOrientation"].length>0?options["playcraftOrientation"]:["both"];const buildOrientations=orientationChannels.includes(adNetwork)?orientationVersions:["both"];/**
|
|
178
41
|
* 构建单个方向版本
|
|
179
|
-
*/
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
const fontPlugin = themeName
|
|
188
|
-
? new FontInjectionWebpackPlugin({ projectRoot, themeName, themeConfig })
|
|
189
|
-
: null;
|
|
190
|
-
|
|
191
|
-
// social_media 渠道:注入 OG / Twitter meta 标签,让 Facebook / LinkedIn
|
|
192
|
-
// 等抓取预览时拿到正确的标题/描述/图片。无 shareMeta 时空跑,不影响构建
|
|
193
|
-
const socialMediaPlugin = (themeName && adNetwork === 'social_media')
|
|
194
|
-
? new SocialMediaInjectorPlugin({ projectRoot, themeName, themeConfig })
|
|
195
|
-
: null;
|
|
196
|
-
|
|
197
|
-
if (!isWebEngine(options.engine)) {
|
|
198
|
-
await runCocosBuild({
|
|
199
|
-
playcraftOrientationValue: orientationValue,
|
|
200
|
-
filename: suffix ? `${options.filename}${suffix}` : options.filename,
|
|
201
|
-
themeName,
|
|
202
|
-
});
|
|
203
|
-
return;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
await runBuild(
|
|
207
|
-
undefined,
|
|
208
|
-
{
|
|
209
|
-
playcraftOrientationValue: orientationValue,
|
|
210
|
-
filename: suffix ? `${options.filename}${suffix}` : options.filename
|
|
211
|
-
},
|
|
212
|
-
undefined,
|
|
213
|
-
{
|
|
214
|
-
plugins: [
|
|
215
|
-
...(fontPlugin ? [fontPlugin] : []),
|
|
216
|
-
...(socialMediaPlugin ? [socialMediaPlugin] : []),
|
|
217
|
-
],
|
|
218
|
-
}
|
|
219
|
-
);
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
(async () => {
|
|
223
|
-
try {
|
|
224
|
-
if (!isWebEngine(options.engine)) {
|
|
225
|
-
const templateHtml = await prepareCocosTemplate({
|
|
226
|
-
playcraftOrientationValue: buildOrientations[0] || 'both',
|
|
227
|
-
});
|
|
228
|
-
for (const orientationValue of buildOrientations) {
|
|
229
|
-
const suffix = getPlaycraftOrientationSuffix(orientationValue);
|
|
230
|
-
if (buildOrientations.length > 1) {
|
|
231
|
-
console.log(`\n📱 开始构建方向版本: ${orientationValue}${suffix ? ` (后缀: ${suffix})` : ''}`);
|
|
232
|
-
}
|
|
233
|
-
await emitCocosChannel(templateHtml, {
|
|
234
|
-
playcraftOrientationValue: orientationValue,
|
|
235
|
-
filename: suffix ? `${options.filename}${suffix}` : options.filename,
|
|
236
|
-
themeName,
|
|
237
|
-
});
|
|
238
|
-
}
|
|
239
|
-
} else {
|
|
240
|
-
for (const orientationValue of buildOrientations) {
|
|
241
|
-
await buildOneOrientation(orientationValue);
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
if (schemaPathToRestore) restoreSchema(schemaPathToRestore);
|
|
246
|
-
|
|
247
|
-
// 主动退出进程,避免 TerserPlugin/webpack-obfuscator 等可能残留的
|
|
248
|
-
// worker 进程句柄(jest-worker 子进程 IPC 通道等)迟迟不释放,
|
|
249
|
-
// 导致本次 build 子进程(乃至上层 batch-build 的 spawn 等待)
|
|
250
|
-
// 迟迟无法结束。此时构建已全部完成,不再有需要等待的异步操作。
|
|
251
|
-
process.exit(0);
|
|
252
|
-
} catch (err) {
|
|
253
|
-
if (schemaPathToRestore) restoreSchema(schemaPathToRestore);
|
|
254
|
-
console.error(err);
|
|
255
|
-
process.exit(1);
|
|
256
|
-
}
|
|
257
|
-
})();
|
|
258
|
-
}
|
|
42
|
+
*/async function buildOneOrientation(orientationValue){const suffix=getPlaycraftOrientationSuffix(orientationValue);if(buildOrientations.length>1){console.log(`\n📱 开始构建方向版本: ${orientationValue}${suffix?` (后缀: ${suffix})`:""}`)}// 注入字体插件(build 模式 base64 内联)
|
|
43
|
+
const fontPlugin=themeName?new FontInjectionWebpackPlugin({projectRoot,themeName,themeConfig}):null;// social_media 渠道:注入 OG / Twitter meta 标签,让 Facebook / LinkedIn
|
|
44
|
+
// 等抓取预览时拿到正确的标题/描述/图片。无 shareMeta 时空跑,不影响构建
|
|
45
|
+
const socialMediaPlugin=themeName&&adNetwork==="social_media"?new SocialMediaInjectorPlugin({projectRoot,themeName,themeConfig}):null;if(!isWebEngine(options.engine)){await runCocosBuild({playcraftOrientationValue:orientationValue,filename:suffix?`${options.filename}${suffix}`:options.filename,themeName});return}await runBuild(undefined,{playcraftOrientationValue:orientationValue,filename:suffix?`${options.filename}${suffix}`:options.filename},undefined,{plugins:[...(fontPlugin?[fontPlugin]:[]),...(socialMediaPlugin?[socialMediaPlugin]:[])]})}(async()=>{try{if(!isWebEngine(options.engine)){const templateHtml=await prepareCocosTemplate({playcraftOrientationValue:buildOrientations[0]||"both"});for(const orientationValue of buildOrientations){const suffix=getPlaycraftOrientationSuffix(orientationValue);if(buildOrientations.length>1){console.log(`\n📱 开始构建方向版本: ${orientationValue}${suffix?` (后缀: ${suffix})`:""}`)}await emitCocosChannel(templateHtml,{playcraftOrientationValue:orientationValue,filename:suffix?`${options.filename}${suffix}`:options.filename,themeName})}}else{for(const orientationValue of buildOrientations){await buildOneOrientation(orientationValue)}}if(schemaPathToRestore)restoreSchema(schemaPathToRestore);// 主动退出进程,避免 TerserPlugin/webpack-obfuscator 等可能残留的
|
|
46
|
+
// worker 进程句柄(jest-worker 子进程 IPC 通道等)迟迟不释放,
|
|
47
|
+
// 导致本次 build 子进程(乃至上层 batch-build 的 spawn 等待)
|
|
48
|
+
// 迟迟无法结束。此时构建已全部完成,不再有需要等待的异步操作。
|
|
49
|
+
process.exit(0)}catch(err){if(schemaPathToRestore)restoreSchema(schemaPathToRestore);console.error(err);process.exit(1)}})()}
|
package/cli/commands/builds.js
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
'use strict';
|
|
4
|
-
|
|
5
|
-
/**
|
|
2
|
+
"use strict";/**
|
|
6
3
|
* Batch Builds Command for playable-scripts
|
|
7
4
|
*
|
|
8
5
|
* 支持:
|
|
@@ -16,12 +13,4 @@
|
|
|
16
13
|
* playable-scripts builds -c "google,facebook" # 指定渠道
|
|
17
14
|
* playable-scripts builds -t "theme1" -c "google" # 指定主题和渠道
|
|
18
15
|
* playable-scripts builds --parallel 3 # 设置并发数
|
|
19
|
-
*/
|
|
20
|
-
|
|
21
|
-
process.on('unhandledRejection', (err) => {
|
|
22
|
-
throw err;
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
const { buildBatch } = require('../../core/batch-build');
|
|
26
|
-
|
|
27
|
-
buildBatch();
|
|
16
|
+
*/process.on("unhandledRejection",err=>{throw err});const{buildBatch}=require("../../core/batch-build");buildBatch();
|
package/cli/commands/dev.js
CHANGED
|
@@ -1,22 +1 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
process.env.BABEL_ENV = 'development';
|
|
4
|
-
process.env.NODE_ENV = 'development';
|
|
5
|
-
|
|
6
|
-
const { options } = require('../../core/options.js');
|
|
7
|
-
const { isWebEngine } = require('../../core/utils/parseArgvOptions.js');
|
|
8
|
-
|
|
9
|
-
if (!isWebEngine(options.engine)) {
|
|
10
|
-
const { runCocosDev } = require('../../core/engines/cocos/dev-server.js');
|
|
11
|
-
runCocosDev({
|
|
12
|
-
projectRoot: process.cwd(),
|
|
13
|
-
port: process.env.PREVIEW_PORT || options.port || 3000,
|
|
14
|
-
cmd: process.argv[2] || 'start',
|
|
15
|
-
}).catch((err) => {
|
|
16
|
-
console.error(err);
|
|
17
|
-
process.exit(1);
|
|
18
|
-
});
|
|
19
|
-
} else {
|
|
20
|
-
const { runDev } = require('../../core/webpack.dev.js');
|
|
21
|
-
runDev();
|
|
22
|
-
}
|
|
1
|
+
"use strict";process.env.BABEL_ENV="development";process.env.NODE_ENV="development";const{options}=require("../../core/options.js");const{isWebEngine}=require("../../core/utils/parseArgvOptions.js");if(!isWebEngine(options.engine)){const{runCocosDev}=require("../../core/engines/cocos/dev-server.js");runCocosDev({projectRoot:process.cwd(),port:process.env.PREVIEW_PORT||options.port||3000,cmd:process.argv[2]||"start"}).catch(err=>{console.error(err);process.exit(1)})}else{const{runDev}=require("../../core/webpack.dev.js");runDev()}
|