@playcraft/devkit 1.0.12 → 1.0.13

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 (39) hide show
  1. package/LICENSE +21 -21
  2. package/cli/bin/playable-scripts.js +0 -0
  3. package/cli/commands/build.js +5 -5
  4. package/cli/commands/builds.js +14 -14
  5. package/cli/commands/pack.js +47 -47
  6. package/core/batch-build.js +71 -71
  7. package/core/cos-uploader.js +37 -34
  8. package/core/index.d.ts +185 -185
  9. package/core/loaders/gltf-loader.js +19 -19
  10. package/core/plugins/AdikteevInjectorPlugin.js +11 -11
  11. package/core/plugins/BigoAdsInjectorPlugin.js +4 -4
  12. package/core/plugins/DAPIInjectorPlugin.js +4 -4
  13. package/core/plugins/DebuggerInjectionPlugin.js +5 -5
  14. package/core/plugins/ExitAPIInjectorPlugin.js +9 -9
  15. package/core/plugins/FflateCompressionPlugin.js +43 -43
  16. package/core/plugins/LiftoffInjectorPlugin.js +11 -11
  17. package/core/plugins/MRAIDInjectorPlugin.js +3 -3
  18. package/core/plugins/MintegralInjectorPlugin.js +4 -4
  19. package/core/plugins/PangleInjectorPlugin.js +3 -3
  20. package/core/plugins/SnapchatInjectorPlugin.js +4 -4
  21. package/core/plugins/TikTokInjectorPlugin.js +3 -3
  22. package/core/plugins/UnityInjectorPlugin.js +13 -13
  23. package/core/resources/snapchat-config.json +1 -1
  24. package/core/resources/tiktok-config.json +1 -1
  25. package/core/utils/buildDefines.js +2 -2
  26. package/core/utils/buildTemplateString.js +2 -2
  27. package/core/utils/generateAdikteevHtmlWebpackPluginConfig.js +26 -26
  28. package/core/utils/generateInMobiHtmlWebpackPluginConfig.js +16 -16
  29. package/core/utils/injectSDKPlugins.js +10 -10
  30. package/core/utils/logOptions.js +2 -2
  31. package/core/utils/mergeOptions.js +5 -5
  32. package/core/utils/parseArgvOptions.js +4 -4
  33. package/core/utils/resolveChannelFold2Zip.js +12 -12
  34. package/core/utils/validateThemeData.js +80 -80
  35. package/core/vite.dev.js +12 -12
  36. package/core/webpack.build.js +12 -12
  37. package/core/webpack.dev.js +12 -12
  38. package/defines.d.ts +54 -54
  39. package/package.json +1 -1
package/core/index.d.ts CHANGED
@@ -1,185 +1,185 @@
1
- import { Configuration as WebpackConfig } from 'webpack';
2
- import { WebpackPluginInstance } from 'webpack';
3
- import { UserConfig as ViteUserConfig } from 'vite';
4
-
5
- /** Supported file extensions for webpack resolution */
6
- export declare const allowedExtensions: string[];
7
-
8
- /** Base webpack configuration used by both development and build configs */
9
- export declare const webpackCommonConfig: WebpackConfig;
10
-
11
- /** Options for CLI arguments */
12
- export interface CLIOptionConfig {
13
- name: string;
14
- alias?: string;
15
- hasValue?: boolean;
16
- defaultValue?: any;
17
- description: string;
18
- parser?: (value: string) => any;
19
- }
20
-
21
- /** Parse command line arguments based on configuration */
22
- export declare function parseArgvOptions(possibleOptions: CLIOptionConfig[]): Record<string, any>;
23
-
24
- /** Deep merge configuration options */
25
- export declare function mergeOptions<T>(target: T, source?: Partial<T>): T;
26
-
27
- /** Configuration for webpack defines */
28
- export interface DefinesOptions {
29
- /** Development mode flag for conditional code */
30
- __DEV__: string;
31
- /** Google Play Store URL constant */
32
- GOOGLE_PLAY_URL: string;
33
- /** App Store URL constant */
34
- APP_STORE_URL: string;
35
- /** Current advertising network identifier */
36
- AD_NETWORK: string;
37
- /** Current advertising protocol */
38
- AD_PROTOCOL: string;
39
- /** Application name constant */
40
- APP: string;
41
- /** Build name constant */
42
- NAME: string;
43
- /** Build version constant */
44
- VERSION: string;
45
- /** Unique build identifier generated from timestamp */
46
- BUILD_HASH: string;
47
- /** Current language code */
48
- LANGUAGE: string;
49
- /** Current orientation identifier */
50
- ORIENTATION: 'both' | 'portrait' | 'landscape' | 'square';
51
- }
52
-
53
- /** CLI configuration options */
54
- export interface CLIOptions {
55
- /** Output directory for build files (default: 'dist') */
56
- outDir: string;
57
- /** Path to build.json configuration file (default: 'build.json') */
58
- buildConfig: string;
59
- /** Path to tsconfig.json configuration file (default: 'tsconfig.json') */
60
- tsConfig: string;
61
- /** Path to jsconfig.json configuration file (default: 'jsconfig.json') */
62
- jsConfig: string;
63
- /** Development server port number (default: 3000) */
64
- port: number;
65
- /** Whether to open browser automatically (default: false) */
66
- open: boolean;
67
- /** Ad protocol to use (default: 'none') */
68
- protocol: 'none' | 'mraid' | 'dapi';
69
- /** Ad network identifier (default: 'preview') */
70
- network:
71
- | 'preview'
72
- | 'applovin'
73
- | 'unity'
74
- | 'google'
75
- | 'ironsource'
76
- | 'facebook'
77
- | 'moloco'
78
- | 'mintegral'
79
- | 'vungle'
80
- | 'adcolony'
81
- | 'tapjoy'
82
- | 'snapchat'
83
- | 'tiktok'
84
- | 'appreciate'
85
- | 'chartboost'
86
- | 'pangle'
87
- | 'mytarget'
88
- | 'liftoff'
89
- | 'smadex'
90
- | 'adikteev'
91
- | 'bigabid'
92
- | 'inmobi';
93
- /** Development mode flag */
94
- dev: boolean;
95
- /** Skip recommended meta tags injection */
96
- skipRecommendedMeta?: boolean;
97
- /** URL of debugger script to inject */
98
- debugger?: string;
99
- /** Code obfuscation level: 0=no minimize/obfuscate, 1=terser only, 2=obfuscator basic, 3=obfuscator+dead code, 4=maximum (default: 2) */
100
- obfuscateLevel: 0 | 1 | 2 | 3 | 4;
101
- /** Directories to exclude from compression (default: []) */
102
- excludeCompressDirs: string[];
103
- /** Template for output filename using pattern {app}_{name}_{version}_{date}_{language}_{network} */
104
- filename: string;
105
- /** Application name used in build filename and APP define */
106
- app: string;
107
- /** Concept name used in build filename and NAME define */
108
- name: string;
109
- /** Version name used in build filename and VERSION define */
110
- version: string;
111
- /** Language code for localization */
112
- language: 'auto' | 'en' | 'es' | 'zh' | 'hi' | 'ar' | 'fr' | 'de' | 'ja' | 'pt';
113
- /** Orientation identifier */
114
- orientation: 'both' | 'portrait' | 'landscape' | 'square';
115
- /** Google Play Store URL for the app */
116
- googlePlayUrl: string;
117
- /** App Store URL for the app */
118
- appStoreUrl: string;
119
- /** Webpack define plugin configuration */
120
- defines: Record<string, string>;
121
- }
122
-
123
- /** Global options object */
124
- export declare const options: CLIOptions;
125
-
126
- /** Create webpack config for development */
127
- export declare function makeWebpackDevConfig(
128
- customOptions?: Partial<CLIOptions>,
129
- customDefines?: Record<string, any>,
130
- webpackCustomConfig?: Partial<WebpackConfig>
131
- ): WebpackConfig;
132
-
133
- /** Create webpack config for production build */
134
- export declare function makeWebpackBuildConfig(
135
- customOptions?: Partial<CLIOptions>,
136
- customDefines?: Record<string, any>,
137
- webpackCustomConfig?: Partial<WebpackConfig>
138
- ): WebpackConfig;
139
-
140
- /** Start webpack development server */
141
- export declare function runDev(
142
- webpackConfig?: WebpackConfig,
143
- customOptions?: Partial<CLIOptions>,
144
- customDefines?: Record<string, any>,
145
- webpackCustomConfig?: Partial<WebpackConfig>
146
- ): void;
147
-
148
- /** Run webpack production build */
149
- export declare function runBuild(
150
- webpackConfig?: WebpackConfig,
151
- customOptions?: Partial<CLIOptions>,
152
- customDefines?: Record<string, any>,
153
- webpackCustomConfig?: Partial<WebpackConfig>
154
- ): void;
155
-
156
- /** Plugin for injecting DAPI script */
157
- export declare class DAPIInjectorPlugin implements WebpackPluginInstance {
158
- apply(compiler: any): void;
159
- }
160
-
161
- /** Plugin for injecting debugger script */
162
- export declare class DebuggerInjectionPlugin implements WebpackPluginInstance {
163
- constructor(debuggerSrc: string);
164
- apply(compiler: any): void;
165
- }
166
-
167
- /** Plugin for injecting Google's ExitAPI and meta tags */
168
- export declare class ExitAPIInjectorPlugin implements WebpackPluginInstance {
169
- apply(compiler: any): void;
170
- }
171
-
172
- /** Create Vite config for development */
173
- export declare function makeViteDevConfig(
174
- customOptions?: Partial<CLIOptions>,
175
- customDefines?: Record<string, any>,
176
- viteCustomConfig?: Partial<ViteUserConfig>
177
- ): ViteUserConfig;
178
-
179
- /** Start Vite development server */
180
- export declare function runViteDev(
181
- viteConfig?: ViteUserConfig,
182
- customOptions?: Partial<CLIOptions>,
183
- customDefines?: Record<string, any>,
184
- viteCustomConfig?: Partial<ViteUserConfig>
185
- ): Promise<void>;
1
+ import { Configuration as WebpackConfig } from 'webpack';
2
+ import { WebpackPluginInstance } from 'webpack';
3
+ import { UserConfig as ViteUserConfig } from 'vite';
4
+
5
+ /** Supported file extensions for webpack resolution */
6
+ export declare const allowedExtensions: string[];
7
+
8
+ /** Base webpack configuration used by both development and build configs */
9
+ export declare const webpackCommonConfig: WebpackConfig;
10
+
11
+ /** Options for CLI arguments */
12
+ export interface CLIOptionConfig {
13
+ name: string;
14
+ alias?: string;
15
+ hasValue?: boolean;
16
+ defaultValue?: any;
17
+ description: string;
18
+ parser?: (value: string) => any;
19
+ }
20
+
21
+ /** Parse command line arguments based on configuration */
22
+ export declare function parseArgvOptions(possibleOptions: CLIOptionConfig[]): Record<string, any>;
23
+
24
+ /** Deep merge configuration options */
25
+ export declare function mergeOptions<T>(target: T, source?: Partial<T>): T;
26
+
27
+ /** Configuration for webpack defines */
28
+ export interface DefinesOptions {
29
+ /** Development mode flag for conditional code */
30
+ __DEV__: string;
31
+ /** Google Play Store URL constant */
32
+ GOOGLE_PLAY_URL: string;
33
+ /** App Store URL constant */
34
+ APP_STORE_URL: string;
35
+ /** Current advertising network identifier */
36
+ AD_NETWORK: string;
37
+ /** Current advertising protocol */
38
+ AD_PROTOCOL: string;
39
+ /** Application name constant */
40
+ APP: string;
41
+ /** Build name constant */
42
+ NAME: string;
43
+ /** Build version constant */
44
+ VERSION: string;
45
+ /** Unique build identifier generated from timestamp */
46
+ BUILD_HASH: string;
47
+ /** Current language code */
48
+ LANGUAGE: string;
49
+ /** Current orientation identifier */
50
+ ORIENTATION: 'both' | 'portrait' | 'landscape' | 'square';
51
+ }
52
+
53
+ /** CLI configuration options */
54
+ export interface CLIOptions {
55
+ /** Output directory for build files (default: 'dist') */
56
+ outDir: string;
57
+ /** Path to build.json configuration file (default: 'build.json') */
58
+ buildConfig: string;
59
+ /** Path to tsconfig.json configuration file (default: 'tsconfig.json') */
60
+ tsConfig: string;
61
+ /** Path to jsconfig.json configuration file (default: 'jsconfig.json') */
62
+ jsConfig: string;
63
+ /** Development server port number (default: 3000) */
64
+ port: number;
65
+ /** Whether to open browser automatically (default: false) */
66
+ open: boolean;
67
+ /** Ad protocol to use (default: 'none') */
68
+ protocol: 'none' | 'mraid' | 'dapi';
69
+ /** Ad network identifier (default: 'preview') */
70
+ network:
71
+ | 'preview'
72
+ | 'applovin'
73
+ | 'unity'
74
+ | 'google'
75
+ | 'ironsource'
76
+ | 'facebook'
77
+ | 'moloco'
78
+ | 'mintegral'
79
+ | 'vungle'
80
+ | 'adcolony'
81
+ | 'tapjoy'
82
+ | 'snapchat'
83
+ | 'tiktok'
84
+ | 'appreciate'
85
+ | 'chartboost'
86
+ | 'pangle'
87
+ | 'mytarget'
88
+ | 'liftoff'
89
+ | 'smadex'
90
+ | 'adikteev'
91
+ | 'bigabid'
92
+ | 'inmobi';
93
+ /** Development mode flag */
94
+ dev: boolean;
95
+ /** Skip recommended meta tags injection */
96
+ skipRecommendedMeta?: boolean;
97
+ /** URL of debugger script to inject */
98
+ debugger?: string;
99
+ /** Code obfuscation level: 0=no minimize/obfuscate, 1=terser only, 2=obfuscator basic, 3=obfuscator+dead code, 4=maximum (default: 2) */
100
+ obfuscateLevel: 0 | 1 | 2 | 3 | 4;
101
+ /** Directories to exclude from compression (default: []) */
102
+ excludeCompressDirs: string[];
103
+ /** Template for output filename using pattern {app}_{name}_{version}_{date}_{language}_{network} */
104
+ filename: string;
105
+ /** Application name used in build filename and APP define */
106
+ app: string;
107
+ /** Concept name used in build filename and NAME define */
108
+ name: string;
109
+ /** Version name used in build filename and VERSION define */
110
+ version: string;
111
+ /** Language code for localization */
112
+ language: 'auto' | 'en' | 'es' | 'zh' | 'hi' | 'ar' | 'fr' | 'de' | 'ja' | 'pt';
113
+ /** Orientation identifier */
114
+ orientation: 'both' | 'portrait' | 'landscape' | 'square';
115
+ /** Google Play Store URL for the app */
116
+ googlePlayUrl: string;
117
+ /** App Store URL for the app */
118
+ appStoreUrl: string;
119
+ /** Webpack define plugin configuration */
120
+ defines: Record<string, string>;
121
+ }
122
+
123
+ /** Global options object */
124
+ export declare const options: CLIOptions;
125
+
126
+ /** Create webpack config for development */
127
+ export declare function makeWebpackDevConfig(
128
+ customOptions?: Partial<CLIOptions>,
129
+ customDefines?: Record<string, any>,
130
+ webpackCustomConfig?: Partial<WebpackConfig>
131
+ ): WebpackConfig;
132
+
133
+ /** Create webpack config for production build */
134
+ export declare function makeWebpackBuildConfig(
135
+ customOptions?: Partial<CLIOptions>,
136
+ customDefines?: Record<string, any>,
137
+ webpackCustomConfig?: Partial<WebpackConfig>
138
+ ): WebpackConfig;
139
+
140
+ /** Start webpack development server */
141
+ export declare function runDev(
142
+ webpackConfig?: WebpackConfig,
143
+ customOptions?: Partial<CLIOptions>,
144
+ customDefines?: Record<string, any>,
145
+ webpackCustomConfig?: Partial<WebpackConfig>
146
+ ): void;
147
+
148
+ /** Run webpack production build */
149
+ export declare function runBuild(
150
+ webpackConfig?: WebpackConfig,
151
+ customOptions?: Partial<CLIOptions>,
152
+ customDefines?: Record<string, any>,
153
+ webpackCustomConfig?: Partial<WebpackConfig>
154
+ ): void;
155
+
156
+ /** Plugin for injecting DAPI script */
157
+ export declare class DAPIInjectorPlugin implements WebpackPluginInstance {
158
+ apply(compiler: any): void;
159
+ }
160
+
161
+ /** Plugin for injecting debugger script */
162
+ export declare class DebuggerInjectionPlugin implements WebpackPluginInstance {
163
+ constructor(debuggerSrc: string);
164
+ apply(compiler: any): void;
165
+ }
166
+
167
+ /** Plugin for injecting Google's ExitAPI and meta tags */
168
+ export declare class ExitAPIInjectorPlugin implements WebpackPluginInstance {
169
+ apply(compiler: any): void;
170
+ }
171
+
172
+ /** Create Vite config for development */
173
+ export declare function makeViteDevConfig(
174
+ customOptions?: Partial<CLIOptions>,
175
+ customDefines?: Record<string, any>,
176
+ viteCustomConfig?: Partial<ViteUserConfig>
177
+ ): ViteUserConfig;
178
+
179
+ /** Start Vite development server */
180
+ export declare function runViteDev(
181
+ viteConfig?: ViteUserConfig,
182
+ customOptions?: Partial<CLIOptions>,
183
+ customDefines?: Record<string, any>,
184
+ viteCustomConfig?: Partial<ViteUserConfig>
185
+ ): Promise<void>;
@@ -1,22 +1,22 @@
1
- "use strict";const path=require("path");const loaderUtils=require("loader-utils");const fs=require("fs");const isObject=value=>typeof value==="object"&&value!==null;const isDataURI=value=>/^data:/i.test(value);/**
2
- * A utility function that allows mapping the value for a given key in an object
3
- * [in place](https://en.wikipedia.org/wiki/In-place_algorithm).
4
- *
5
- * @remarks
6
- * This function recursively iterates through every key in the object.
7
- * Once a key strictly equal to the given key is found, the callback function
8
- * is invoked, and its return value (or resolved value) is then set as the new value
9
- * for that entry.
10
- *
11
- * @param {unknown} obj - The object to mutate.
12
- * @param {string} key - The key to match against.
13
- * @param {(value: unknown) => Promise<any>} callback
14
- * The callback that either returns the mapped value, or returns a Promise
15
- * that resolves to the new value.
16
- */async function mapDeep(obj,key,callback){if(Array.isArray(obj)){for(const item of obj){await mapDeep(item,key,callback)}}else if(isObject(obj)){for(const[k,v]of Object.entries(obj)){if(k===key){obj[k]=await callback(v)}else{await mapDeep(v,key,callback)}}}}/**
17
- * @typedef {import(".").GLTFLoaderDefinition} GLTFLoader
18
- * @this {ThisParameterType<GLTFLoader>}
19
- * @type {GLTFLoader}
1
+ "use strict";const path=require("path");const loaderUtils=require("loader-utils");const fs=require("fs");const isObject=value=>typeof value==="object"&&value!==null;const isDataURI=value=>/^data:/i.test(value);/**
2
+ * A utility function that allows mapping the value for a given key in an object
3
+ * [in place](https://en.wikipedia.org/wiki/In-place_algorithm).
4
+ *
5
+ * @remarks
6
+ * This function recursively iterates through every key in the object.
7
+ * Once a key strictly equal to the given key is found, the callback function
8
+ * is invoked, and its return value (or resolved value) is then set as the new value
9
+ * for that entry.
10
+ *
11
+ * @param {unknown} obj - The object to mutate.
12
+ * @param {string} key - The key to match against.
13
+ * @param {(value: unknown) => Promise<any>} callback
14
+ * The callback that either returns the mapped value, or returns a Promise
15
+ * that resolves to the new value.
16
+ */async function mapDeep(obj,key,callback){if(Array.isArray(obj)){for(const item of obj){await mapDeep(item,key,callback)}}else if(isObject(obj)){for(const[k,v]of Object.entries(obj)){if(k===key){obj[k]=await callback(v)}else{await mapDeep(v,key,callback)}}}}/**
17
+ * @typedef {import(".").GLTFLoaderDefinition} GLTFLoader
18
+ * @this {ThisParameterType<GLTFLoader>}
19
+ * @type {GLTFLoader}
20
20
  */async function gltfLoader(content){// Destructure loader options and set default values:
21
21
  const{// inline = true,
22
22
  // useRelativePaths = true,
@@ -1,14 +1,14 @@
1
- "use strict";const HtmlWebpackPlugin=require("html-webpack-plugin");/**
2
- * AdikteevInjectorPlugin
3
- *
4
- * 在开发环境中注入 Adikteev MRAID mock 和占位符变量
5
- *
6
- * 官方文档: https://help.adikteev.com/hc/en-us/articles/10549028250130
7
- *
8
- * Adikteev 要求:
9
- * 1. 使用 mraid.open() 打开目标 URL
10
- * 2. 暴露 AK_CLICK_DESTINATION_URL 和 AK_CLICK_PIXEL_URL 占位符
11
- * 3. 生产环境由 Adikteev CDN 提供 mraid.js
1
+ "use strict";const HtmlWebpackPlugin=require("html-webpack-plugin");/**
2
+ * AdikteevInjectorPlugin
3
+ *
4
+ * 在开发环境中注入 Adikteev MRAID mock 和占位符变量
5
+ *
6
+ * 官方文档: https://help.adikteev.com/hc/en-us/articles/10549028250130
7
+ *
8
+ * Adikteev 要求:
9
+ * 1. 使用 mraid.open() 打开目标 URL
10
+ * 2. 暴露 AK_CLICK_DESTINATION_URL 和 AK_CLICK_PIXEL_URL 占位符
11
+ * 3. 生产环境由 Adikteev CDN 提供 mraid.js
12
12
  */class AdikteevInjectorPlugin{apply(compiler){compiler.hooks.compilation.tap("AdikteevInjectorPlugin",compilation=>{HtmlWebpackPlugin.getHooks(compilation).alterAssetTagGroups.tapAsync("AdikteevInjectorPlugin",(data,cb)=>{// 注入 MRAID mock (仅开发环境)
13
13
  data.headTags.unshift({tagName:"script",innerHTML:`
14
14
  // Adikteev MRAID Mock (Development Only)
@@ -1,7 +1,7 @@
1
- "use strict";const HtmlWebpackPlugin=require("html-webpack-plugin");/**
2
- * BigoAds SDK 注入插件
3
- * 在 HTML 头部注入 BigoAds 专用 SDK 脚本
4
- * 文档: https://www.bigoads.com/help/detail?id=143&moduleId=7&currentLan=CN
1
+ "use strict";const HtmlWebpackPlugin=require("html-webpack-plugin");/**
2
+ * BigoAds SDK 注入插件
3
+ * 在 HTML 头部注入 BigoAds 专用 SDK 脚本
4
+ * 文档: https://www.bigoads.com/help/detail?id=143&moduleId=7&currentLan=CN
5
5
  */class BigoAdsInjectorPlugin{apply(compiler){compiler.hooks.compilation.tap("BigoAdsInjectorPlugin",compilation=>{HtmlWebpackPlugin.getHooks(compilation).beforeEmit.tapAsync("BigoAdsInjectorPlugin",(data,cb)=>{// BigoAds 要求必须引入此 SDK,不允许使用标准 mraid.js
6
6
  const bigoAdsScript=`<script src="https://static-web.likeevideo.com/as/common-static/big-data/dsp-public/bgy-mraid-sdk.js"></script>`;// 在 <head> 标签后注入
7
7
  data.html=data.html.replace("<head>",`<head>\n ${bigoAdsScript}`);cb(null,data)})})}}exports.BigoAdsInjectorPlugin=BigoAdsInjectorPlugin;
@@ -1,5 +1,5 @@
1
- "use strict";const HtmlWebpackPlugin=require("html-webpack-plugin");const dapiSrc="function getScript(e,i){var n=document.createElement(\"script\");n.type=\"text/javascript\",n.async=!0,i&&(n.onload=i),n.src=e,document.head.appendChild(n)}function parseMessage(e){var i=e.data,n=i.indexOf(DOLLAR_PREFIX+RECEIVE_MSG_PREFIX);if(-1!==n){var t=i.slice(n+2);return getMessageParams(t)}return{}}function getMessageParams(e){var i,n=[],t=e.split(\"/\"),a=t.length;if(-1===e.indexOf(RECEIVE_MSG_PREFIX)){if(a>=2&&a%2===0)for(i=0;a>i;i+=2)n[t[i]]=t.length<i+1?null:decodeURIComponent(t[i+1])}else{var o=e.split(RECEIVE_MSG_PREFIX);void 0!==o[1]&&(n=JSON&&JSON.parse(o[1]))}return n}function getDapi(e){var i=parseMessage(e);if(!i||i.name===GET_DAPI_URL_MSG_NAME){var n=i.data;getScript(n,onDapiReceived)}}function invokeDapiListeners(){for(var e in dapiEventsPool)dapiEventsPool.hasOwnProperty(e)&&dapi.addEventListener(e,dapiEventsPool[e])}function onDapiReceived(){dapi=window.dapi,window.removeEventListener(\"message\",getDapi),invokeDapiListeners()}function init(){window.dapi.isDemoDapi&&(window.parent.postMessage(DOLLAR_PREFIX+SEND_MSG_PREFIX+JSON.stringify({state:\"getDapiUrl\"}),\"*\"),window.addEventListener(\"message\",getDapi,!1))}var DOLLAR_PREFIX=\"$$\",RECEIVE_MSG_PREFIX=\"DAPI_SERVICE:\",SEND_MSG_PREFIX=\"DAPI_AD:\",GET_DAPI_URL_MSG_NAME=\"connection.getDapiUrl\",dapiEventsPool={},dapi=window.dapi||{isReady:function(){return!1},addEventListener:function(e,i){dapiEventsPool[e]=i},removeEventListener:function(e){delete dapiEventsPool[e]},isDemoDapi:!0};init();";/**
2
- * Webpack plugin that injects DAPI (Display Advertising Programming Interface) script
3
- * into the HTML head. This enables communication with ad networks that use DAPI protocol.
4
- * @implements {import('webpack').WebpackPluginInstance}
1
+ "use strict";const HtmlWebpackPlugin=require("html-webpack-plugin");const dapiSrc="function getScript(e,i){var n=document.createElement(\"script\");n.type=\"text/javascript\",n.async=!0,i&&(n.onload=i),n.src=e,document.head.appendChild(n)}function parseMessage(e){var i=e.data,n=i.indexOf(DOLLAR_PREFIX+RECEIVE_MSG_PREFIX);if(-1!==n){var t=i.slice(n+2);return getMessageParams(t)}return{}}function getMessageParams(e){var i,n=[],t=e.split(\"/\"),a=t.length;if(-1===e.indexOf(RECEIVE_MSG_PREFIX)){if(a>=2&&a%2===0)for(i=0;a>i;i+=2)n[t[i]]=t.length<i+1?null:decodeURIComponent(t[i+1])}else{var o=e.split(RECEIVE_MSG_PREFIX);void 0!==o[1]&&(n=JSON&&JSON.parse(o[1]))}return n}function getDapi(e){var i=parseMessage(e);if(!i||i.name===GET_DAPI_URL_MSG_NAME){var n=i.data;getScript(n,onDapiReceived)}}function invokeDapiListeners(){for(var e in dapiEventsPool)dapiEventsPool.hasOwnProperty(e)&&dapi.addEventListener(e,dapiEventsPool[e])}function onDapiReceived(){dapi=window.dapi,window.removeEventListener(\"message\",getDapi),invokeDapiListeners()}function init(){window.dapi.isDemoDapi&&(window.parent.postMessage(DOLLAR_PREFIX+SEND_MSG_PREFIX+JSON.stringify({state:\"getDapiUrl\"}),\"*\"),window.addEventListener(\"message\",getDapi,!1))}var DOLLAR_PREFIX=\"$$\",RECEIVE_MSG_PREFIX=\"DAPI_SERVICE:\",SEND_MSG_PREFIX=\"DAPI_AD:\",GET_DAPI_URL_MSG_NAME=\"connection.getDapiUrl\",dapiEventsPool={},dapi=window.dapi||{isReady:function(){return!1},addEventListener:function(e,i){dapiEventsPool[e]=i},removeEventListener:function(e){delete dapiEventsPool[e]},isDemoDapi:!0};init();";/**
2
+ * Webpack plugin that injects DAPI (Display Advertising Programming Interface) script
3
+ * into the HTML head. This enables communication with ad networks that use DAPI protocol.
4
+ * @implements {import('webpack').WebpackPluginInstance}
5
5
  */class DAPIInjectorPlugin{apply(compiler){compiler.hooks.compilation.tap("DAPIInjectorPlugin",compilation=>{HtmlWebpackPlugin.getHooks(compilation).alterAssetTagGroups.tapAsync("DAPIInjectorPlugin",(data,callback)=>{data.headTags.splice(0,0,{tagName:"script",voidTag:false,meta:{plugin:"html-inline-script-webpack-plugin"},innerHTML:dapiSrc});callback(null,data)})})}}exports.DAPIInjectorPlugin=DAPIInjectorPlugin;
@@ -1,6 +1,6 @@
1
- "use strict";const HtmlWebpackPlugin=require("html-webpack-plugin");/**
2
- * Webpack plugin that injects a custom debugger script into the HTML head
3
- * @implements {import('webpack').WebpackPluginInstance}
4
- */class DebuggerInjectionPlugin{/**
5
- * @param {string} debuggerSrc - URL of the debugger script to inject
1
+ "use strict";const HtmlWebpackPlugin=require("html-webpack-plugin");/**
2
+ * Webpack plugin that injects a custom debugger script into the HTML head
3
+ * @implements {import('webpack').WebpackPluginInstance}
4
+ */class DebuggerInjectionPlugin{/**
5
+ * @param {string} debuggerSrc - URL of the debugger script to inject
6
6
  */constructor(debuggerSrc){this.debuggerSrc=debuggerSrc}apply(compiler){compiler.hooks.compilation.tap("DebuggerInjectionPlugin",compilation=>{HtmlWebpackPlugin.getHooks(compilation).alterAssetTagGroups.tapAsync("DebuggerInjectionPlugin",(data,callback)=>{data.headTags.splice(0,0,{tagName:"script",voidTag:false,meta:{plugin:"html-inline-script-webpack-plugin"},attributes:{src:this.debuggerSrc,type:"text/javascript"}});callback(null,data)})})}}exports.DebuggerInjectionPlugin=DebuggerInjectionPlugin;
@@ -1,10 +1,10 @@
1
- "use strict";const HtmlWebpackPlugin=require("html-webpack-plugin");/**
2
- * Webpack plugin that injects Google's ExitAPI script and required meta tags for Google Ads.
3
- * Adds:
4
- * - ExitAPI script for handling ad exits
5
- * - Meta tag for ad size configuration
6
- * - Meta tag for ad orientation support
7
- * @implements {import('webpack').WebpackPluginInstance}
8
- */class ExitAPIInjectorPlugin{/**
9
- * @param {ORIENTATION} orientation - device orientation
1
+ "use strict";const HtmlWebpackPlugin=require("html-webpack-plugin");/**
2
+ * Webpack plugin that injects Google's ExitAPI script and required meta tags for Google Ads.
3
+ * Adds:
4
+ * - ExitAPI script for handling ad exits
5
+ * - Meta tag for ad size configuration
6
+ * - Meta tag for ad orientation support
7
+ * @implements {import('webpack').WebpackPluginInstance}
8
+ */class ExitAPIInjectorPlugin{/**
9
+ * @param {ORIENTATION} orientation - device orientation
10
10
  */constructor(orientation){this.orientation=orientation}apply(compiler){compiler.hooks.compilation.tap("ExitAPIInjectorPlugin",compilation=>{HtmlWebpackPlugin.getHooks(compilation).alterAssetTagGroups.tapAsync("ExitAPIInjectorPlugin",(data,callback)=>{data.headTags.splice(0,0,{tagName:"script",voidTag:false,meta:{plugin:"html-inline-script-webpack-plugin"},attributes:{src:"https://tpc.googlesyndication.com/pagead/gadgets/html5/api/exitapi.js",type:"text/javascript"}});let width=320;let height=480;if(this.orientation==="square")width=480;else if(this.orientation==="landscape"){width=480;height=320}data.headTags.splice(0,0,{tagName:"meta",voidTag:true,meta:{plugin:"html-webpack-plugin"},attributes:{name:"ad.size",content:`width=${width},height=${height}`}});data.headTags.splice(0,0,{tagName:"meta",voidTag:true,meta:{plugin:"html-webpack-plugin"},attributes:{name:"ad.orientation",content:this.orientation==="both"||this.orientation==="square"?"portrait,landscape":this.orientation}});callback(null,data)})})}}exports.ExitAPIInjectorPlugin=ExitAPIInjectorPlugin;
@@ -1,34 +1,34 @@
1
- "use strict";/**
2
- * Webpack 插件:使用 fflate 压缩 HTML 文件并生成自解压版本
3
- *
4
- * 工作原理:
5
- * 1. 编译时:读取最终生成的 HTML 文件
6
- * 2. 使用 fflate.zlibSync 进行最高级别压缩(level: 9,固定)
7
- * 3. 转换为 Base64 编码字符串
8
- * 4. 生成新的 HTML,包含:
9
- * - fflate 解压库(内联)
10
- * - 压缩后的数据(Base64 字符串)
11
- * - 自动解压和执行代码
12
- * 5. 运行时:浏览器自动解压并执行原始 HTML
13
- *
14
- * 收益:
15
- * - 体积减少约 66-68%(压缩后)
16
- * - 解压速度极快(3-5ms)
17
- * - 完美兼容所有浏览器(99%+)
18
- * - fflate 包体积仅 8KB
19
- *
20
- * 注意:
21
- * - 仅在打正式包(生产环境)时使用
22
- * - 压缩等级固定为 9(最高压缩)
23
- * - 不保留原始文件
24
- */const fflate=require("fflate");const fs=require("fs");const path=require("path");const{minify}=require("terser");class FflateCompressionPlugin{/**
25
- * @param {Object} options - 插件配置选项
26
- * @param {boolean} [options.enabled=true] - 是否启用压缩
27
- * @param {number} [options.level=9] - 压缩等级(固定为 9)
28
- * @param {boolean} [options.keepOriginal=false] - 是否保留原始文件(固定为 false)
29
- * @param {boolean} [options.logStats=true] - 是否输出压缩统计
30
- * @param {string} [options.googlePlayUrl] - Google Play 商店链接
31
- * @param {string} [options.appStoreUrl] - App Store 商店链接
1
+ "use strict";/**
2
+ * Webpack 插件:使用 fflate 压缩 HTML 文件并生成自解压版本
3
+ *
4
+ * 工作原理:
5
+ * 1. 编译时:读取最终生成的 HTML 文件
6
+ * 2. 使用 fflate.zlibSync 进行最高级别压缩(level: 9,固定)
7
+ * 3. 转换为 Base64 编码字符串
8
+ * 4. 生成新的 HTML,包含:
9
+ * - fflate 解压库(内联)
10
+ * - 压缩后的数据(Base64 字符串)
11
+ * - 自动解压和执行代码
12
+ * 5. 运行时:浏览器自动解压并执行原始 HTML
13
+ *
14
+ * 收益:
15
+ * - 体积减少约 66-68%(压缩后)
16
+ * - 解压速度极快(3-5ms)
17
+ * - 完美兼容所有浏览器(99%+)
18
+ * - fflate 包体积仅 8KB
19
+ *
20
+ * 注意:
21
+ * - 仅在打正式包(生产环境)时使用
22
+ * - 压缩等级固定为 9(最高压缩)
23
+ * - 不保留原始文件
24
+ */const fflate=require("fflate");const fs=require("fs");const path=require("path");const{minify}=require("terser");class FflateCompressionPlugin{/**
25
+ * @param {Object} options - 插件配置选项
26
+ * @param {boolean} [options.enabled=true] - 是否启用压缩
27
+ * @param {number} [options.level=9] - 压缩等级(固定为 9)
28
+ * @param {boolean} [options.keepOriginal=false] - 是否保留原始文件(固定为 false)
29
+ * @param {boolean} [options.logStats=true] - 是否输出压缩统计
30
+ * @param {string} [options.googlePlayUrl] - Google Play 商店链接
31
+ * @param {string} [options.appStoreUrl] - App Store 商店链接
32
32
  */constructor(options={}){this.options={enabled:options.enabled!==false,level:options.level||9,keepOriginal:options.keepOriginal||false,logStats:options.logStats!==false,googlePlayUrl:options.googlePlayUrl||"https://play.google.com/store/games",appStoreUrl:options.appStoreUrl||"https://www.apple.com/app-store/"}}apply(compiler){if(!this.options.enabled){console.log("\u26A0\uFE0F fflate compression is disabled");return}const webpack=require("webpack");// 使用 processAssets 钩子(Webpack 5),在 ZipPlugin 之前执行
33
33
  // 阶段顺序:OPTIMIZE_INLINE (700) → SUMMARIZE (1000) → OPTIMIZE_TRANSFER (3000)
34
34
  // HtmlWebpackPlugin + HtmlInlineScriptPlugin 在 OPTIMIZE_INLINE 阶段完成 HTML 生成
@@ -45,24 +45,24 @@ const minifiedFflate=await minify(fflateLibContent,{compress:{passes:2,dead_code
45
45
  const headContent=this.extractHeadContent(originalHtml);// 生成自解压 HTML
46
46
  const decompressedHtml=await this.generateDecompressHtml(base64String,fflateLibContent,headContent);const finalSize=Buffer.byteLength(decompressedHtml,"utf8");// 输出统计信息
47
47
  if(this.options.logStats){console.log(`\n📄 ${htmlFilename}`);console.log(` 原始大小: ${(originalSize/1024).toFixed(2)} KB`);console.log(` 压缩后大小: ${(compressedSize/1024).toFixed(2)} KB`);console.log(` Base64 大小: ${(base64Size/1024).toFixed(2)} KB`);console.log(` 最终大小: ${(finalSize/1024).toFixed(2)} KB (含解压代码)`);console.log(` 压缩率: ${compressionRatio}%`);console.log(` 体积减少: ${originalSize-finalSize} bytes (${((1-finalSize/originalSize)*100).toFixed(2)}%)`);console.log(` 压缩耗时: ${compressTime}ms`);if(finalSize<originalSize){const saved=originalSize-finalSize;console.log(` ✅ 节省空间: ${(saved/1024).toFixed(2)} KB (${(saved/originalSize*100).toFixed(2)}%)`)}else{console.log(` ⚠️ 压缩后反而变大了 ${finalSize-originalSize} bytes`);console.log(` 💡 建议: 对于小文件(<50KB),压缩可能不划算`)}}// 更新 webpack 资源(使用 Webpack 5 API)
48
- compilation.updateAsset(htmlFilename,new RawSource(decompressedHtml))}console.log("\n\u2705 fflate compression completed!\n")}catch(error){console.error("\n\u274C fflate compression failed:",error);throw error}}/**
49
- * 从原始 HTML 中提取 <head> 内容
50
- * 保留 meta 标签、外部 script 引用、link 标签、title 等
51
- * 排除内联 style 和内联 script(这些会在解压后恢复)
52
- * @param {string} html - 原始 HTML 内容
53
- * @returns {string} 提取的 head 内容(HTML 字符串)
48
+ compilation.updateAsset(htmlFilename,new RawSource(decompressedHtml))}console.log("\n\u2705 fflate compression completed!\n")}catch(error){console.error("\n\u274C fflate compression failed:",error);throw error}}/**
49
+ * 从原始 HTML 中提取 <head> 内容
50
+ * 保留 meta 标签、外部 script 引用、link 标签、title 等
51
+ * 排除内联 style 和内联 script(这些会在解压后恢复)
52
+ * @param {string} html - 原始 HTML 内容
53
+ * @returns {string} 提取的 head 内容(HTML 字符串)
54
54
  */extractHeadContent(html){// 提取 <head>...</head> 之间的内容
55
55
  const headMatch=html.match(/<head[^>]*>([\s\S]*?)<\/head>/i);if(!headMatch)return"";const headHtml=headMatch[1];const elements=[];// 提取所有 meta 标签(自闭合,排除 charset 和 viewport,因为模板已包含)
56
56
  const metaRegex=/<meta\s+[^>]*?\/?>/gi;let match;while((match=metaRegex.exec(headHtml))!==null){const tag=match[0];// 排除 charset 和 viewport(自解压模板已包含)
57
57
  if(/charset\s*=/i.test(tag))continue;if(/name\s*=\s*["']viewport["']/i.test(tag))continue;elements.push(tag)}// 提取 title 标签
58
58
  const titleMatch=headHtml.match(/<title[^>]*>[\s\S]*?<\/title>/i);if(titleMatch){elements.push(titleMatch[0])}// 提取外部 script 标签(有 src 属性的)
59
59
  const scriptRegex=/<script\s+[^>]*src\s*=\s*["'][^"']+["'][^>]*>[\s\S]*?<\/script>/gi;while((match=scriptRegex.exec(headHtml))!==null){elements.push(match[0])}// 提取 link 标签
60
- const linkRegex=/<link\s+[^>]*?\/?>/gi;while((match=linkRegex.exec(headHtml))!==null){elements.push(match[0])}return elements.join("\n ")}/**
61
- * 生成自解压 HTML 模板(极简压缩版本,无需 module)
62
- * @param {string} compressedBase64 - 压缩后的 Base64 字符串
63
- * @param {string} fflateLibCode - fflate 库代码(已压缩)
64
- * @param {string} headContent - 从原始 HTML 提取的 head 内容
65
- * @returns {Promise<string>} 完整的自解压 HTML
60
+ const linkRegex=/<link\s+[^>]*?\/?>/gi;while((match=linkRegex.exec(headHtml))!==null){elements.push(match[0])}return elements.join("\n ")}/**
61
+ * 生成自解压 HTML 模板(极简压缩版本,无需 module)
62
+ * @param {string} compressedBase64 - 压缩后的 Base64 字符串
63
+ * @param {string} fflateLibCode - fflate 库代码(已压缩)
64
+ * @param {string} headContent - 从原始 HTML 提取的 head 内容
65
+ * @returns {Promise<string>} 完整的自解压 HTML
66
66
  */async generateDecompressHtml(compressedBase64,fflateLibCode,headContent=""){// 可读的解压代码(保持格式以便维护)
67
67
  const decompressCodeReadable=`
68
68
  (function() {