@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.
Files changed (74) hide show
  1. package/README.md +96 -0
  2. package/dist/base-builder.d.ts +66 -0
  3. package/dist/base-builder.js +415 -0
  4. package/dist/converter.d.ts +35 -0
  5. package/dist/converter.js +148 -0
  6. package/dist/generators/config-generator.d.ts +7 -0
  7. package/dist/generators/config-generator.js +122 -0
  8. package/dist/generators/settings-generator.d.ts +14 -0
  9. package/dist/generators/settings-generator.js +100 -0
  10. package/dist/index.d.ts +14 -0
  11. package/dist/index.js +14 -0
  12. package/dist/loaders/playcanvas-loader.d.ts +10 -0
  13. package/dist/loaders/playcanvas-loader.js +18 -0
  14. package/dist/loaders/playcraft-loader.d.ts +10 -0
  15. package/dist/loaders/playcraft-loader.js +51 -0
  16. package/dist/platforms/applovin.d.ts +10 -0
  17. package/dist/platforms/applovin.js +67 -0
  18. package/dist/platforms/base.d.ts +29 -0
  19. package/dist/platforms/base.js +11 -0
  20. package/dist/platforms/bigo.d.ts +15 -0
  21. package/dist/platforms/bigo.js +77 -0
  22. package/dist/platforms/facebook.d.ts +9 -0
  23. package/dist/platforms/facebook.js +37 -0
  24. package/dist/platforms/google.d.ts +10 -0
  25. package/dist/platforms/google.js +53 -0
  26. package/dist/platforms/index.d.ts +14 -0
  27. package/dist/platforms/index.js +47 -0
  28. package/dist/platforms/ironsource.d.ts +10 -0
  29. package/dist/platforms/ironsource.js +71 -0
  30. package/dist/platforms/liftoff.d.ts +10 -0
  31. package/dist/platforms/liftoff.js +56 -0
  32. package/dist/platforms/moloco.d.ts +10 -0
  33. package/dist/platforms/moloco.js +53 -0
  34. package/dist/platforms/snapchat.d.ts +10 -0
  35. package/dist/platforms/snapchat.js +59 -0
  36. package/dist/platforms/tiktok.d.ts +15 -0
  37. package/dist/platforms/tiktok.js +65 -0
  38. package/dist/platforms/unity.d.ts +10 -0
  39. package/dist/platforms/unity.js +69 -0
  40. package/dist/playable-builder.d.ts +97 -0
  41. package/dist/playable-builder.js +590 -0
  42. package/dist/types.d.ts +90 -0
  43. package/dist/types.js +1 -0
  44. package/dist/vite/config-builder.d.ts +15 -0
  45. package/dist/vite/config-builder.js +212 -0
  46. package/dist/vite/platform-configs.d.ts +38 -0
  47. package/dist/vite/platform-configs.js +257 -0
  48. package/dist/vite/plugin-model-compression.d.ts +11 -0
  49. package/dist/vite/plugin-model-compression.js +63 -0
  50. package/dist/vite/plugin-platform.d.ts +17 -0
  51. package/dist/vite/plugin-platform.js +241 -0
  52. package/dist/vite/plugin-playcanvas.d.ts +18 -0
  53. package/dist/vite/plugin-playcanvas.js +711 -0
  54. package/dist/vite/plugin-source-builder.d.ts +15 -0
  55. package/dist/vite/plugin-source-builder.js +344 -0
  56. package/dist/vite-builder.d.ts +51 -0
  57. package/dist/vite-builder.js +122 -0
  58. package/package.json +51 -0
  59. package/templates/__loading__.js +100 -0
  60. package/templates/__modules__.js +47 -0
  61. package/templates/__settings__.template.js +20 -0
  62. package/templates/__start__.js +332 -0
  63. package/templates/index.html +18 -0
  64. package/templates/logo.png +0 -0
  65. package/templates/manifest.json +1 -0
  66. package/templates/patches/cannon.min.js +28 -0
  67. package/templates/patches/lz4.js +10 -0
  68. package/templates/patches/one-page-http-get.js +20 -0
  69. package/templates/patches/one-page-inline-game-scripts.js +20 -0
  70. package/templates/patches/one-page-mraid-resize-canvas.js +46 -0
  71. package/templates/patches/p2.min.js +27 -0
  72. package/templates/patches/playcraft-no-xhr.js +52 -0
  73. package/templates/playcanvas-stable.min.js +16363 -0
  74. package/templates/styles.css +43 -0
package/README.md ADDED
@@ -0,0 +1,96 @@
1
+ # @playcraft/build
2
+
3
+ PlayCraft 核心构建模块。将 PlayCanvas/PlayCraft 项目打包为 Playable Ads。
4
+
5
+ ## 功能
6
+
7
+ - 两阶段构建(Base Build → Channel Build)
8
+ - 支持 10 个广告平台
9
+ - 使用 Vite 进行资源内联与压缩
10
+ - 平台特定适配与 SDK 注入
11
+
12
+ ## 支持的平台
13
+
14
+ - Facebook
15
+ - Snapchat
16
+ - ironSource
17
+ - AppLovin
18
+ - Google Ads
19
+ - TikTok/Pangle
20
+ - Unity Ads
21
+ - Liftoff
22
+ - Moloco
23
+ - BIGO Ads
24
+
25
+ ## 使用
26
+
27
+ ### 基础用法
28
+
29
+ ```typescript
30
+ import { BaseBuilder, ViteBuilder, type BuildOptions } from '@playcraft/build';
31
+
32
+ // 阶段1:Base Build
33
+ const baseBuilder = new BaseBuilder('/path/to/project', {
34
+ outputDir: './build',
35
+ });
36
+ const baseBuildResult = await baseBuilder.build();
37
+
38
+ // 阶段2:Channel Build
39
+ const buildOptions: BuildOptions = {
40
+ platform: 'facebook',
41
+ format: 'html',
42
+ outputDir: './dist',
43
+ };
44
+
45
+ const viteBuilder = new ViteBuilder(baseBuildResult.outputDir, buildOptions);
46
+ const outputPath = await viteBuilder.build();
47
+ const sizeReport = viteBuilder.getSizeReport();
48
+
49
+ console.log('输出:', outputPath);
50
+ console.log('大小报告:', sizeReport);
51
+ ```
52
+
53
+ ### 平台适配器
54
+
55
+ ```typescript
56
+ import { createPlatformAdapter } from '@playcraft/build';
57
+
58
+ const adapter = createPlatformAdapter({
59
+ platform: 'facebook',
60
+ format: 'html',
61
+ });
62
+
63
+ console.log(adapter.getName()); // "Facebook"
64
+ console.log(adapter.getSizeLimit()); // 2097152 (2MB)
65
+ console.log(adapter.getDefaultFormat()); // "html"
66
+ ```
67
+
68
+ ## 架构
69
+
70
+ ```
71
+ @playcraft/build
72
+ ├── BaseBuilder # 阶段1:生成多文件构建产物
73
+ ├── ViteBuilder # 阶段2:Vite 单文件打包
74
+ ├── PlayableBuilder # 阶段2:旧构建器(兼容)
75
+ ├── platforms/ # 平台适配器
76
+ │ ├── FacebookAdapter
77
+ │ ├── SnapchatAdapter
78
+ │ ├── IronSourceAdapter
79
+ │ ├── AppLovinAdapter
80
+ │ ├── GoogleAdapter
81
+ │ ├── TikTokAdapter
82
+ │ ├── UnityAdapter
83
+ │ ├── LiftoffAdapter
84
+ │ ├── MolocoAdapter
85
+ │ └── BigoAdapter
86
+ └── vite/ # Vite 插件
87
+ ├── plugin-playcanvas
88
+ ├── plugin-platform
89
+ └── plugin-model-compression
90
+ ```
91
+
92
+ ## 依赖方
93
+
94
+ - `@playcraft/cli`:CLI 工具
95
+ - `@playcraft/worker`:队列消费与异步构建
96
+ - `@playcraft/backend`:类型定义用于参数校验
@@ -0,0 +1,66 @@
1
+ export interface BaseBuildOptions {
2
+ outputDir: string;
3
+ }
4
+ export interface BaseBuildOutput {
5
+ outputDir: string;
6
+ files: {
7
+ html: string;
8
+ engine: string | null;
9
+ config: string;
10
+ settings: string | null;
11
+ modules: string | null;
12
+ start: string;
13
+ scenes: string[];
14
+ assets: string[];
15
+ };
16
+ }
17
+ /**
18
+ * 基础构建器 - 生成可运行的多文件构建产物
19
+ *
20
+ * 职责:
21
+ * 1. 从源代码或构建产物加载项目
22
+ * 2. 确保所有必需文件存在且格式正确
23
+ * 3. 输出可直接运行的多文件版本
24
+ * 4. 不做任何内联或压缩
25
+ */
26
+ export declare class BaseBuilder {
27
+ private projectDir;
28
+ private options;
29
+ constructor(projectDir: string, options: BaseBuildOptions);
30
+ /**
31
+ * 执行基础构建
32
+ */
33
+ build(): Promise<BaseBuildOutput>;
34
+ /**
35
+ * 检测项目类型
36
+ */
37
+ private detectProjectType;
38
+ /**
39
+ * 从官方构建产物构建
40
+ */
41
+ private buildFromOfficial;
42
+ /**
43
+ * 验证官方构建产物
44
+ */
45
+ private validateOfficialBuild;
46
+ /**
47
+ * 复制构建文件到输出目录
48
+ */
49
+ private copyBuildFiles;
50
+ /**
51
+ * 递归复制目录
52
+ */
53
+ private copyDirectory;
54
+ /**
55
+ * 从源代码构建(使用 Vite)
56
+ */
57
+ private buildFromSource;
58
+ /**
59
+ * 扫描输出文件
60
+ */
61
+ private scanOutputFiles;
62
+ /**
63
+ * 递归扫描目录
64
+ */
65
+ private scanDirectory;
66
+ }
@@ -0,0 +1,415 @@
1
+ import fs from 'fs/promises';
2
+ import path from 'path';
3
+ import { fileURLToPath } from 'url';
4
+ import { build as viteBuild } from 'vite';
5
+ import { viteSourceBuilderPlugin } from './vite/plugin-source-builder.js';
6
+ const __filename = fileURLToPath(import.meta.url);
7
+ const __dirname = path.dirname(__filename);
8
+ /**
9
+ * 基础构建器 - 生成可运行的多文件构建产物
10
+ *
11
+ * 职责:
12
+ * 1. 从源代码或构建产物加载项目
13
+ * 2. 确保所有必需文件存在且格式正确
14
+ * 3. 输出可直接运行的多文件版本
15
+ * 4. 不做任何内联或压缩
16
+ */
17
+ export class BaseBuilder {
18
+ constructor(projectDir, options) {
19
+ this.projectDir = projectDir;
20
+ this.options = options;
21
+ }
22
+ /**
23
+ * 执行基础构建
24
+ */
25
+ async build() {
26
+ // 1. 检测项目类型
27
+ const projectType = await this.detectProjectType();
28
+ if (projectType === 'official-build') {
29
+ // 官方构建产物 - 直接复制并验证
30
+ return await this.buildFromOfficial();
31
+ }
32
+ else {
33
+ // 源代码格式(PlayCanvas 或 PlayCraft)- 使用 Vite 生成构建产物
34
+ const formatName = projectType === 'playcraft' ? 'PlayCraft' : 'PlayCanvas';
35
+ console.log(`[BaseBuilder] 检测到 ${formatName} 源代码格式,使用 Vite 构建...`);
36
+ return await this.buildFromSource();
37
+ }
38
+ }
39
+ /**
40
+ * 检测项目类型
41
+ */
42
+ async detectProjectType() {
43
+ // 1. 检查是否是官方构建产物
44
+ const buildIndicators = [
45
+ path.join(this.projectDir, 'index.html'),
46
+ path.join(this.projectDir, 'config.json'),
47
+ ];
48
+ try {
49
+ await fs.access(buildIndicators[0]);
50
+ await fs.access(buildIndicators[1]);
51
+ return 'official-build';
52
+ }
53
+ catch (error) {
54
+ // 2. 检查是否是 PlayCraft 项目格式
55
+ const manifestPath = path.join(this.projectDir, 'manifest.json');
56
+ try {
57
+ await fs.access(manifestPath);
58
+ const manifestContent = await fs.readFile(manifestPath, 'utf-8');
59
+ const manifest = JSON.parse(manifestContent);
60
+ if (manifest.format === 'playcraft' || Array.isArray(manifest.assets)) {
61
+ return 'playcraft';
62
+ }
63
+ }
64
+ catch (error) {
65
+ // manifest.json 不存在或格式不对
66
+ }
67
+ // 3. 默认视为源代码项目
68
+ return 'source';
69
+ }
70
+ }
71
+ /**
72
+ * 从官方构建产物构建
73
+ */
74
+ async buildFromOfficial() {
75
+ // 验证必需文件存在
76
+ await this.validateOfficialBuild();
77
+ // 创建输出目录
78
+ await fs.mkdir(this.options.outputDir, { recursive: true });
79
+ // 复制所有文件到输出目录
80
+ const files = await this.copyBuildFiles();
81
+ return {
82
+ outputDir: this.options.outputDir,
83
+ files,
84
+ };
85
+ }
86
+ /**
87
+ * 验证官方构建产物
88
+ */
89
+ async validateOfficialBuild() {
90
+ const requiredFiles = [
91
+ 'index.html',
92
+ 'config.json',
93
+ '__start__.js',
94
+ ];
95
+ const missingFiles = [];
96
+ for (const file of requiredFiles) {
97
+ try {
98
+ await fs.access(path.join(this.projectDir, file));
99
+ }
100
+ catch (error) {
101
+ missingFiles.push(file);
102
+ }
103
+ }
104
+ if (missingFiles.length > 0) {
105
+ throw new Error(`官方构建产物缺少必需文件: ${missingFiles.join(', ')}\n` +
106
+ `请确保项目目录包含完整的构建产物。`);
107
+ }
108
+ }
109
+ /**
110
+ * 复制构建文件到输出目录
111
+ */
112
+ async copyBuildFiles() {
113
+ const files = {
114
+ html: '',
115
+ engine: null,
116
+ config: '',
117
+ settings: null,
118
+ modules: null,
119
+ start: '',
120
+ scenes: [],
121
+ assets: [],
122
+ };
123
+ // 复制 index.html
124
+ const htmlPath = path.join(this.projectDir, 'index.html');
125
+ const outputHtmlPath = path.join(this.options.outputDir, 'index.html');
126
+ await fs.copyFile(htmlPath, outputHtmlPath);
127
+ files.html = outputHtmlPath;
128
+ // 复制 config.json
129
+ const configPath = path.join(this.projectDir, 'config.json');
130
+ const outputConfigPath = path.join(this.options.outputDir, 'config.json');
131
+ await fs.copyFile(configPath, outputConfigPath);
132
+ files.config = outputConfigPath;
133
+ // 读取 config.json 以获取场景信息
134
+ const configContent = await fs.readFile(configPath, 'utf-8');
135
+ const configJson = JSON.parse(configContent);
136
+ // 复制 __start__.js
137
+ const startPath = path.join(this.projectDir, '__start__.js');
138
+ const outputStartPath = path.join(this.options.outputDir, '__start__.js');
139
+ await fs.copyFile(startPath, outputStartPath);
140
+ files.start = outputStartPath;
141
+ // 复制 __settings__.js(如果存在)
142
+ const settingsPath = path.join(this.projectDir, '__settings__.js');
143
+ try {
144
+ await fs.access(settingsPath);
145
+ const outputSettingsPath = path.join(this.options.outputDir, '__settings__.js');
146
+ await fs.copyFile(settingsPath, outputSettingsPath);
147
+ files.settings = outputSettingsPath;
148
+ }
149
+ catch (error) {
150
+ // __settings__.js 不是必需的
151
+ }
152
+ // 复制 __modules__.js(如果存在)
153
+ const modulesPath = path.join(this.projectDir, '__modules__.js');
154
+ try {
155
+ await fs.access(modulesPath);
156
+ const outputModulesPath = path.join(this.options.outputDir, '__modules__.js');
157
+ await fs.copyFile(modulesPath, outputModulesPath);
158
+ files.modules = outputModulesPath;
159
+ }
160
+ catch (error) {
161
+ // __modules__.js 不是必需的
162
+ }
163
+ // 复制 PlayCanvas Engine(查找可能的文件名)
164
+ const engineNames = [
165
+ 'playcanvas-stable.min.js',
166
+ 'playcanvas.min.js',
167
+ '__lib__.js',
168
+ ];
169
+ for (const engineName of engineNames) {
170
+ const enginePath = path.join(this.projectDir, engineName);
171
+ try {
172
+ await fs.access(enginePath);
173
+ const outputEnginePath = path.join(this.options.outputDir, engineName);
174
+ await fs.copyFile(enginePath, outputEnginePath);
175
+ files.engine = outputEnginePath;
176
+ break;
177
+ }
178
+ catch (error) {
179
+ // 继续尝试下一个
180
+ }
181
+ }
182
+ // 复制场景文件
183
+ if (configJson.scenes && Array.isArray(configJson.scenes)) {
184
+ for (const scene of configJson.scenes) {
185
+ if (scene.url && !scene.url.startsWith('data:')) {
186
+ const scenePath = path.join(this.projectDir, scene.url);
187
+ try {
188
+ await fs.access(scenePath);
189
+ const sceneDir = path.dirname(scene.url);
190
+ if (sceneDir && sceneDir !== '.') {
191
+ const outputSceneDir = path.join(this.options.outputDir, sceneDir);
192
+ await fs.mkdir(outputSceneDir, { recursive: true });
193
+ }
194
+ const outputScenePath = path.join(this.options.outputDir, scene.url);
195
+ await fs.copyFile(scenePath, outputScenePath);
196
+ files.scenes.push(outputScenePath);
197
+ }
198
+ catch (error) {
199
+ console.warn(`警告: 场景文件不存在: ${scene.url}`);
200
+ }
201
+ }
202
+ }
203
+ }
204
+ // 复制资产文件(从 config.json 中的 assets)
205
+ if (configJson.assets) {
206
+ const assetsDir = path.join(this.options.outputDir, 'files');
207
+ await fs.mkdir(assetsDir, { recursive: true });
208
+ for (const [assetId, assetData] of Object.entries(configJson.assets)) {
209
+ const asset = assetData;
210
+ if (asset.file && asset.file.url && !asset.file.url.startsWith('data:')) {
211
+ const assetPath = path.join(this.projectDir, asset.file.url);
212
+ try {
213
+ await fs.access(assetPath);
214
+ const assetDir = path.dirname(asset.file.url);
215
+ if (assetDir && assetDir !== '.') {
216
+ const outputAssetDir = path.join(this.options.outputDir, assetDir);
217
+ await fs.mkdir(outputAssetDir, { recursive: true });
218
+ }
219
+ const outputAssetPath = path.join(this.options.outputDir, asset.file.url);
220
+ await fs.copyFile(assetPath, outputAssetPath);
221
+ files.assets.push(outputAssetPath);
222
+ }
223
+ catch (error) {
224
+ // 资产文件可能不存在(可能是内联的)
225
+ }
226
+ }
227
+ }
228
+ }
229
+ // 复制 files/ 目录(如果存在)
230
+ const filesDir = path.join(this.projectDir, 'files');
231
+ try {
232
+ const filesDirStat = await fs.stat(filesDir);
233
+ if (filesDirStat.isDirectory()) {
234
+ const outputFilesDir = path.join(this.options.outputDir, 'files');
235
+ await this.copyDirectory(filesDir, outputFilesDir);
236
+ }
237
+ }
238
+ catch (error) {
239
+ // files/ 目录可能不存在
240
+ }
241
+ // 复制 styles.css(如果存在)
242
+ const stylesPath = path.join(this.projectDir, 'styles.css');
243
+ try {
244
+ await fs.access(stylesPath);
245
+ const outputStylesPath = path.join(this.options.outputDir, 'styles.css');
246
+ await fs.copyFile(stylesPath, outputStylesPath);
247
+ }
248
+ catch (error) {
249
+ // styles.css 可能不存在
250
+ }
251
+ // 复制 manifest.json(如果存在)
252
+ const manifestPath = path.join(this.projectDir, 'manifest.json');
253
+ try {
254
+ await fs.access(manifestPath);
255
+ const outputManifestPath = path.join(this.options.outputDir, 'manifest.json');
256
+ await fs.copyFile(manifestPath, outputManifestPath);
257
+ }
258
+ catch (error) {
259
+ // manifest.json 可能不存在
260
+ }
261
+ return files;
262
+ }
263
+ /**
264
+ * 递归复制目录
265
+ */
266
+ async copyDirectory(src, dest) {
267
+ await fs.mkdir(dest, { recursive: true });
268
+ const entries = await fs.readdir(src, { withFileTypes: true });
269
+ for (const entry of entries) {
270
+ const srcPath = path.join(src, entry.name);
271
+ const destPath = path.join(dest, entry.name);
272
+ if (entry.isDirectory()) {
273
+ await this.copyDirectory(srcPath, destPath);
274
+ }
275
+ else {
276
+ await fs.copyFile(srcPath, destPath);
277
+ }
278
+ }
279
+ }
280
+ /**
281
+ * 从源代码构建(使用 Vite)
282
+ */
283
+ async buildFromSource() {
284
+ console.log('[BaseBuilder] 使用 Vite 从源代码构建...');
285
+ // 1. 创建 Vite 配置
286
+ const viteConfig = {
287
+ root: this.projectDir,
288
+ base: './',
289
+ build: {
290
+ outDir: this.options.outputDir,
291
+ emptyOutDir: true,
292
+ // 多文件输出(不内联资源)
293
+ assetsInlineLimit: 0,
294
+ // Base Build 不压缩(保持可读性和调试性)
295
+ minify: false,
296
+ cssMinify: false,
297
+ sourcemap: false,
298
+ rollupOptions: {
299
+ input: {
300
+ // 虚拟模块:用户脚本入口
301
+ 'game-scripts': 'virtual:game-scripts',
302
+ },
303
+ output: {
304
+ entryFileNames: '__[name].js',
305
+ chunkFileNames: '__[name]-[hash].js',
306
+ assetFileNames: 'files/assets/[name].[ext]',
307
+ },
308
+ // 外部化 PlayCanvas Engine(不打包)
309
+ external: ['pc', 'playcanvas'],
310
+ // 仅对用户脚本模块启用 tree-shake(引擎已外部化)
311
+ treeshake: true,
312
+ },
313
+ },
314
+ plugins: [
315
+ // 源代码构建插件
316
+ viteSourceBuilderPlugin({
317
+ projectDir: this.projectDir,
318
+ outputDir: this.options.outputDir,
319
+ }),
320
+ ],
321
+ };
322
+ // 2. 执行 Vite 构建
323
+ await viteBuild(viteConfig);
324
+ // 3. 扫描生成的文件
325
+ const files = await this.scanOutputFiles();
326
+ // 4. 返回构建结果
327
+ return {
328
+ outputDir: this.options.outputDir,
329
+ files,
330
+ };
331
+ }
332
+ /**
333
+ * 扫描输出文件
334
+ */
335
+ async scanOutputFiles() {
336
+ const files = {
337
+ html: path.join(this.options.outputDir, 'index.html'),
338
+ engine: null,
339
+ config: path.join(this.options.outputDir, 'config.json'),
340
+ settings: path.join(this.options.outputDir, '__settings__.js'),
341
+ modules: null,
342
+ start: path.join(this.options.outputDir, '__start__.js'),
343
+ scenes: [],
344
+ assets: [],
345
+ };
346
+ // 检查 engine
347
+ const enginePath = path.join(this.options.outputDir, 'playcanvas-stable.min.js');
348
+ try {
349
+ await fs.access(enginePath);
350
+ files.engine = enginePath;
351
+ }
352
+ catch (error) {
353
+ // engine 可能不存在
354
+ }
355
+ // 检查 modules
356
+ const modulesPath = path.join(this.options.outputDir, '__modules__.js');
357
+ try {
358
+ await fs.access(modulesPath);
359
+ files.modules = modulesPath;
360
+ }
361
+ catch (error) {
362
+ // modules 可能不存在
363
+ }
364
+ // 读取 config.json 以获取场景信息
365
+ try {
366
+ const configContent = await fs.readFile(files.config, 'utf-8');
367
+ const configJson = JSON.parse(configContent);
368
+ // 扫描场景文件
369
+ if (configJson.scenes && Array.isArray(configJson.scenes)) {
370
+ for (const scene of configJson.scenes) {
371
+ if (scene.url && !scene.url.startsWith('data:')) {
372
+ const scenePath = path.join(this.options.outputDir, scene.url);
373
+ try {
374
+ await fs.access(scenePath);
375
+ files.scenes.push(scenePath);
376
+ }
377
+ catch (error) {
378
+ // 场景文件可能不存在
379
+ }
380
+ }
381
+ }
382
+ }
383
+ // 扫描资产文件(从 files/ 目录)
384
+ const filesDir = path.join(this.options.outputDir, 'files');
385
+ try {
386
+ const filesDirStat = await fs.stat(filesDir);
387
+ if (filesDirStat.isDirectory()) {
388
+ await this.scanDirectory(filesDir, files.assets);
389
+ }
390
+ }
391
+ catch (error) {
392
+ // files/ 目录可能不存在
393
+ }
394
+ }
395
+ catch (error) {
396
+ console.warn('警告: 无法读取 config.json:', error);
397
+ }
398
+ return files;
399
+ }
400
+ /**
401
+ * 递归扫描目录
402
+ */
403
+ async scanDirectory(dir, files) {
404
+ const entries = await fs.readdir(dir, { withFileTypes: true });
405
+ for (const entry of entries) {
406
+ const fullPath = path.join(dir, entry.name);
407
+ if (entry.isDirectory()) {
408
+ await this.scanDirectory(fullPath, files);
409
+ }
410
+ else {
411
+ files.push(fullPath);
412
+ }
413
+ }
414
+ }
415
+ }
@@ -0,0 +1,35 @@
1
+ import type { AssetInfo, BuildOptions } from './types.js';
2
+ export declare class OnePageConverter {
3
+ private projectDir;
4
+ private options;
5
+ private assets;
6
+ constructor(projectDir: string, options: BuildOptions);
7
+ /**
8
+ * 添加资产到转换列表
9
+ */
10
+ addAsset(assetPath: string, type: string): void;
11
+ /**
12
+ * 编码所有资产为 Base64
13
+ */
14
+ encodeAssets(): Promise<void>;
15
+ /**
16
+ * 获取资产的 Base64 数据 URL
17
+ */
18
+ getDataUrl(assetPath: string): string | null;
19
+ /**
20
+ * 替换 HTML 中的 URL 为 Base64 数据 URL
21
+ */
22
+ replaceUrlsWithBase64(html: string, urlMap: Map<string, string>): string;
23
+ /**
24
+ * 内联脚本到 HTML
25
+ */
26
+ inlineScripts(html: string): Promise<string>;
27
+ /**
28
+ * 获取所有资产信息
29
+ */
30
+ getAssets(): AssetInfo[];
31
+ /**
32
+ * 获取总大小
33
+ */
34
+ getTotalSize(): number;
35
+ }