@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.
Files changed (101) hide show
  1. package/cli/bin/playable-scripts.js +6 -53
  2. package/cli/commands/build.js +32 -241
  3. package/cli/commands/builds.js +2 -13
  4. package/cli/commands/dev.js +1 -22
  5. package/cli/commands/pack.js +40 -320
  6. package/cli/commands/vite-dev.js +1 -7
  7. package/core/artifacts/emit-fonts.test.js +1 -0
  8. package/core/artifacts/emit.js +4 -98
  9. package/core/artifacts/fflate.js +1 -31
  10. package/core/artifacts/zip.js +1 -39
  11. package/core/batch-build.js +147 -1261
  12. package/core/constants.js +2 -20
  13. package/core/cos-uploader.js +23 -289
  14. package/core/engines/cocos/adapter-vfs-path.test.js +1 -0
  15. package/core/engines/cocos/clean-cache.js +5 -179
  16. package/core/engines/cocos/clean-cache.test.js +1 -75
  17. package/core/engines/cocos/cli-build.js +2 -116
  18. package/core/engines/cocos/cli.js +11 -38
  19. package/core/engines/cocos/constants.js +1 -21
  20. package/core/engines/cocos/creator-cli.js +1 -108
  21. package/core/engines/cocos/dev-server.js +4 -412
  22. package/core/engines/cocos/fs.js +1 -105
  23. package/core/engines/cocos/injects/3x/init.js +19 -438
  24. package/core/engines/cocos/injects/3x/main.js +2 -52
  25. package/core/engines/cocos/injects/libs/pako.js +1 -2
  26. package/core/engines/cocos/mcp-refresh.js +2 -76
  27. package/core/engines/cocos/merge-inline.test.js +1 -0
  28. package/core/engines/cocos/merge.js +9 -148
  29. package/core/engines/cocos/omit-playable-weight.js +10 -0
  30. package/core/engines/cocos/omit-playable-weight.test.js +2 -0
  31. package/core/engines/cocos/pack.js +1 -187
  32. package/core/engines/cocos/preview-cache.js +2 -48
  33. package/core/engines/cocos/preview-cache.test.js +1 -32
  34. package/core/engines/cocos/preview-concat.js +6 -189
  35. package/core/engines/cocos/preview-concat.test.js +1 -73
  36. package/core/engines/cocos/preview-json-hook.js +1 -200
  37. package/core/engines/cocos/preview-json-pack.js +3 -376
  38. package/core/engines/cocos/preview-json-pack.test.js +2 -226
  39. package/core/engines/cocos/preview-proxy.js +1 -132
  40. package/core/engines/cocos/rebundle-preview.js +2 -54
  41. package/core/engines/cocos/strip-social-share.js +3 -115
  42. package/core/engines/cocos/theme-assets.js +2 -161
  43. package/core/engines/cocos/theme-levels.js +1 -0
  44. package/core/engines/cocos/writable-cli.js +2 -248
  45. package/core/engines/cocos/writable-cli.test.js +1 -112
  46. package/core/engines/web/index.js +1 -20
  47. package/core/engines/web/vite.dev.js +17 -322
  48. package/core/engines/web/webpack.build.js +37 -522
  49. package/core/engines/web/webpack.common.js +11 -177
  50. package/core/engines/web/webpack.dev.js +6 -88
  51. package/core/index.js +7 -101
  52. package/core/injectors/apply.js +1 -94
  53. package/core/injectors/check-channel-matrix.js +2 -130
  54. package/core/injectors/spec.js +10 -217
  55. package/core/loaders/gltf-loader.js +28 -74
  56. package/core/options.js +16 -353
  57. package/core/plugins/AdikteevInjectorPlugin.js +4 -26
  58. package/core/plugins/BigoAdsInjectorPlugin.js +4 -21
  59. package/core/plugins/DAPIInjectorPlugin.js +2 -25
  60. package/core/plugins/DebuggerInjectionPlugin.js +3 -31
  61. package/core/plugins/ExitAPIInjectorPlugin.js +3 -56
  62. package/core/plugins/FflateCompressionPlugin.js +160 -307
  63. package/core/plugins/FflateCompressionPlugin.test.js +13 -0
  64. package/core/plugins/FontInjectionWebpackPlugin.js +4 -46
  65. package/core/plugins/LiftoffInjectorPlugin.js +4 -26
  66. package/core/plugins/MRAIDInjectorPlugin.js +2 -24
  67. package/core/plugins/MintegralInjectorPlugin.js +2 -25
  68. package/core/plugins/PangleInjectorPlugin.js +2 -24
  69. package/core/plugins/PlaycraftOrientationInjectorPlugin.js +3 -29
  70. package/core/plugins/SnapchatInjectorPlugin.js +4 -26
  71. package/core/plugins/SocialMediaInjectorPlugin.js +7 -119
  72. package/core/plugins/TikTokInjectorPlugin.js +2 -24
  73. package/core/plugins/UnityInjectorPlugin.js +8 -37
  74. package/core/plugins/ZipPlugin.js +20 -154
  75. package/core/plugins/socialMediaVitePlugin.js +2 -108
  76. package/core/utils/buildDefines.js +2 -30
  77. package/core/utils/buildTemplateString.js +5 -39
  78. package/core/utils/date.js +1 -16
  79. package/core/utils/fontRegistry.js +13 -81
  80. package/core/utils/fontResolver.js +37 -335
  81. package/core/utils/generateAdikteevHtmlWebpackPluginConfig.js +8 -42
  82. package/core/utils/generateBigabidHtmlWebpackPluginConfig.js +3 -30
  83. package/core/utils/generateInMobiHtmlWebpackPluginConfig.js +7 -43
  84. package/core/utils/getPlaycraftOrientationSuffix.js +2 -9
  85. package/core/utils/injectSDKPlugins.js +13 -68
  86. package/core/utils/logOptions.js +5 -46
  87. package/core/utils/mergeOptions.js +2 -21
  88. package/core/utils/obfuscateLevels.js +14 -0
  89. package/core/utils/obfuscateLevels.test.js +10 -0
  90. package/core/utils/parseArgvOptions.js +5 -125
  91. package/core/utils/resolveChannelFold2Zip.js +3 -15
  92. package/core/utils/validateThemeData.js +26 -227
  93. package/core/validators/pre-build-checker.js +25 -287
  94. package/core/validators/tracking-validator.js +40 -441
  95. package/core/validators/tracking-validator.test.js +2 -84
  96. package/core/vite.dev.js +1 -1
  97. package/core/webpack.build.js +1 -1
  98. package/core/webpack.common.js +1 -1
  99. package/core/webpack.dev.js +1 -1
  100. package/package.json +2 -3
  101. package/README.md +0 -262
@@ -1,177 +1,11 @@
1
- const path = require('path');
2
- const fs = require('fs');
3
- const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
4
- const { VueLoaderPlugin } = require('vue-loader');
5
- const { options } = require('../../options');
6
-
7
- const tsConfigPath = path.resolve(options.tsConfig);
8
- const jsConfigPath = path.resolve(options.jsConfig);
9
- let jsTsConfigPath = null;
10
- if (fs.existsSync(tsConfigPath)) {
11
- jsTsConfigPath = tsConfigPath;
12
- } else if (fs.existsSync(jsConfigPath)) {
13
- jsTsConfigPath = jsConfigPath;
14
- }
15
-
16
- /** @type {string[]} List of file extensions that webpack will resolve */
17
- const allowedExtensions = [
18
- '.vue',
19
- '.ts',
20
- '.tsx',
21
- '.js',
22
- '.json',
23
- '.json5',
24
- '.png',
25
- '.glb',
26
- '.fbx',
27
- '.obj',
28
- '.jpg',
29
- '.webp',
30
- '.mp3',
31
- '.svg',
32
- '.xml',
33
- '.atlas',
34
- '.fnt',
35
- '.css',
36
- '.gif',
37
- '.mp4',
38
- '.woff',
39
- '.woff2',
40
- '.ttf',
41
- '.otf'
42
- ];
43
-
44
- /** @type {import('webpack').Configuration} Base webpack configuration used by both development and build configs */
45
- const webpackConfig = {
46
- entry: path.resolve('src/index'),
47
- resolve: {
48
- extensions: allowedExtensions,
49
- alias: {
50
- assets: path.resolve('assets'),
51
- vue: 'vue/dist/vue.esm-bundler.js',
52
- '@': path.resolve('src'),
53
- },
54
- plugins: jsTsConfigPath
55
- ? [
56
- new TsconfigPathsPlugin({
57
- configFile: jsTsConfigPath,
58
- extensions: allowedExtensions
59
- })
60
- ]
61
- : []
62
- },
63
- output: {
64
- filename: 'build.js',
65
- path: path.resolve('dist')
66
- },
67
- module: {
68
- rules: [
69
- // Vue 单文件组件
70
- {
71
- test: /\.vue$/,
72
- loader: 'vue-loader'
73
- },
74
- // {
75
- // test: /\.tsx?$/,
76
- // use: 'ts-loader',
77
- // exclude: /node_modules/,
78
- // },
79
- {
80
- test: /\.ts?$/,
81
- exclude: /node_modules/,
82
- use: [
83
- {
84
- loader: 'babel-loader',
85
- options: {
86
- // presets: ['@babel/preset-env'],
87
- plugins:
88
- options.compilation.allowTemplateLiterals === false ? ['@babel/plugin-transform-template-literals'] : []
89
- }
90
- },
91
-
92
- {
93
- loader: 'esbuild-loader',
94
- options: {
95
- loader: 'ts',
96
- target: 'es2015'
97
- }
98
- }
99
- ]
100
- },
101
- {
102
- test: /\.css$/,
103
- use: ['style-loader', 'css-loader']
104
- },
105
- {
106
- test: /\.(js|mjs)$/,
107
- // exclude: /node_modules/,
108
- use: {
109
- loader: 'babel-loader',
110
- options: {
111
- // presets: ['@babel/preset-env'],
112
- plugins: options.compilation.allowTemplateLiterals === false ? ['@babel/plugin-transform-template-literals'] : []
113
- }
114
- }
115
- },
116
- {
117
- test: /\.(gltf)$/,
118
- loader: path.join(__dirname, '../../loaders/gltf-loader.js')
119
- },
120
- {
121
- test: /\.(gif|png|jpe?g|webp|mp3|mpeg|mp4|m4a|ogg|wav|glb|fbx|obj)$/i,
122
- type: 'asset/inline'
123
- },
124
- {
125
- test: /\.json5$/i,
126
- type: 'javascript/auto',
127
- use: {
128
- loader: 'json5-loader',
129
- options: {
130
- esModule: false
131
- }
132
- }
133
- },
134
- // 处理 json?url → base64
135
- {
136
- test: /\.json$/i,
137
- resourceQuery: /url/,
138
- type: 'asset/inline',
139
- generator: {
140
- dataUrl: (content) => `data:application/json;base64,${content.toString('base64')}`
141
- }
142
- },
143
- {
144
- test: /\.(svg|xml)$/i,
145
- type: 'asset/source'
146
- },
147
- {
148
- test: /\.atlas$/,
149
- type: 'asset/inline',
150
- generator: {
151
- dataUrl: (content) => {
152
- return `data:text/atlas;base64,${content.toString('base64')}`;
153
- }
154
- }
155
- },
156
- {
157
- test: /\.fnt$/i,
158
- type: 'asset/inline',
159
- generator: {
160
- dataUrl: (content) => {
161
- return `data:text/plain;base64,${content.toString('base64')}`;
162
- }
163
- }
164
- },
165
- {
166
- test: /\.(woff|woff2|eot|ttf|otf)$/i,
167
- type: 'asset/inline'
168
- }
169
- ]
170
- },
171
- plugins: [
172
- new VueLoaderPlugin()
173
- ]
174
- };
175
-
176
- exports.allowedExtensions = allowedExtensions;
177
- exports.webpackCommonConfig = webpackConfig;
1
+ "use strict";const path=require("path");const fs=require("fs");const TsconfigPathsPlugin=require("tsconfig-paths-webpack-plugin");const{VueLoaderPlugin}=require("vue-loader");const{options}=require("../../options");const tsConfigPath=path.resolve(options.tsConfig);const jsConfigPath=path.resolve(options.jsConfig);let jsTsConfigPath=null;if(fs.existsSync(tsConfigPath)){jsTsConfigPath=tsConfigPath}else if(fs.existsSync(jsConfigPath)){jsTsConfigPath=jsConfigPath}/** @type {string[]} List of file extensions that webpack will resolve */const allowedExtensions=[".vue",".ts",".tsx",".js",".json",".json5",".png",".glb",".fbx",".obj",".jpg",".webp",".mp3",".svg",".xml",".atlas",".fnt",".css",".gif",".mp4",".woff",".woff2",".ttf",".otf"];/** @type {import('webpack').Configuration} Base webpack configuration used by both development and build configs */const webpackConfig={entry:path.resolve("src/index"),resolve:{extensions:allowedExtensions,alias:{assets:path.resolve("assets"),vue:"vue/dist/vue.esm-bundler.js","@":path.resolve("src")},plugins:jsTsConfigPath?[new TsconfigPathsPlugin({configFile:jsTsConfigPath,extensions:allowedExtensions})]:[]},output:{filename:"build.js",path:path.resolve("dist")},module:{rules:[// Vue 单文件组件
2
+ {test:/\.vue$/,loader:"vue-loader"},// {
3
+ // test: /\.tsx?$/,
4
+ // use: 'ts-loader',
5
+ // exclude: /node_modules/,
6
+ // },
7
+ {test:/\.ts?$/,exclude:/node_modules/,use:[{loader:"babel-loader",options:{// presets: ['@babel/preset-env'],
8
+ plugins:options.compilation.allowTemplateLiterals===false?["@babel/plugin-transform-template-literals"]:[]}},{loader:"esbuild-loader",options:{loader:"ts",target:"es2015"}}]},{test:/\.css$/,use:["style-loader","css-loader"]},{test:/\.(js|mjs)$/,// exclude: /node_modules/,
9
+ use:{loader:"babel-loader",options:{// presets: ['@babel/preset-env'],
10
+ plugins:options.compilation.allowTemplateLiterals===false?["@babel/plugin-transform-template-literals"]:[]}}},{test:/\.(gltf)$/,loader:path.join(__dirname,"../../loaders/gltf-loader.js")},{test:/\.(gif|png|jpe?g|webp|mp3|mpeg|mp4|m4a|ogg|wav|glb|fbx|obj)$/i,type:"asset/inline"},{test:/\.json5$/i,type:"javascript/auto",use:{loader:"json5-loader",options:{esModule:false}}},// 处理 json?url → base64
11
+ {test:/\.json$/i,resourceQuery:/url/,type:"asset/inline",generator:{dataUrl:content=>`data:application/json;base64,${content.toString("base64")}`}},{test:/\.(svg|xml)$/i,type:"asset/source"},{test:/\.atlas$/,type:"asset/inline",generator:{dataUrl:content=>{return`data:text/atlas;base64,${content.toString("base64")}`}}},{test:/\.fnt$/i,type:"asset/inline",generator:{dataUrl:content=>{return`data:text/plain;base64,${content.toString("base64")}`}}},{test:/\.(woff|woff2|eot|ttf|otf)$/i,type:"asset/inline"}]},plugins:[new VueLoaderPlugin]};exports.allowedExtensions=allowedExtensions;exports.webpackCommonConfig=webpackConfig;
@@ -1,98 +1,16 @@
1
- const { merge } = require('webpack-merge');
2
- const webpack = require('webpack');
3
- const HtmlWebpackPlugin = require('html-webpack-plugin');
4
- const WebpackDevServer = require('webpack-dev-server');
5
- const { webpackCommonConfig } = require('./webpack.common.js');
6
- const path = require('path');
7
- const { DebuggerInjectionPlugin } = require('../../plugins/DebuggerInjectionPlugin.js');
8
- const { options } = require('../../options.js');
9
- const { mergeOptions } = require('../../utils/mergeOptions.js');
10
- const { buildDefines } = require('../../utils/buildDefines.js');
11
- const { logOptions } = require('../../utils/logOptions.js');
12
- const { injectSDKPlugins } = require('../../utils/injectSDKPlugins.js');
13
- const { PlaycraftOrientationInjectorPlugin } = require('../../plugins/PlaycraftOrientationInjectorPlugin.js');
14
-
15
- /**
1
+ "use strict";const{merge}=require("webpack-merge");const webpack=require("webpack");const HtmlWebpackPlugin=require("html-webpack-plugin");const WebpackDevServer=require("webpack-dev-server");const{webpackCommonConfig}=require("./webpack.common.js");const path=require("path");const{DebuggerInjectionPlugin}=require("../../plugins/DebuggerInjectionPlugin.js");const{options}=require("../../options.js");const{mergeOptions}=require("../../utils/mergeOptions.js");const{buildDefines}=require("../../utils/buildDefines.js");const{logOptions}=require("../../utils/logOptions.js");const{injectSDKPlugins}=require("../../utils/injectSDKPlugins.js");const{PlaycraftOrientationInjectorPlugin}=require("../../plugins/PlaycraftOrientationInjectorPlugin.js");/**
16
2
  * Creates webpack configuration for development
17
3
  * @param {Partial<import('./index').CLIOptions>} [customOptions] - Custom options to merge with default options
18
4
  * @param {Record<string, any>} [customDefines] - Additional defines for webpack.DefinePlugin
19
5
  * @param {import('webpack').Configuration} [webpackCustomConfig] - Custom webpack config to merge
20
6
  * @returns {import('webpack').Configuration} Final webpack development configuration
21
- */
22
- function makeWebpackDevConfig(customOptions, customDefines, webpackCustomConfig) {
23
- const devOptions = mergeOptions(options, customOptions);
24
- logOptions(devOptions)
25
- customDefines = customDefines || {};
26
- webpackCustomConfig = webpackCustomConfig || {};
27
-
28
- /** @type {'both'|'landscape'|'portrait'} */
29
- const playcraftOrientationValue = devOptions.playcraftOrientationValue || 'both';
30
-
31
- const webpackConfig = merge(
32
- webpackCommonConfig,
33
- {
34
- mode: 'development',
35
- devtool: 'inline-source-map',
36
- devServer: {
37
- static: {
38
- directory: path.resolve('dist')
39
- },
40
- hot: true,
41
- // compress: true,
42
- port: devOptions['port'],
43
- allowedHosts: 'all',
44
- open: devOptions['open']
45
- },
46
- plugins: [
47
- new HtmlWebpackPlugin({
48
- template: path.resolve('src/index.html'),
49
- inlineSource: '.(js|css|png|jpg|webp|svg|xml|atlas|mp3|gif|glb|fbx|obj)$',
50
- meta: {
51
- viewport: 'width=device-width,initial-scale=1.0,viewport-fit=cover,maximum-scale=1.0,user-scalable=no'
52
- }
53
- }),
54
- // 注入 window.playcraftOrientation 全局变量,标识当前构建产物对应的横竖屏方向版本
55
- new PlaycraftOrientationInjectorPlugin(playcraftOrientationValue),
56
-
57
- new webpack.DefinePlugin({
58
- ...buildDefines(devOptions),
59
- ...devOptions.defines,
60
- __DEV__: JSON.stringify(devOptions['dev'] === undefined ? true : devOptions['dev']),
61
- ...customDefines
62
- })
63
- ]
64
- },
65
- webpackCustomConfig
66
- );
67
-
68
- if (devOptions['debugger']) {
69
- webpackConfig.plugins.push(new DebuggerInjectionPlugin(devOptions['debugger']));
70
- }
71
-
72
- // 注入渠道 SDK 插件(与 build 保持一致)
73
- injectSDKPlugins(webpackConfig, {
74
- network: devOptions['network'],
75
- protocol: devOptions['protocol'],
76
- playcraftOrientationValue
77
- });
78
-
79
- return webpackConfig;
80
- }
81
-
82
- /**
7
+ */function makeWebpackDevConfig(customOptions,customDefines,webpackCustomConfig){const devOptions=mergeOptions(options,customOptions);logOptions(devOptions);customDefines=customDefines||{};webpackCustomConfig=webpackCustomConfig||{};/** @type {'both'|'landscape'|'portrait'} */const playcraftOrientationValue=devOptions.playcraftOrientationValue||"both";const webpackConfig=merge(webpackCommonConfig,{mode:"development",devtool:"inline-source-map",devServer:{static:{directory:path.resolve("dist")},hot:true,// compress: true,
8
+ port:devOptions["port"],allowedHosts:"all",open:devOptions["open"]},plugins:[new HtmlWebpackPlugin({template:path.resolve("src/index.html"),inlineSource:".(js|css|png|jpg|webp|svg|xml|atlas|mp3|gif|glb|fbx|obj)$",meta:{viewport:"width=device-width,initial-scale=1.0,viewport-fit=cover,maximum-scale=1.0,user-scalable=no"}}),// 注入 window.playcraftOrientation 全局变量,标识当前构建产物对应的横竖屏方向版本
9
+ new PlaycraftOrientationInjectorPlugin(playcraftOrientationValue),new webpack.DefinePlugin({...buildDefines(devOptions),...devOptions.defines,__DEV__:JSON.stringify(devOptions["dev"]===undefined?true:devOptions["dev"]),...customDefines})]},webpackCustomConfig);if(devOptions["debugger"]){webpackConfig.plugins.push(new DebuggerInjectionPlugin(devOptions["debugger"]))}// 注入渠道 SDK 插件(与 build 保持一致)
10
+ injectSDKPlugins(webpackConfig,{network:devOptions["network"],protocol:devOptions["protocol"],playcraftOrientationValue});return webpackConfig}/**
83
11
  * Starts webpack development server
84
12
  * @param {import('webpack').Configuration} [webpackConfig] - Webpack configuration to use, creates default if not provided
85
13
  * @param {Partial<import('./index').CLIOptions>} [customOptions] - Custom options to merge with default options
86
14
  * @param {Record<string, any>} [customDefines] - Additional defines for webpack.DefinePlugin
87
15
  * @param {import('webpack').Configuration} [webpackCustomConfig] - Custom webpack config to merge
88
- */
89
- function runDev(webpackConfig, customOptions, customDefines, webpackCustomConfig) {
90
- if (!webpackConfig) webpackConfig = makeWebpackDevConfig(customOptions, customDefines, webpackCustomConfig);
91
-
92
- const compiler = webpack(webpackConfig);
93
- const server = new WebpackDevServer(webpackConfig.devServer, compiler);
94
- server.start();
95
- }
96
-
97
- exports.makeWebpackDevConfig = makeWebpackDevConfig;
98
- exports.runDev = runDev;
16
+ */function runDev(webpackConfig,customOptions,customDefines,webpackCustomConfig){if(!webpackConfig)webpackConfig=makeWebpackDevConfig(customOptions,customDefines,webpackCustomConfig);const compiler=webpack(webpackConfig);const server=new WebpackDevServer(webpackConfig.devServer,compiler);server.start()}exports.makeWebpackDevConfig=makeWebpackDevConfig;exports.runDev=runDev;
package/core/index.js CHANGED
@@ -1,101 +1,7 @@
1
- const { allowedExtensions, webpackCommonConfig } = require('./webpack.common.js');
2
- const { parseArgvOptions } = require('./utils/parseArgvOptions.js');
3
- const { mergeOptions } = require('./utils/mergeOptions.js');
4
- const { options } = require('./options.js');
5
- const { DAPIInjectorPlugin } = require('./plugins/DAPIInjectorPlugin.js');
6
- const { DebuggerInjectionPlugin } = require('./plugins/DebuggerInjectionPlugin.js');
7
- const { ExitAPIInjectorPlugin } = require('./plugins/ExitAPIInjectorPlugin.js');
8
- const { runBuild, makeWebpackBuildConfig } = require('./webpack.build.js');
9
- const { runDev, makeWebpackDevConfig } = require('./webpack.dev.js');
10
- const { runViteDev, makeViteDevConfig, json5Plugin, assetInlinePlugin, fontFamilyPlugin } = require('./vite.dev.js');
11
-
12
- // 字体注入
13
- const { FontInjectionWebpackPlugin } = require('./plugins/FontInjectionWebpackPlugin.js');
14
- const { FONT_REGISTRY, getRegisteredFontKeys, isBuiltin: isBuiltinFont, getFontEntry } = require('./utils/fontRegistry.js');
15
- const { getOrGenerateFontCSS } = require('./utils/fontResolver.js');
16
-
17
- // 验证器
18
- const {
19
- runPreBuildChecks,
20
- runTrackingCheck,
21
- registerChecker,
22
- toggleChecker,
23
- listCheckers
24
- } = require('./validators/pre-build-checker.js');
25
-
26
- const {
27
- validateTracking,
28
- printValidationResult,
29
- TRACKING_METHODS,
30
- SDK_TO_TRACKING_MAP
31
- } = require('./validators/tracking-validator.js');
32
-
33
- exports.mergeOptions = mergeOptions;
34
- exports.parseArgvOptions = parseArgvOptions;
35
-
36
- exports.options = options;
37
-
38
- exports.allowedExtensions = allowedExtensions;
39
- exports.webpackCommonConfig = webpackCommonConfig;
40
- exports.makeWebpackDevConfig = makeWebpackDevConfig;
41
- exports.makeWebpackBuildConfig = makeWebpackBuildConfig;
42
- exports.runDev = runDev;
43
- exports.runBuild = runBuild;
44
-
45
- exports.DAPIInjectorPlugin = DAPIInjectorPlugin;
46
- exports.ExitAPIInjectorPlugin = ExitAPIInjectorPlugin;
47
- exports.DebuggerInjectionPlugin = DebuggerInjectionPlugin;
48
-
49
- exports.makeViteDevConfig = makeViteDevConfig;
50
- exports.runViteDev = runViteDev;
51
-
52
- // 公共 Vite 插件(供项目 vite.config.ts 直接引用)
53
- exports.json5Plugin = json5Plugin;
54
- exports.assetInlinePlugin = assetInlinePlugin;
55
- exports.fontFamilyPlugin = fontFamilyPlugin;
56
-
57
- // 编译前检查器导出
58
- exports.runPreBuildChecks = runPreBuildChecks;
59
- exports.runTrackingCheck = runTrackingCheck;
60
- exports.registerChecker = registerChecker;
61
- exports.toggleChecker = toggleChecker;
62
- exports.listCheckers = listCheckers;
63
-
64
- // 埋点验证器导出
65
- exports.validateTracking = validateTracking;
66
- exports.printValidationResult = printValidationResult;
67
- exports.TRACKING_METHODS = TRACKING_METHODS;
68
- exports.SDK_TO_TRACKING_MAP = SDK_TO_TRACKING_MAP;
69
-
70
- // 字体注入导出
71
- exports.FontInjectionWebpackPlugin = FontInjectionWebpackPlugin;
72
- exports.FONT_REGISTRY = FONT_REGISTRY;
73
- exports.getRegisteredFontKeys = getRegisteredFontKeys;
74
- exports.isBuiltinFont = isBuiltinFont;
75
- exports.getFontEntry = getFontEntry;
76
- exports.getOrGenerateFontCSS = getOrGenerateFontCSS;
77
-
78
- const { runCocosBuild, syncThemeForPreview } = require('./engines/cocos/pack.js');
79
- const { runCocosEngineBuild } = require('./engines/cocos/cli-build.js');
80
- const { prepareWritableCocosCli } = require('./engines/cocos/writable-cli.js');
81
- const { syncGeneratedTheme } = require('./engines/cocos/theme-assets.js');
82
- const { refreshAssets } = require('./engines/cocos/mcp-refresh.js');
83
- const { spawnCocos, needsXvfb } = require('./engines/cocos/cli.js');
84
- const {
85
- stripAdsdkCjsImport,
86
- stripSocialShareFromDir,
87
- isSocialMediaNetwork,
88
- } = require('./engines/cocos/strip-social-share.js');
89
- const { runCocosDev } = require('./engines/cocos/dev-server.js');
90
- exports.runCocosBuild = runCocosBuild;
91
- exports.syncThemeForPreview = syncThemeForPreview;
92
- exports.runCocosEngineBuild = runCocosEngineBuild;
93
- exports.prepareWritableCocosCli = prepareWritableCocosCli;
94
- exports.syncGeneratedTheme = syncGeneratedTheme;
95
- exports.refreshAssets = refreshAssets;
96
- exports.spawnCocos = spawnCocos;
97
- exports.needsXvfb = needsXvfb;
98
- exports.stripAdsdkCjsImport = stripAdsdkCjsImport;
99
- exports.stripSocialShareFromDir = stripSocialShareFromDir;
100
- exports.isSocialMediaNetwork = isSocialMediaNetwork;
101
- exports.runCocosDev = runCocosDev;
1
+ "use strict";const{allowedExtensions,webpackCommonConfig}=require("./webpack.common.js");const{parseArgvOptions}=require("./utils/parseArgvOptions.js");const{mergeOptions}=require("./utils/mergeOptions.js");const{options}=require("./options.js");const{DAPIInjectorPlugin}=require("./plugins/DAPIInjectorPlugin.js");const{DebuggerInjectionPlugin}=require("./plugins/DebuggerInjectionPlugin.js");const{ExitAPIInjectorPlugin}=require("./plugins/ExitAPIInjectorPlugin.js");const{runBuild,makeWebpackBuildConfig}=require("./webpack.build.js");const{runDev,makeWebpackDevConfig}=require("./webpack.dev.js");const{runViteDev,makeViteDevConfig,json5Plugin,assetInlinePlugin,fontFamilyPlugin}=require("./vite.dev.js");// 字体注入
2
+ const{FontInjectionWebpackPlugin}=require("./plugins/FontInjectionWebpackPlugin.js");const{FONT_REGISTRY,getRegisteredFontKeys,isBuiltin:isBuiltinFont,getFontEntry}=require("./utils/fontRegistry.js");const{getOrGenerateFontCSS}=require("./utils/fontResolver.js");// 验证器
3
+ const{runPreBuildChecks,runTrackingCheck,registerChecker,toggleChecker,listCheckers}=require("./validators/pre-build-checker.js");const{validateTracking,printValidationResult,TRACKING_METHODS,SDK_TO_TRACKING_MAP}=require("./validators/tracking-validator.js");exports.mergeOptions=mergeOptions;exports.parseArgvOptions=parseArgvOptions;exports.options=options;exports.allowedExtensions=allowedExtensions;exports.webpackCommonConfig=webpackCommonConfig;exports.makeWebpackDevConfig=makeWebpackDevConfig;exports.makeWebpackBuildConfig=makeWebpackBuildConfig;exports.runDev=runDev;exports.runBuild=runBuild;exports.DAPIInjectorPlugin=DAPIInjectorPlugin;exports.ExitAPIInjectorPlugin=ExitAPIInjectorPlugin;exports.DebuggerInjectionPlugin=DebuggerInjectionPlugin;exports.makeViteDevConfig=makeViteDevConfig;exports.runViteDev=runViteDev;// 公共 Vite 插件(供项目 vite.config.ts 直接引用)
4
+ exports.json5Plugin=json5Plugin;exports.assetInlinePlugin=assetInlinePlugin;exports.fontFamilyPlugin=fontFamilyPlugin;// 编译前检查器导出
5
+ exports.runPreBuildChecks=runPreBuildChecks;exports.runTrackingCheck=runTrackingCheck;exports.registerChecker=registerChecker;exports.toggleChecker=toggleChecker;exports.listCheckers=listCheckers;// 埋点验证器导出
6
+ exports.validateTracking=validateTracking;exports.printValidationResult=printValidationResult;exports.TRACKING_METHODS=TRACKING_METHODS;exports.SDK_TO_TRACKING_MAP=SDK_TO_TRACKING_MAP;// 字体注入导出
7
+ exports.FontInjectionWebpackPlugin=FontInjectionWebpackPlugin;exports.FONT_REGISTRY=FONT_REGISTRY;exports.getRegisteredFontKeys=getRegisteredFontKeys;exports.isBuiltinFont=isBuiltinFont;exports.getFontEntry=getFontEntry;exports.getOrGenerateFontCSS=getOrGenerateFontCSS;const{runCocosBuild,syncThemeForPreview}=require("./engines/cocos/pack.js");const{runCocosEngineBuild}=require("./engines/cocos/cli-build.js");const{prepareWritableCocosCli}=require("./engines/cocos/writable-cli.js");const{syncGeneratedTheme}=require("./engines/cocos/theme-assets.js");const{refreshAssets}=require("./engines/cocos/mcp-refresh.js");const{spawnCocos,needsXvfb}=require("./engines/cocos/cli.js");const{stripAdsdkCjsImport,stripSocialShareFromDir,isSocialMediaNetwork}=require("./engines/cocos/strip-social-share.js");const{runCocosDev}=require("./engines/cocos/dev-server.js");exports.runCocosBuild=runCocosBuild;exports.syncThemeForPreview=syncThemeForPreview;exports.runCocosEngineBuild=runCocosEngineBuild;exports.prepareWritableCocosCli=prepareWritableCocosCli;exports.syncGeneratedTheme=syncGeneratedTheme;exports.refreshAssets=refreshAssets;exports.spawnCocos=spawnCocos;exports.needsXvfb=needsXvfb;exports.stripAdsdkCjsImport=stripAdsdkCjsImport;exports.stripSocialShareFromDir=stripSocialShareFromDir;exports.isSocialMediaNetwork=isSocialMediaNetwork;exports.runCocosDev=runCocosDev;
@@ -1,94 +1 @@
1
- 'use strict';
2
-
3
- const { load } = require('cheerio');
4
- const { META, LIFTOFF_FONT } = require('./spec');
5
-
6
- function renderTag(tag) {
7
- const attrs = tag.attributes || {};
8
- const attrStr = Object.entries(attrs)
9
- .map(([k, v]) => `${k}="${String(v).replace(/"/g, '&quot;')}"`)
10
- .join(' ');
11
- if (tag.tagName === 'meta') {
12
- return `<meta ${attrStr} />`;
13
- }
14
- const inner = tag.innerHTML || '';
15
- return `<script${attrStr ? ' ' + attrStr : ''}>${inner}</script>`;
16
- }
17
-
18
- function applyMeta($, spec) {
19
- const viewport = spec.viewport || META.COMMON_VIEWPORT;
20
- if ($('meta[charset]').length) {
21
- $('meta[charset]').first().attr('charset', META.COMMON_CHARSET);
22
- } else {
23
- $('head').prepend(`<meta charset="${META.COMMON_CHARSET}" />`);
24
- }
25
- if ($('meta[name="viewport"]').length) {
26
- $('meta[name="viewport"]').attr('content', viewport);
27
- } else {
28
- $('head').prepend(`<meta name="viewport" content="${viewport}" />`);
29
- }
30
- if (!spec.skipRecommendedMeta) {
31
- if (!$('meta[name="HandheldFriendly"]').length) {
32
- $('head').append('<meta name="HandheldFriendly" content="True" />');
33
- }
34
- if (!$('meta[http-equiv="cleartype"]').length) {
35
- $('head').append('<meta http-equiv="cleartype" content="on" />');
36
- }
37
- if (!$('meta[name="apple-mobile-web-app-capable"]').length) {
38
- $('head').append('<meta name="apple-mobile-web-app-capable" content="yes" />');
39
- }
40
- if (!$('meta[name="mobile-web-app-capable"]').length) {
41
- $('head').append('<meta name="mobile-web-app-capable" content="yes" />');
42
- }
43
- if (!$('meta[http-equiv="X-UA-Compatible"]').length) {
44
- $('head').append('<meta http-equiv="X-UA-Compatible" content="IE=10" />');
45
- }
46
- }
47
- if (spec.liftoffFont) {
48
- $('head').append(LIFTOFF_FONT);
49
- }
50
- }
51
-
52
- function applyInjections(html, spec) {
53
- const $ = load(html);
54
- applyMeta($, spec);
55
- const tags = (spec.headTags || []).slice().reverse();
56
- for (const tag of tags) {
57
- $('head').prepend(renderTag(tag));
58
- }
59
- let out = $.html();
60
- for (const transform of spec.htmlTransforms || []) {
61
- out = transform(out);
62
- }
63
- if (spec.scanStubHtml) {
64
- if (/<\/body>/i.test(out)) {
65
- out = out.replace(/<\/body>/i, `${spec.scanStubHtml}</body>`);
66
- } else {
67
- out += spec.scanStubHtml;
68
- }
69
- }
70
- return out;
71
- }
72
-
73
- function extractInlineScripts(html) {
74
- const $ = load(html);
75
- const scripts = [];
76
- $('script').each((_i, el) => {
77
- const $el = $(el);
78
- if ($el.attr('src')) return;
79
- scripts.push($el.html() || '');
80
- $el.remove();
81
- });
82
- return { html: $.html(), scripts };
83
- }
84
-
85
- function extractBodyScripts(html) {
86
- return extractInlineScripts(html);
87
- }
88
-
89
- module.exports = {
90
- applyInjections,
91
- extractBodyScripts,
92
- extractInlineScripts,
93
- renderTag,
94
- };
1
+ "use strict";const{load}=require("cheerio");const{META,LIFTOFF_FONT}=require("./spec");function renderTag(tag){const attrs=tag.attributes||{};const attrStr=Object.entries(attrs).map(([k,v])=>`${k}="${String(v).replace(/"/g,"&quot;")}"`).join(" ");if(tag.tagName==="meta"){return`<meta ${attrStr} />`}const inner=tag.innerHTML||"";return`<script${attrStr?" "+attrStr:""}>${inner}</script>`}function applyMeta($,spec){const viewport=spec.viewport||META.COMMON_VIEWPORT;if($("meta[charset]").length){$("meta[charset]").first().attr("charset",META.COMMON_CHARSET)}else{$("head").prepend(`<meta charset="${META.COMMON_CHARSET}" />`)}if($("meta[name=\"viewport\"]").length){$("meta[name=\"viewport\"]").attr("content",viewport)}else{$("head").prepend(`<meta name="viewport" content="${viewport}" />`)}if(!spec.skipRecommendedMeta){if(!$("meta[name=\"HandheldFriendly\"]").length){$("head").append("<meta name=\"HandheldFriendly\" content=\"True\" />")}if(!$("meta[http-equiv=\"cleartype\"]").length){$("head").append("<meta http-equiv=\"cleartype\" content=\"on\" />")}if(!$("meta[name=\"apple-mobile-web-app-capable\"]").length){$("head").append("<meta name=\"apple-mobile-web-app-capable\" content=\"yes\" />")}if(!$("meta[name=\"mobile-web-app-capable\"]").length){$("head").append("<meta name=\"mobile-web-app-capable\" content=\"yes\" />")}if(!$("meta[http-equiv=\"X-UA-Compatible\"]").length){$("head").append("<meta http-equiv=\"X-UA-Compatible\" content=\"IE=10\" />")}}if(spec.liftoffFont){$("head").append(LIFTOFF_FONT)}}function applyInjections(html,spec){const $=load(html);applyMeta($,spec);const tags=(spec.headTags||[]).slice().reverse();for(const tag of tags){$("head").prepend(renderTag(tag))}let out=$.html();for(const transform of spec.htmlTransforms||[]){out=transform(out)}if(spec.scanStubHtml){if(/<\/body>/i.test(out)){out=out.replace(/<\/body>/i,`${spec.scanStubHtml}</body>`)}else{out+=spec.scanStubHtml}}return out}function extractInlineScripts(html){const $=load(html);const scripts=[];$("script").each((_i,el)=>{const $el=$(el);if($el.attr("src"))return;scripts.push($el.html()||"");$el.remove()});return{html:$.html(),scripts}}function extractBodyScripts(html){return extractInlineScripts(html)}module.exports={applyInjections,extractBodyScripts,extractInlineScripts,renderTag};
@@ -1,137 +1,9 @@
1
1
  #!/usr/bin/env node
2
- 'use strict';
3
-
4
- /**
2
+ "use strict";/**
5
3
  * Compare Cocos pack plan + injections against webpack.build.js rules.
6
4
  * Run: node core/injectors/check-channel-matrix.js
7
5
  *
8
6
  * Webpack is not modified. Known intentional Cocos diffs:
9
7
  * facebook / mintegral zip = inlined index.html only
10
8
  * (webpack still skips HtmlInlineScriptPlugin for those two)
11
- */
12
-
13
- const { allowedAdNetworks, mraidPartners } = require('../utils/parseArgvOptions');
14
- const { applyInjections } = require('./apply');
15
- const { getChannelPackPlan, zipOutputNetworks, zipOutputAllowedNetworks } = require('./spec');
16
-
17
- const WEBPACK_ZIP = [
18
- 'google', 'pangle', 'tiktok', 'vungle', 'mytarget', 'mintegral', 'adikteev',
19
- 'bigabid', 'inmobi', 'snapchat', 'bigoads', 'liftoff', 'facebook', 'remerge'
20
- ];
21
- const WEBPACK_ZIP_OPTIONAL = ['moloco'];
22
- const WEBPACK_SKIP_INLINE = ['mintegral', 'adikteev', 'bigabid', 'facebook'];
23
- const INTENTIONAL_INLINE_ZIP = ['facebook', 'mintegral'];
24
-
25
- function webpackProtocol(network) {
26
- return mraidPartners.includes(network) ? 'mraid' : 'none';
27
- }
28
-
29
- function webpackExpect(network) {
30
- const zip = WEBPACK_ZIP.includes(network);
31
- const skipInline = WEBPACK_SKIP_INLINE.includes(network) && (zip || network === 'mintegral' || network === 'adikteev' || network === 'bigabid');
32
- let files;
33
- if (!zip) files = ['*.html'];
34
- else if (network === 'adikteev') files = ['index.html', 'creative.js', 'style.css'];
35
- else if (network === 'bigabid') files = ['index.html', 'main.js'];
36
- else if (network === 'tiktok' || network === 'snapchat' || network === 'bigoads') files = ['index.html', 'config.json'];
37
- else if (skipInline && network === 'facebook') files = ['index.html', 'build.js'];
38
- else if (skipInline && network === 'mintegral') files = ['index.html', 'build.js'];
39
- else files = ['index.html'];
40
- return { zip, skipInline, files };
41
- }
42
-
43
- const INJECT_EXPECT = {
44
- google: ['exitapi.js', 'ad.size', 'ad.orientation'],
45
- tiktok: ['union-fe-nc-i18n'],
46
- pangle: ['union-fe-nc/playable/sdk'],
47
- mintegral: ['mintGameStart'],
48
- unity: ['src="mraid.js"'],
49
- ironsource: ['src="mraid.js"'],
50
- remerge: ['src="mraid.js"'],
51
- liftoff: ['src="mraid.js"', 'Helvetica Neue'],
52
- bigoads: ['bgy-mraid-sdk.js'],
53
- snapchat: ['ScPlayableAd'],
54
- inmobi: ['INMOBI_DSPMACROS'],
55
- social_media: ['og:type'],
56
- };
57
-
58
- const INJECT_FORBID = {
59
- applovin: ['src="mraid.js"'],
60
- facebook: ['src="mraid.js"'],
61
- preview: ['src="mraid.js"'],
62
- google: ['src="mraid.js"'],
63
- };
64
-
65
- const baseHtml = '<html><head></head><body><div id="GameDiv"></div></body></html>';
66
- const failures = [];
67
- const rows = [];
68
-
69
- for (const network of allowedAdNetworks) {
70
- const protocol = webpackProtocol(network);
71
- const buildOptions = {
72
- network,
73
- protocol,
74
- zip: false,
75
- googlePlayUrl: 'https://play.example',
76
- appStoreUrl: 'https://app.example',
77
- playcraftOrientationValue: 'both',
78
- filename: 'Game',
79
- };
80
- const themePayload = { mergedData: { gamePlay: { shareMeta: { title: 'T' } } }, i18nOverride: {}, assetRecordByPath: {} };
81
- const plan = getChannelPackPlan(buildOptions, themePayload);
82
- const wx = webpackExpect(network);
83
- const html = applyInjections(baseHtml, plan.spec);
84
-
85
- const cocosFiles = plan.isZip
86
- ? plan.zipEntries.filter((n, i, a) => a.indexOf(n) === i)
87
- : ['*.html'];
88
-
89
- let expectedCocosFiles = wx.files;
90
- if (INTENTIONAL_INLINE_ZIP.includes(network)) expectedCocosFiles = ['index.html'];
91
-
92
- const zipMismatch = plan.isZip !== wx.zip;
93
- const filesMismatch = plan.isZip && expectedCocosFiles.slice().sort().join() !== cocosFiles.slice().sort().join();
94
-
95
- for (const s of INJECT_EXPECT[network] || []) {
96
- if (!html.includes(s)) failures.push(`${network}: missing inject "${s}"`);
97
- }
98
- for (const s of INJECT_FORBID[network] || []) {
99
- if (html.includes(s)) failures.push(`${network}: unexpected inject "${s}"`);
100
- }
101
- if (zipMismatch) failures.push(`${network}: zip webpack=${wx.zip} cocos=${plan.isZip}`);
102
- if (filesMismatch) failures.push(`${network}: files webpack/cocos expected=${expectedCocosFiles} got=${cocosFiles}`);
103
- if (!html.includes('HandheldFriendly')) failures.push(`${network}: missing recommended meta`);
104
- if (!html.includes('FbPlayableAd.onCTAClick')) failures.push(`${network}: missing channel scan stub`);
105
-
106
- const note = INTENTIONAL_INLINE_ZIP.includes(network) && wx.files.includes('build.js')
107
- ? 'cocos inlines (webpack still splits)'
108
- : '';
109
- rows.push({
110
- network,
111
- zip: plan.isZip ? 'zip' : 'html',
112
- layout: plan.layout,
113
- files: cocosFiles.join(', '),
114
- note,
115
- });
116
- }
117
-
118
- if (JSON.stringify(zipOutputNetworks.slice().sort()) !== JSON.stringify(WEBPACK_ZIP.slice().sort())) {
119
- failures.push(`zipOutputNetworks != webpack list`);
120
- }
121
- if (JSON.stringify(zipOutputAllowedNetworks) !== JSON.stringify(WEBPACK_ZIP_OPTIONAL)) {
122
- failures.push(`zipOutputAllowedNetworks != webpack list`);
123
- }
124
-
125
- console.log('network'.padEnd(14), 'fmt'.padEnd(6), 'layout'.padEnd(12), 'files');
126
- console.log('-'.repeat(80));
127
- for (const row of rows) {
128
- console.log(row.network.padEnd(14), row.zip.padEnd(6), row.layout.padEnd(12), row.files, row.note ? ` ← ${row.note}` : '');
129
- }
130
-
131
- if (failures.length) {
132
- console.error('\nFAIL');
133
- failures.forEach((f) => console.error(' -', f));
134
- process.exit(1);
135
- }
136
- console.log('\nOK all', allowedAdNetworks.length, 'networks');
137
- console.log('Intentional diffs: facebook, mintegral zip contain only index.html (webpack comment still says split JS).');
9
+ */const{allowedAdNetworks,mraidPartners}=require("../utils/parseArgvOptions");const{applyInjections}=require("./apply");const{getChannelPackPlan,zipOutputNetworks,zipOutputAllowedNetworks}=require("./spec");const WEBPACK_ZIP=["google","pangle","tiktok","vungle","mytarget","mintegral","adikteev","bigabid","inmobi","snapchat","bigoads","liftoff","facebook","remerge"];const WEBPACK_ZIP_OPTIONAL=["moloco"];const WEBPACK_SKIP_INLINE=["mintegral","adikteev","bigabid","facebook"];const INTENTIONAL_INLINE_ZIP=["facebook","mintegral"];function webpackProtocol(network){return mraidPartners.includes(network)?"mraid":"none"}function webpackExpect(network){const zip=WEBPACK_ZIP.includes(network);const skipInline=WEBPACK_SKIP_INLINE.includes(network)&&(zip||network==="mintegral"||network==="adikteev"||network==="bigabid");let files;if(!zip)files=["*.html"];else if(network==="adikteev")files=["index.html","creative.js","style.css"];else if(network==="bigabid")files=["index.html","main.js"];else if(network==="tiktok"||network==="snapchat"||network==="bigoads")files=["index.html","config.json"];else if(skipInline&&network==="facebook")files=["index.html","build.js"];else if(skipInline&&network==="mintegral")files=["index.html","build.js"];else files=["index.html"];return{zip,skipInline,files}}const INJECT_EXPECT={google:["exitapi.js","ad.size","ad.orientation"],tiktok:["union-fe-nc-i18n"],pangle:["union-fe-nc/playable/sdk"],mintegral:["mintGameStart"],unity:["src=\"mraid.js\""],ironsource:["src=\"mraid.js\""],remerge:["src=\"mraid.js\""],liftoff:["src=\"mraid.js\"","Helvetica Neue"],bigoads:["bgy-mraid-sdk.js"],snapchat:["ScPlayableAd"],inmobi:["INMOBI_DSPMACROS"],social_media:["og:type"]};const INJECT_FORBID={applovin:["src=\"mraid.js\""],facebook:["src=\"mraid.js\""],preview:["src=\"mraid.js\""],google:["src=\"mraid.js\""]};const baseHtml="<html><head></head><body><div id=\"GameDiv\"></div></body></html>";const failures=[];const rows=[];for(const network of allowedAdNetworks){const protocol=webpackProtocol(network);const buildOptions={network,protocol,zip:false,googlePlayUrl:"https://play.example",appStoreUrl:"https://app.example",playcraftOrientationValue:"both",filename:"Game"};const themePayload={mergedData:{gamePlay:{shareMeta:{title:"T"}}},i18nOverride:{},assetRecordByPath:{}};const plan=getChannelPackPlan(buildOptions,themePayload);const wx=webpackExpect(network);const html=applyInjections(baseHtml,plan.spec);const cocosFiles=plan.isZip?plan.zipEntries.filter((n,i,a)=>a.indexOf(n)===i):["*.html"];let expectedCocosFiles=wx.files;if(INTENTIONAL_INLINE_ZIP.includes(network))expectedCocosFiles=["index.html"];const zipMismatch=plan.isZip!==wx.zip;const filesMismatch=plan.isZip&&expectedCocosFiles.slice().sort().join()!==cocosFiles.slice().sort().join();for(const s of INJECT_EXPECT[network]||[]){if(!html.includes(s))failures.push(`${network}: missing inject "${s}"`)}for(const s of INJECT_FORBID[network]||[]){if(html.includes(s))failures.push(`${network}: unexpected inject "${s}"`)}if(zipMismatch)failures.push(`${network}: zip webpack=${wx.zip} cocos=${plan.isZip}`);if(filesMismatch)failures.push(`${network}: files webpack/cocos expected=${expectedCocosFiles} got=${cocosFiles}`);if(!html.includes("HandheldFriendly"))failures.push(`${network}: missing recommended meta`);if(!html.includes("FbPlayableAd.onCTAClick"))failures.push(`${network}: missing channel scan stub`);const note=INTENTIONAL_INLINE_ZIP.includes(network)&&wx.files.includes("build.js")?"cocos inlines (webpack still splits)":"";rows.push({network,zip:plan.isZip?"zip":"html",layout:plan.layout,files:cocosFiles.join(", "),note})}if(JSON.stringify(zipOutputNetworks.slice().sort())!==JSON.stringify(WEBPACK_ZIP.slice().sort())){failures.push(`zipOutputNetworks != webpack list`)}if(JSON.stringify(zipOutputAllowedNetworks)!==JSON.stringify(WEBPACK_ZIP_OPTIONAL)){failures.push(`zipOutputAllowedNetworks != webpack list`)}console.log("network".padEnd(14),"fmt".padEnd(6),"layout".padEnd(12),"files");console.log("-".repeat(80));for(const row of rows){console.log(row.network.padEnd(14),row.zip.padEnd(6),row.layout.padEnd(12),row.files,row.note?` ← ${row.note}`:"")}if(failures.length){console.error("\nFAIL");failures.forEach(f=>console.error(" -",f));process.exit(1)}console.log("\nOK all",allowedAdNetworks.length,"networks");console.log("Intentional diffs: facebook, mintegral zip contain only index.html (webpack comment still says split JS).");