@playcraft/build 0.0.2
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/README.md +96 -0
- package/dist/base-builder.d.ts +66 -0
- package/dist/base-builder.js +415 -0
- package/dist/converter.d.ts +35 -0
- package/dist/converter.js +148 -0
- package/dist/generators/config-generator.d.ts +7 -0
- package/dist/generators/config-generator.js +122 -0
- package/dist/generators/settings-generator.d.ts +14 -0
- package/dist/generators/settings-generator.js +100 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +14 -0
- package/dist/loaders/playcanvas-loader.d.ts +10 -0
- package/dist/loaders/playcanvas-loader.js +18 -0
- package/dist/loaders/playcraft-loader.d.ts +10 -0
- package/dist/loaders/playcraft-loader.js +51 -0
- package/dist/platforms/applovin.d.ts +10 -0
- package/dist/platforms/applovin.js +67 -0
- package/dist/platforms/base.d.ts +29 -0
- package/dist/platforms/base.js +11 -0
- package/dist/platforms/bigo.d.ts +15 -0
- package/dist/platforms/bigo.js +77 -0
- package/dist/platforms/facebook.d.ts +9 -0
- package/dist/platforms/facebook.js +37 -0
- package/dist/platforms/google.d.ts +10 -0
- package/dist/platforms/google.js +53 -0
- package/dist/platforms/index.d.ts +14 -0
- package/dist/platforms/index.js +47 -0
- package/dist/platforms/ironsource.d.ts +10 -0
- package/dist/platforms/ironsource.js +71 -0
- package/dist/platforms/liftoff.d.ts +10 -0
- package/dist/platforms/liftoff.js +56 -0
- package/dist/platforms/moloco.d.ts +10 -0
- package/dist/platforms/moloco.js +53 -0
- package/dist/platforms/snapchat.d.ts +10 -0
- package/dist/platforms/snapchat.js +59 -0
- package/dist/platforms/tiktok.d.ts +15 -0
- package/dist/platforms/tiktok.js +65 -0
- package/dist/platforms/unity.d.ts +10 -0
- package/dist/platforms/unity.js +69 -0
- package/dist/playable-builder.d.ts +97 -0
- package/dist/playable-builder.js +590 -0
- package/dist/types.d.ts +90 -0
- package/dist/types.js +1 -0
- package/dist/vite/config-builder.d.ts +15 -0
- package/dist/vite/config-builder.js +212 -0
- package/dist/vite/platform-configs.d.ts +38 -0
- package/dist/vite/platform-configs.js +257 -0
- package/dist/vite/plugin-model-compression.d.ts +11 -0
- package/dist/vite/plugin-model-compression.js +63 -0
- package/dist/vite/plugin-platform.d.ts +17 -0
- package/dist/vite/plugin-platform.js +241 -0
- package/dist/vite/plugin-playcanvas.d.ts +18 -0
- package/dist/vite/plugin-playcanvas.js +711 -0
- package/dist/vite/plugin-source-builder.d.ts +15 -0
- package/dist/vite/plugin-source-builder.js +344 -0
- package/dist/vite-builder.d.ts +51 -0
- package/dist/vite-builder.js +122 -0
- package/package.json +51 -0
- package/templates/__loading__.js +100 -0
- package/templates/__modules__.js +47 -0
- package/templates/__settings__.template.js +20 -0
- package/templates/__start__.js +332 -0
- package/templates/index.html +18 -0
- package/templates/logo.png +0 -0
- package/templates/manifest.json +1 -0
- package/templates/patches/cannon.min.js +28 -0
- package/templates/patches/lz4.js +10 -0
- package/templates/patches/one-page-http-get.js +20 -0
- package/templates/patches/one-page-inline-game-scripts.js +20 -0
- package/templates/patches/one-page-mraid-resize-canvas.js +46 -0
- package/templates/patches/p2.min.js +27 -0
- package/templates/patches/playcraft-no-xhr.js +52 -0
- package/templates/playcanvas-stable.min.js +16363 -0
- package/templates/styles.css +43 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type UserConfig } from 'vite';
|
|
2
|
+
import type { Platform, BuildOptions } from '../types.js';
|
|
3
|
+
export declare class ViteConfigBuilder {
|
|
4
|
+
private baseBuildDir;
|
|
5
|
+
private platform;
|
|
6
|
+
private options;
|
|
7
|
+
constructor(baseBuildDir: string, platform: Platform, options: BuildOptions);
|
|
8
|
+
create(): UserConfig;
|
|
9
|
+
private getPlatformConfig;
|
|
10
|
+
private shouldMinifyCSS;
|
|
11
|
+
private shouldMinifyJS;
|
|
12
|
+
private createPlugins;
|
|
13
|
+
private getPlayableOptions;
|
|
14
|
+
private resolveExternFiles;
|
|
15
|
+
}
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import { createLogger, defineConfig } from 'vite';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import { viteSingleFile } from 'vite-plugin-singlefile';
|
|
5
|
+
import viteImagemin from '@vheemstra/vite-plugin-imagemin';
|
|
6
|
+
import imageminMozjpeg from 'imagemin-mozjpeg';
|
|
7
|
+
import imageminPngquant from 'imagemin-pngquant';
|
|
8
|
+
import imageminWebp from 'imagemin-webp';
|
|
9
|
+
import { visualizer } from 'rollup-plugin-visualizer';
|
|
10
|
+
import { PLATFORM_CONFIGS } from './platform-configs.js';
|
|
11
|
+
import { vitePlayCanvasPlugin } from './plugin-playcanvas.js';
|
|
12
|
+
import { vitePlatformPlugin } from './plugin-platform.js';
|
|
13
|
+
import { viteModelCompressionPlugin } from './plugin-model-compression.js';
|
|
14
|
+
import { createPlatformAdapter } from '../platforms/index.js';
|
|
15
|
+
export class ViteConfigBuilder {
|
|
16
|
+
constructor(baseBuildDir, platform, options) {
|
|
17
|
+
this.baseBuildDir = baseBuildDir;
|
|
18
|
+
this.platform = platform;
|
|
19
|
+
this.options = options;
|
|
20
|
+
}
|
|
21
|
+
create() {
|
|
22
|
+
const platformConfig = this.getPlatformConfig();
|
|
23
|
+
const outputDir = this.options.outputDir || './dist';
|
|
24
|
+
const playableOptions = this.getPlayableOptions(platformConfig);
|
|
25
|
+
const rootDir = fs.realpathSync(this.baseBuildDir);
|
|
26
|
+
const logger = createLogger();
|
|
27
|
+
const customLogger = {
|
|
28
|
+
...logger,
|
|
29
|
+
warn(msg, options) {
|
|
30
|
+
if (typeof msg === 'string' && msg.includes('can\'t be bundled without type="module"')) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
logger.warn(msg, options);
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
return defineConfig({
|
|
37
|
+
root: rootDir,
|
|
38
|
+
base: './',
|
|
39
|
+
customLogger,
|
|
40
|
+
build: {
|
|
41
|
+
outDir: outputDir,
|
|
42
|
+
emptyOutDir: true,
|
|
43
|
+
// CSS 压缩
|
|
44
|
+
cssMinify: this.shouldMinifyCSS(platformConfig) ? 'lightningcss' : false,
|
|
45
|
+
// JS 压缩
|
|
46
|
+
minify: this.shouldMinifyJS(platformConfig) ? 'terser' : false,
|
|
47
|
+
terserOptions: {
|
|
48
|
+
compress: {
|
|
49
|
+
drop_console: true,
|
|
50
|
+
drop_debugger: true,
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
// 资源内联阈值(所有资源都内联)
|
|
54
|
+
assetsInlineLimit: Infinity,
|
|
55
|
+
// 不生成 sourcemap(Playable Ads 不需要)
|
|
56
|
+
sourcemap: platformConfig.includeSourcemap,
|
|
57
|
+
rollupOptions: {
|
|
58
|
+
input: {
|
|
59
|
+
main: path.join(rootDir, 'index.html'),
|
|
60
|
+
},
|
|
61
|
+
onwarn(warning, warn) {
|
|
62
|
+
const message = typeof warning === 'string' ? warning : warning.message;
|
|
63
|
+
if (message && message.includes('can\'t be bundled without type="module"')) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
warn(warning);
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
plugins: this.createPlugins(platformConfig, outputDir, playableOptions),
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
getPlatformConfig() {
|
|
74
|
+
const baseConfig = PLATFORM_CONFIGS[this.platform];
|
|
75
|
+
const resolvedOutputFormat = this.options.format ?? baseConfig.outputFormat;
|
|
76
|
+
// 根据选项覆盖配置
|
|
77
|
+
return {
|
|
78
|
+
...baseConfig,
|
|
79
|
+
outputFormat: resolvedOutputFormat,
|
|
80
|
+
minifyCSS: this.options.cssMinify ?? baseConfig.minifyCSS,
|
|
81
|
+
minifyJS: this.options.jsMinify ?? baseConfig.minifyJS,
|
|
82
|
+
compressImages: this.options.compressImages ?? baseConfig.compressImages,
|
|
83
|
+
compressModels: this.options.compressModels ?? baseConfig.compressModels,
|
|
84
|
+
modelCompression: {
|
|
85
|
+
method: this.options.modelCompression ?? baseConfig.modelCompression?.method ?? 'draco',
|
|
86
|
+
quality: baseConfig.modelCompression?.quality ?? 0.8,
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
shouldMinifyCSS(config) {
|
|
91
|
+
return config.minifyCSS;
|
|
92
|
+
}
|
|
93
|
+
shouldMinifyJS(config) {
|
|
94
|
+
return config.minifyJS;
|
|
95
|
+
}
|
|
96
|
+
createPlugins(platformConfig, outputDir, playableOptions) {
|
|
97
|
+
const plugins = [];
|
|
98
|
+
// 1. PlayCanvas 资源转换插件(最先执行)
|
|
99
|
+
plugins.push(vitePlayCanvasPlugin({
|
|
100
|
+
baseBuildDir: this.baseBuildDir,
|
|
101
|
+
inlineScripts: true,
|
|
102
|
+
convertDataUrls: platformConfig.outputFormat === 'html',
|
|
103
|
+
outputFormat: playableOptions.outputFormat,
|
|
104
|
+
patchXhrOut: playableOptions.patchXhrOut,
|
|
105
|
+
inlineGameScripts: playableOptions.inlineGameScripts,
|
|
106
|
+
compressEngine: playableOptions.compressEngine,
|
|
107
|
+
configJsonInline: playableOptions.configJsonInline,
|
|
108
|
+
mraidSupport: playableOptions.mraidSupport,
|
|
109
|
+
ammoReplacement: this.options.ammoReplacement,
|
|
110
|
+
}));
|
|
111
|
+
// 2. 平台特定插件
|
|
112
|
+
const platformAdapter = createPlatformAdapter(this.options);
|
|
113
|
+
plugins.push(vitePlatformPlugin({
|
|
114
|
+
platform: this.platform,
|
|
115
|
+
adapter: platformAdapter,
|
|
116
|
+
outputDir: outputDir,
|
|
117
|
+
baseBuildDir: this.baseBuildDir,
|
|
118
|
+
outputFormat: platformConfig.outputFormat,
|
|
119
|
+
externFiles: playableOptions.externFiles,
|
|
120
|
+
mraidSupport: playableOptions.mraidSupport,
|
|
121
|
+
}));
|
|
122
|
+
// 3. 图片压缩插件
|
|
123
|
+
if (platformConfig.compressImages) {
|
|
124
|
+
const imageQuality = platformConfig.imageQuality || {
|
|
125
|
+
jpg: 75,
|
|
126
|
+
png: [0.7, 0.8],
|
|
127
|
+
webp: 75,
|
|
128
|
+
};
|
|
129
|
+
const jpegQuality = this.options.imageQuality ?? imageQuality.jpg ?? 75;
|
|
130
|
+
const pngQuality = Array.isArray(imageQuality.png) && imageQuality.png.length >= 2
|
|
131
|
+
? [imageQuality.png[0], imageQuality.png[1]]
|
|
132
|
+
: [0.7, 0.8];
|
|
133
|
+
const webpQuality = imageQuality.webp ?? 75;
|
|
134
|
+
const imageminPlugin = viteImagemin({
|
|
135
|
+
plugins: {
|
|
136
|
+
jpg: [imageminMozjpeg({ quality: jpegQuality })],
|
|
137
|
+
jpeg: [imageminMozjpeg({ quality: jpegQuality })],
|
|
138
|
+
png: [imageminPngquant({ quality: pngQuality })],
|
|
139
|
+
},
|
|
140
|
+
makeWebp: this.options.convertToWebP !== false ? {
|
|
141
|
+
plugins: {
|
|
142
|
+
jpg: [imageminWebp({ quality: webpQuality })],
|
|
143
|
+
jpeg: [imageminWebp({ quality: webpQuality })],
|
|
144
|
+
png: [imageminWebp({ quality: webpQuality })],
|
|
145
|
+
},
|
|
146
|
+
} : undefined,
|
|
147
|
+
});
|
|
148
|
+
if (imageminPlugin) {
|
|
149
|
+
plugins.push(imageminPlugin);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
// 4. 模型压缩插件
|
|
153
|
+
if (platformConfig.compressModels) {
|
|
154
|
+
plugins.push(viteModelCompressionPlugin({
|
|
155
|
+
quality: platformConfig.modelCompression?.quality ?? 0.8,
|
|
156
|
+
method: platformConfig.modelCompression?.method ?? 'draco',
|
|
157
|
+
enabled: true,
|
|
158
|
+
}));
|
|
159
|
+
}
|
|
160
|
+
// 5. 单文件输出插件(仅HTML格式)
|
|
161
|
+
if (platformConfig.outputFormat === 'html') {
|
|
162
|
+
plugins.push(viteSingleFile({
|
|
163
|
+
removeViteModuleLoader: true,
|
|
164
|
+
}));
|
|
165
|
+
}
|
|
166
|
+
// 6. 打包分析报告
|
|
167
|
+
if (this.options.analyze) {
|
|
168
|
+
const reportPath = this.options.analyzeReportPath
|
|
169
|
+
? this.options.analyzeReportPath
|
|
170
|
+
: path.join(outputDir, 'bundle-report.html');
|
|
171
|
+
plugins.push(visualizer({
|
|
172
|
+
filename: reportPath,
|
|
173
|
+
template: 'treemap',
|
|
174
|
+
gzipSize: true,
|
|
175
|
+
brotliSize: true,
|
|
176
|
+
open: false,
|
|
177
|
+
}));
|
|
178
|
+
}
|
|
179
|
+
return plugins.filter(Boolean);
|
|
180
|
+
}
|
|
181
|
+
getPlayableOptions(config) {
|
|
182
|
+
const playable = config.playable ?? {};
|
|
183
|
+
const externFiles = this.resolveExternFiles(playable.externFiles);
|
|
184
|
+
return {
|
|
185
|
+
outputFormat: config.outputFormat,
|
|
186
|
+
patchXhrOut: this.options.patchXhrOut ?? playable.patchXhrOut ?? false,
|
|
187
|
+
inlineGameScripts: this.options.inlineGameScripts ?? playable.inlineGameScripts ?? false,
|
|
188
|
+
compressEngine: this.options.compressEngine ?? playable.compressEngine ?? false,
|
|
189
|
+
configJsonInline: playable.configJsonInline ?? (config.outputFormat === 'html'),
|
|
190
|
+
externFiles,
|
|
191
|
+
mraidSupport: this.options.mraidSupport ?? playable.mraidSupport ?? false,
|
|
192
|
+
snapchatCta: this.options.snapchatCta ?? playable.snapchatCta ?? false,
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
resolveExternFiles(defaultValue) {
|
|
196
|
+
const optionValue = this.options.externFiles;
|
|
197
|
+
const raw = optionValue ?? defaultValue;
|
|
198
|
+
if (!raw) {
|
|
199
|
+
return undefined;
|
|
200
|
+
}
|
|
201
|
+
if (typeof raw === 'object') {
|
|
202
|
+
return raw;
|
|
203
|
+
}
|
|
204
|
+
const folderName = this.options.snapchat?.folderName;
|
|
205
|
+
const externalUrlPrefix = this.options.snapchat?.externalUrlPrefix;
|
|
206
|
+
return {
|
|
207
|
+
enabled: true,
|
|
208
|
+
folderName,
|
|
209
|
+
externalUrlPrefix,
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { Platform, ExternFilesConfig } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* 平台 Vite 配置接口
|
|
4
|
+
*/
|
|
5
|
+
export interface PlatformViteConfig {
|
|
6
|
+
sizeLimit: number;
|
|
7
|
+
outputFormat: 'html' | 'zip';
|
|
8
|
+
minifyCSS: boolean;
|
|
9
|
+
minifyJS: boolean;
|
|
10
|
+
compressImages: boolean;
|
|
11
|
+
compressModels: boolean;
|
|
12
|
+
injectScripts?: string[];
|
|
13
|
+
htmlTransforms?: Array<(html: string) => string>;
|
|
14
|
+
outputFileName: string;
|
|
15
|
+
includeSourcemap: boolean;
|
|
16
|
+
imageQuality?: {
|
|
17
|
+
jpg?: number;
|
|
18
|
+
png?: [number, number];
|
|
19
|
+
webp?: number;
|
|
20
|
+
};
|
|
21
|
+
modelCompression?: {
|
|
22
|
+
method?: 'draco' | 'meshopt';
|
|
23
|
+
quality?: number;
|
|
24
|
+
};
|
|
25
|
+
playable?: {
|
|
26
|
+
patchXhrOut?: boolean;
|
|
27
|
+
inlineGameScripts?: boolean;
|
|
28
|
+
compressEngine?: boolean;
|
|
29
|
+
configJsonInline?: boolean;
|
|
30
|
+
externFiles?: boolean | ExternFilesConfig;
|
|
31
|
+
mraidSupport?: boolean;
|
|
32
|
+
snapchatCta?: boolean;
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* 平台配置映射
|
|
37
|
+
*/
|
|
38
|
+
export declare const PLATFORM_CONFIGS: Record<Platform, PlatformViteConfig>;
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 平台配置映射
|
|
3
|
+
*/
|
|
4
|
+
export const PLATFORM_CONFIGS = {
|
|
5
|
+
facebook: {
|
|
6
|
+
sizeLimit: 5 * 1024 * 1024, // 5MB(HTML/ZIP 总包体)
|
|
7
|
+
outputFormat: 'html',
|
|
8
|
+
minifyCSS: true,
|
|
9
|
+
minifyJS: true,
|
|
10
|
+
compressImages: true,
|
|
11
|
+
compressModels: true,
|
|
12
|
+
injectScripts: ['fbPlayableAd'],
|
|
13
|
+
outputFileName: 'index.html',
|
|
14
|
+
includeSourcemap: false,
|
|
15
|
+
imageQuality: {
|
|
16
|
+
jpg: 75,
|
|
17
|
+
png: [0.7, 0.8],
|
|
18
|
+
webp: 75,
|
|
19
|
+
},
|
|
20
|
+
modelCompression: {
|
|
21
|
+
method: 'draco',
|
|
22
|
+
quality: 0.8,
|
|
23
|
+
},
|
|
24
|
+
playable: {
|
|
25
|
+
patchXhrOut: true,
|
|
26
|
+
inlineGameScripts: true,
|
|
27
|
+
compressEngine: true,
|
|
28
|
+
configJsonInline: true,
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
snapchat: {
|
|
32
|
+
sizeLimit: 5 * 1024 * 1024, // 5MB
|
|
33
|
+
outputFormat: 'zip',
|
|
34
|
+
minifyCSS: true,
|
|
35
|
+
minifyJS: true,
|
|
36
|
+
compressImages: true,
|
|
37
|
+
compressModels: true,
|
|
38
|
+
injectScripts: ['mraid', 'snapchatCta'],
|
|
39
|
+
outputFileName: 'ad.html',
|
|
40
|
+
includeSourcemap: false,
|
|
41
|
+
imageQuality: {
|
|
42
|
+
jpg: 80,
|
|
43
|
+
png: [0.75, 0.85],
|
|
44
|
+
webp: 80,
|
|
45
|
+
},
|
|
46
|
+
modelCompression: {
|
|
47
|
+
method: 'draco',
|
|
48
|
+
quality: 0.85,
|
|
49
|
+
},
|
|
50
|
+
playable: {
|
|
51
|
+
inlineGameScripts: true,
|
|
52
|
+
externFiles: true,
|
|
53
|
+
mraidSupport: true,
|
|
54
|
+
snapchatCta: true,
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
ironsource: {
|
|
58
|
+
sizeLimit: 5 * 1024 * 1024, // 5MB(修正)
|
|
59
|
+
outputFormat: 'html',
|
|
60
|
+
minifyCSS: true,
|
|
61
|
+
minifyJS: true,
|
|
62
|
+
compressImages: true,
|
|
63
|
+
compressModels: true,
|
|
64
|
+
injectScripts: ['mraid', 'dapi'],
|
|
65
|
+
outputFileName: 'index.html',
|
|
66
|
+
includeSourcemap: false,
|
|
67
|
+
imageQuality: {
|
|
68
|
+
jpg: 75,
|
|
69
|
+
png: [0.7, 0.8],
|
|
70
|
+
webp: 75,
|
|
71
|
+
},
|
|
72
|
+
modelCompression: {
|
|
73
|
+
method: 'draco',
|
|
74
|
+
quality: 0.8,
|
|
75
|
+
},
|
|
76
|
+
playable: {
|
|
77
|
+
patchXhrOut: true,
|
|
78
|
+
inlineGameScripts: true,
|
|
79
|
+
configJsonInline: true,
|
|
80
|
+
mraidSupport: true,
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
applovin: {
|
|
84
|
+
sizeLimit: 5 * 1024 * 1024, // 5MB(修正)
|
|
85
|
+
outputFormat: 'html',
|
|
86
|
+
minifyCSS: true,
|
|
87
|
+
minifyJS: true,
|
|
88
|
+
compressImages: true,
|
|
89
|
+
compressModels: true,
|
|
90
|
+
injectScripts: ['mraid'],
|
|
91
|
+
outputFileName: 'index.html',
|
|
92
|
+
includeSourcemap: false,
|
|
93
|
+
imageQuality: {
|
|
94
|
+
jpg: 75,
|
|
95
|
+
png: [0.7, 0.8],
|
|
96
|
+
webp: 75,
|
|
97
|
+
},
|
|
98
|
+
modelCompression: {
|
|
99
|
+
method: 'draco',
|
|
100
|
+
quality: 0.8,
|
|
101
|
+
},
|
|
102
|
+
playable: {
|
|
103
|
+
patchXhrOut: true,
|
|
104
|
+
inlineGameScripts: true,
|
|
105
|
+
configJsonInline: true,
|
|
106
|
+
mraidSupport: true,
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
google: {
|
|
110
|
+
sizeLimit: 5 * 1024 * 1024, // 5MB(修正)
|
|
111
|
+
outputFormat: 'zip', // ZIP格式(修正)
|
|
112
|
+
minifyCSS: true,
|
|
113
|
+
minifyJS: true,
|
|
114
|
+
compressImages: true,
|
|
115
|
+
compressModels: true,
|
|
116
|
+
injectScripts: ['exitApi'],
|
|
117
|
+
outputFileName: 'index.html',
|
|
118
|
+
includeSourcemap: false,
|
|
119
|
+
imageQuality: {
|
|
120
|
+
jpg: 75,
|
|
121
|
+
png: [0.7, 0.8],
|
|
122
|
+
webp: 75,
|
|
123
|
+
},
|
|
124
|
+
modelCompression: {
|
|
125
|
+
method: 'draco',
|
|
126
|
+
quality: 0.8,
|
|
127
|
+
},
|
|
128
|
+
playable: {
|
|
129
|
+
inlineGameScripts: true,
|
|
130
|
+
externFiles: true,
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
tiktok: {
|
|
134
|
+
sizeLimit: 5 * 1024 * 1024, // 5MB
|
|
135
|
+
outputFormat: 'zip',
|
|
136
|
+
minifyCSS: true,
|
|
137
|
+
minifyJS: true,
|
|
138
|
+
compressImages: true,
|
|
139
|
+
compressModels: true,
|
|
140
|
+
injectScripts: ['pangleSdk'],
|
|
141
|
+
outputFileName: 'index.html',
|
|
142
|
+
includeSourcemap: false,
|
|
143
|
+
imageQuality: {
|
|
144
|
+
jpg: 80,
|
|
145
|
+
png: [0.75, 0.85],
|
|
146
|
+
webp: 80,
|
|
147
|
+
},
|
|
148
|
+
modelCompression: {
|
|
149
|
+
method: 'draco',
|
|
150
|
+
quality: 0.85,
|
|
151
|
+
},
|
|
152
|
+
playable: {
|
|
153
|
+
inlineGameScripts: true,
|
|
154
|
+
externFiles: true,
|
|
155
|
+
},
|
|
156
|
+
},
|
|
157
|
+
unity: {
|
|
158
|
+
sizeLimit: 5 * 1024 * 1024, // 5MB
|
|
159
|
+
outputFormat: 'html',
|
|
160
|
+
minifyCSS: true,
|
|
161
|
+
minifyJS: true,
|
|
162
|
+
compressImages: true,
|
|
163
|
+
compressModels: true,
|
|
164
|
+
injectScripts: ['mraid3'],
|
|
165
|
+
outputFileName: 'index.html',
|
|
166
|
+
includeSourcemap: false,
|
|
167
|
+
imageQuality: {
|
|
168
|
+
jpg: 75,
|
|
169
|
+
png: [0.7, 0.8],
|
|
170
|
+
webp: 75,
|
|
171
|
+
},
|
|
172
|
+
modelCompression: {
|
|
173
|
+
method: 'draco',
|
|
174
|
+
quality: 0.8,
|
|
175
|
+
},
|
|
176
|
+
playable: {
|
|
177
|
+
patchXhrOut: true,
|
|
178
|
+
inlineGameScripts: true,
|
|
179
|
+
configJsonInline: true,
|
|
180
|
+
mraidSupport: true,
|
|
181
|
+
},
|
|
182
|
+
},
|
|
183
|
+
liftoff: {
|
|
184
|
+
sizeLimit: 5 * 1024 * 1024, // 5MB
|
|
185
|
+
outputFormat: 'zip',
|
|
186
|
+
minifyCSS: true,
|
|
187
|
+
minifyJS: true,
|
|
188
|
+
compressImages: true,
|
|
189
|
+
compressModels: true,
|
|
190
|
+
injectScripts: ['mraid'],
|
|
191
|
+
outputFileName: 'index.html',
|
|
192
|
+
includeSourcemap: false,
|
|
193
|
+
imageQuality: {
|
|
194
|
+
jpg: 75,
|
|
195
|
+
png: [0.7, 0.8],
|
|
196
|
+
webp: 75,
|
|
197
|
+
},
|
|
198
|
+
modelCompression: {
|
|
199
|
+
method: 'draco',
|
|
200
|
+
quality: 0.8,
|
|
201
|
+
},
|
|
202
|
+
playable: {
|
|
203
|
+
inlineGameScripts: true,
|
|
204
|
+
externFiles: true,
|
|
205
|
+
mraidSupport: true,
|
|
206
|
+
},
|
|
207
|
+
},
|
|
208
|
+
moloco: {
|
|
209
|
+
sizeLimit: 5 * 1024 * 1024, // 5MB
|
|
210
|
+
outputFormat: 'html',
|
|
211
|
+
minifyCSS: true,
|
|
212
|
+
minifyJS: true,
|
|
213
|
+
compressImages: true,
|
|
214
|
+
compressModels: true,
|
|
215
|
+
injectScripts: ['fbPlayableAd'],
|
|
216
|
+
outputFileName: 'index.html',
|
|
217
|
+
includeSourcemap: false,
|
|
218
|
+
imageQuality: {
|
|
219
|
+
jpg: 75,
|
|
220
|
+
png: [0.7, 0.8],
|
|
221
|
+
webp: 75,
|
|
222
|
+
},
|
|
223
|
+
modelCompression: {
|
|
224
|
+
method: 'draco',
|
|
225
|
+
quality: 0.8,
|
|
226
|
+
},
|
|
227
|
+
playable: {
|
|
228
|
+
patchXhrOut: true,
|
|
229
|
+
inlineGameScripts: true,
|
|
230
|
+
configJsonInline: true,
|
|
231
|
+
},
|
|
232
|
+
},
|
|
233
|
+
bigo: {
|
|
234
|
+
sizeLimit: 5 * 1024 * 1024, // 5MB
|
|
235
|
+
outputFormat: 'zip',
|
|
236
|
+
minifyCSS: true,
|
|
237
|
+
minifyJS: true,
|
|
238
|
+
compressImages: true,
|
|
239
|
+
compressModels: true,
|
|
240
|
+
injectScripts: ['bigoSdk'],
|
|
241
|
+
outputFileName: 'index.html',
|
|
242
|
+
includeSourcemap: false,
|
|
243
|
+
imageQuality: {
|
|
244
|
+
jpg: 80,
|
|
245
|
+
png: [0.75, 0.85],
|
|
246
|
+
webp: 80,
|
|
247
|
+
},
|
|
248
|
+
modelCompression: {
|
|
249
|
+
method: 'draco',
|
|
250
|
+
quality: 0.85,
|
|
251
|
+
},
|
|
252
|
+
playable: {
|
|
253
|
+
inlineGameScripts: true,
|
|
254
|
+
externFiles: true,
|
|
255
|
+
},
|
|
256
|
+
},
|
|
257
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Plugin } from 'vite';
|
|
2
|
+
export interface ModelCompressionPluginOptions {
|
|
3
|
+
quality?: number;
|
|
4
|
+
method?: 'draco' | 'meshopt';
|
|
5
|
+
enabled?: boolean;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* 3D 模型压缩 Vite 插件
|
|
9
|
+
* 使用 gltf-transform 压缩 GLB/GLTF 模型
|
|
10
|
+
*/
|
|
11
|
+
export declare function viteModelCompressionPlugin(options?: ModelCompressionPluginOptions): Plugin;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { NodeIO } from '@gltf-transform/core';
|
|
2
|
+
import { ALL_EXTENSIONS } from '@gltf-transform/extensions';
|
|
3
|
+
import { draco, textureCompress } from '@gltf-transform/functions';
|
|
4
|
+
import draco3d from 'draco3dgltf';
|
|
5
|
+
/**
|
|
6
|
+
* 3D 模型压缩 Vite 插件
|
|
7
|
+
* 使用 gltf-transform 压缩 GLB/GLTF 模型
|
|
8
|
+
*/
|
|
9
|
+
export function viteModelCompressionPlugin(options = {}) {
|
|
10
|
+
const { quality = 0.8, method = 'draco', enabled = true } = options;
|
|
11
|
+
if (!enabled) {
|
|
12
|
+
return {
|
|
13
|
+
name: 'vite-plugin-model-compression',
|
|
14
|
+
// 返回空插件
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
return {
|
|
18
|
+
name: 'vite-plugin-model-compression',
|
|
19
|
+
async transform(code, id) {
|
|
20
|
+
// 只处理 GLB/GLTF 文件
|
|
21
|
+
if (!id.match(/\.(glb|gltf)$/i)) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
try {
|
|
25
|
+
// 初始化 gltf-transform
|
|
26
|
+
const io = new NodeIO()
|
|
27
|
+
.registerExtensions(ALL_EXTENSIONS)
|
|
28
|
+
.registerDependencies({
|
|
29
|
+
'draco3d.decoder': await draco3d.createDecoderModule(),
|
|
30
|
+
'draco3d.encoder': await draco3d.createEncoderModule(),
|
|
31
|
+
});
|
|
32
|
+
// 读取模型
|
|
33
|
+
const document = await io.read(id);
|
|
34
|
+
// 应用压缩
|
|
35
|
+
if (method === 'draco') {
|
|
36
|
+
await document.transform(draco({
|
|
37
|
+
quantizePosition: 14,
|
|
38
|
+
quantizeNormal: 10,
|
|
39
|
+
quantizeTexcoord: 12,
|
|
40
|
+
quantizeColor: 8,
|
|
41
|
+
}));
|
|
42
|
+
}
|
|
43
|
+
// 纹理压缩
|
|
44
|
+
await document.transform(textureCompress({
|
|
45
|
+
targetFormat: 'webp',
|
|
46
|
+
quality: quality,
|
|
47
|
+
}));
|
|
48
|
+
// 转换为 Base64 data URL
|
|
49
|
+
const glb = await io.writeBinary(document);
|
|
50
|
+
const base64 = Buffer.from(glb).toString('base64');
|
|
51
|
+
return {
|
|
52
|
+
code: `export default "data:model/gltf-binary;base64,${base64}"`,
|
|
53
|
+
map: null,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
console.warn(`警告: 无法压缩模型文件 ${id}: ${error instanceof Error ? error.message : String(error)}`);
|
|
58
|
+
// 如果压缩失败,返回原始内容
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Plugin } from 'vite';
|
|
2
|
+
import type { PlatformAdapter } from '../platforms/base.js';
|
|
3
|
+
import type { Platform } from '../types.js';
|
|
4
|
+
export interface PlatformPluginOptions {
|
|
5
|
+
platform: Platform;
|
|
6
|
+
adapter: PlatformAdapter;
|
|
7
|
+
outputDir: string;
|
|
8
|
+
baseBuildDir: string;
|
|
9
|
+
outputFormat: 'html' | 'zip';
|
|
10
|
+
externFiles?: import('../types.js').ExternFilesConfig;
|
|
11
|
+
mraidSupport?: boolean;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* 平台 Vite 插件
|
|
15
|
+
* 注入平台特定代码和处理输出格式
|
|
16
|
+
*/
|
|
17
|
+
export declare function vitePlatformPlugin(options: PlatformPluginOptions): Plugin;
|