@playcraft/build 0.0.8 → 0.0.10

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 (73) hide show
  1. package/README.md +122 -6
  2. package/dist/analyzers/__tests__/optimization-analyzer.test.d.ts +1 -0
  3. package/dist/analyzers/__tests__/optimization-analyzer.test.js +169 -0
  4. package/dist/analyzers/build-analyzer.d.ts +98 -0
  5. package/dist/analyzers/build-analyzer.js +1160 -0
  6. package/dist/analyzers/enhanced-report-template.d.ts +13 -0
  7. package/dist/analyzers/enhanced-report-template.js +957 -0
  8. package/dist/analyzers/index.d.ts +6 -0
  9. package/dist/analyzers/index.js +9 -0
  10. package/dist/analyzers/optimization-analyzer.d.ts +88 -0
  11. package/dist/analyzers/optimization-analyzer.js +278 -0
  12. package/dist/analyzers/playable-analyzer.d.ts +91 -0
  13. package/dist/analyzers/playable-analyzer.js +977 -0
  14. package/dist/analyzers/report-template.d.ts +50 -0
  15. package/dist/analyzers/report-template.js +591 -0
  16. package/dist/analyzers/scene-asset-collector.js +8 -0
  17. package/dist/base-builder.d.ts +9 -0
  18. package/dist/base-builder.js +156 -2
  19. package/dist/build-state-manager.d.ts +110 -0
  20. package/dist/build-state-manager.js +169 -0
  21. package/dist/generators/config-generator.d.ts +2 -0
  22. package/dist/generators/config-generator.js +179 -10
  23. package/dist/index.d.ts +8 -0
  24. package/dist/index.js +6 -0
  25. package/dist/loaders/playcanvas-loader.d.ts +7 -0
  26. package/dist/loaders/playcanvas-loader.js +17 -0
  27. package/dist/platforms/adikteev.js +4 -2
  28. package/dist/platforms/applovin.js +9 -3
  29. package/dist/platforms/inmobi.js +4 -2
  30. package/dist/platforms/ironsource.js +4 -1
  31. package/dist/platforms/liftoff.js +8 -3
  32. package/dist/platforms/snapchat.js +8 -2
  33. package/dist/platforms/unity.js +8 -2
  34. package/dist/playable-builder.js +3 -1
  35. package/dist/state/build-state-manager.d.ts +174 -0
  36. package/dist/state/build-state-manager.js +235 -0
  37. package/dist/state/index.d.ts +4 -0
  38. package/dist/state/index.js +2 -0
  39. package/dist/state/state-to-report-converter.d.ts +141 -0
  40. package/dist/state/state-to-report-converter.js +177 -0
  41. package/dist/types.d.ts +1 -0
  42. package/dist/utils.d.ts +4 -0
  43. package/dist/utils.js +11 -0
  44. package/dist/vite/config-builder.js +11 -1
  45. package/dist/vite/platform-configs.d.ts +1 -0
  46. package/dist/vite/platform-configs.js +1 -0
  47. package/dist/vite/plugin-build-state.d.ts +13 -0
  48. package/dist/vite/plugin-build-state.js +147 -0
  49. package/dist/vite/plugin-esm-html-generator.js +11 -2
  50. package/dist/vite/plugin-platform.js +3 -1
  51. package/dist/vite/plugin-playcanvas.d.ts +1 -0
  52. package/dist/vite/plugin-playcanvas.js +160 -20
  53. package/dist/vite/plugin-source-builder.js +1 -0
  54. package/dist/vite/plugin-template-minifier.d.ts +20 -0
  55. package/dist/vite/plugin-template-minifier.js +392 -0
  56. package/package.json +12 -12
  57. package/templates/patches/one-page-mraid-resize-canvas.js +18 -4
  58. package/dist/templates/__loading__.js +0 -100
  59. package/dist/templates/__modules__.js +0 -47
  60. package/dist/templates/__settings__.template.js +0 -20
  61. package/dist/templates/__start__.js +0 -332
  62. package/dist/templates/index.html +0 -18
  63. package/dist/templates/logo.png +0 -0
  64. package/dist/templates/manifest.json +0 -1
  65. package/dist/templates/patches/cannon.min.js +0 -28
  66. package/dist/templates/patches/lz4.js +0 -10
  67. package/dist/templates/patches/one-page-http-get.js +0 -20
  68. package/dist/templates/patches/one-page-inline-game-scripts.js +0 -52
  69. package/dist/templates/patches/one-page-mraid-resize-canvas.js +0 -46
  70. package/dist/templates/patches/p2.min.js +0 -27
  71. package/dist/templates/patches/playcraft-no-xhr.js +0 -76
  72. package/dist/templates/playcanvas-stable.min.js +0 -16363
  73. package/dist/templates/styles.css +0 -43
package/README.md CHANGED
@@ -1,13 +1,129 @@
1
1
  # @playcraft/build
2
2
 
3
- PlayCraft 核心构建模块。将 PlayCanvas/PlayCraft 项目打包为 Playable Ads
3
+ PlayCraft 构建系统核心包,提供 Playable Ads 的构建、打包和优化功能。
4
4
 
5
- ## 功能
5
+ ## 功能特性
6
6
 
7
- - 两阶段构建(Base Build → Channel Build)
8
- - 支持 10 个广告平台
9
- - 使用 Vite 进行资源内联与压缩
10
- - 平台特定适配与 SDK 注入
7
+ ### 🎯 核心功能
8
+
9
+ - **多平台支持**:支持 10+ 主流广告平台(Facebook、Snapchat、ironSource 等)
10
+ - **场景过滤**:智能分析场景依赖,只打包选中场景使用的资源
11
+ - **资源优化**:自动精简资源元数据,显著减少 config.json 体积
12
+ - **两阶段构建**:基础构建 + 渠道适配,灵活高效
13
+
14
+ ### 📦 config.json 优化
15
+
16
+ `config.json` 是 PlayCanvas 项目的核心配置文件,包含所有资源的元数据。在大型项目中,这个文件可能达到 2MB 甚至更大,严重影响 Playable Ads 的加载性能。
17
+
18
+ #### 优化策略
19
+
20
+ **1. 资源元数据精简(默认启用)**
21
+
22
+ 自动删除运行时不需要的字段,包括:
23
+ - `tags` - 编辑器标签
24
+ - `i18n` - 国际化数据
25
+ - `meta` - 编辑器元数据
26
+ - `thumbnails` - 缩略图
27
+ - `revision` - 版本号
28
+ - `created_at` / `updated_at` - 时间戳
29
+ - `user` / `branch_id` - 用户和分支信息
30
+
31
+ **预期效果**:减少 30-50% 的 config.json 体积
32
+
33
+ **2. 场景依赖分析**
34
+
35
+ 结合场景过滤功能,只包含选中场景实际使用的资源。
36
+
37
+ **预期效果**:减少 40-70% 的资源数量
38
+
39
+ **3. 组合优化**
40
+
41
+ 同时启用元数据精简和场景过滤,可以实现最佳优化效果。
42
+
43
+ **预期效果**:总体减少 60-80% 的 config.json 体积
44
+
45
+ #### 使用方式
46
+
47
+ ```typescript
48
+ import { generateConfig } from '@playcraft/build';
49
+
50
+ // 默认启用元数据精简
51
+ const config = await generateConfig(projectConfig, {
52
+ selectedScenes: ['MainScene'], // 场景过滤
53
+ projectDir: './project',
54
+ stripMetadata: true, // 元数据精简(默认 true)
55
+ });
56
+
57
+ // 禁用元数据精简(保留完整元数据)
58
+ const configFull = await generateConfig(projectConfig, {
59
+ stripMetadata: false,
60
+ });
61
+ ```
62
+
63
+ #### 优化效果示例
64
+
65
+ ```
66
+ 🗜️ 元数据精简统计:
67
+ - 原始大小: 2048.5 KB
68
+ - 精简后: 1024.3 KB
69
+ - 节省: 1024.2 KB (50.0%)
70
+
71
+ 📊 资源过滤统计:
72
+ - 总资源数: 450
73
+ - 场景依赖: 180
74
+ - 将节省: 270 个资源 (60.0%)
75
+ ```
76
+
77
+ #### 运行时兼容性
78
+
79
+ 精简后的 config.json 完全兼容 PlayCanvas 引擎,所有运行时需要的字段都会保留:
80
+
81
+ - ✅ 资源 URL 和文件信息
82
+ - ✅ 纹理过滤和寻址模式
83
+ - ✅ 材质配置
84
+ - ✅ 模型映射信息
85
+ - ✅ 脚本加载配置
86
+ - ✅ 动画和音频时长
87
+ - ✅ 字体和精灵配置
88
+
89
+ #### 高级优化方案
90
+
91
+ 如果需要进一步优化,可以考虑:
92
+
93
+ **方案二:数据压缩**
94
+ - 使用 lz4/gzip 压缩 config.json
95
+ - 运行时解压
96
+ - 预期减少 60-70% 体积
97
+
98
+ **方案三:按需加载**
99
+ - 只在 config.json 中保留资源引用
100
+ - 详细元数据按需加载
101
+ - 预期减少 70-80% 体积
102
+
103
+ ## API 文档
104
+
105
+ ### generateConfig(projectConfig, options?)
106
+
107
+ 生成 PlayCanvas 构建产物格式的 config.json。
108
+
109
+ **参数**:
110
+ - `projectConfig`: PlayCanvasProject | PlayCraftProject - 项目配置
111
+ - `options`: GenerateConfigOptions - 可选配置
112
+ - `selectedScenes?: string[]` - 选中的场景 ID 或名称列表
113
+ - `projectDir?: string` - 项目目录(用于加载完整场景文件)
114
+ - `stripMetadata?: boolean` - 是否精简资源元数据(默认 true)
115
+
116
+ **返回值**:Promise<any> - config.json 对象
117
+
118
+ ## 相关文档
119
+
120
+ - [构建架构设计](../../docs/cli/build-architecture.md)
121
+ - [平台规格对照表](../../docs/cli/各渠道Playable规格对照表.md)
122
+ - [优化对照](../../docs/cli/playable-ads-optimization.md)
123
+
124
+ ## License
125
+
126
+ MIT
11
127
 
12
128
  ## 支持的平台
13
129
 
@@ -0,0 +1,169 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { OptimizationAnalyzer } from '../optimization-analyzer.js';
3
+ describe('OptimizationAnalyzer', () => {
4
+ it('should detect large uncompressed files', () => {
5
+ const state = {
6
+ version: '1.0.0',
7
+ buildTime: Date.now(),
8
+ assets: {
9
+ 'large-file': {
10
+ id: 'large-file',
11
+ originalName: 'large-file.js',
12
+ originalPath: '/path/to/large-file.js',
13
+ originalSize: 200 * 1024, // 200KB
14
+ finalSize: 195 * 1024, // 只压缩了 5KB
15
+ totalCompressionRatio: 0.025, // 2.5% 压缩率
16
+ type: 'script',
17
+ processingHistory: [
18
+ {
19
+ stage: 'base-build',
20
+ name: 'large-file.js',
21
+ size: 195 * 1024,
22
+ optimizations: [],
23
+ },
24
+ ],
25
+ },
26
+ },
27
+ stages: [],
28
+ };
29
+ const analyzer = new OptimizationAnalyzer(state);
30
+ const result = analyzer.analyze();
31
+ expect(result.totalSuggestions).toBeGreaterThan(0);
32
+ expect(result.suggestions.some(s => s.type === 'large-uncompressed')).toBe(true);
33
+ });
34
+ it('should detect PNG images that can be converted to WebP', () => {
35
+ const state = {
36
+ version: '1.0.0',
37
+ buildTime: Date.now(),
38
+ assets: {
39
+ 'image': {
40
+ id: 'image',
41
+ originalName: 'image.png',
42
+ originalPath: '/path/to/image.png',
43
+ originalSize: 100 * 1024, // 100KB
44
+ finalSize: 100 * 1024,
45
+ totalCompressionRatio: 0,
46
+ type: 'texture',
47
+ processingHistory: [
48
+ {
49
+ stage: 'base-build',
50
+ name: 'image.png',
51
+ size: 100 * 1024,
52
+ optimizations: [],
53
+ },
54
+ ],
55
+ },
56
+ },
57
+ stages: [],
58
+ };
59
+ const analyzer = new OptimizationAnalyzer(state);
60
+ const result = analyzer.analyze();
61
+ expect(result.suggestions.some(s => s.type === 'format-conversion')).toBe(true);
62
+ });
63
+ it('should detect missing minification', () => {
64
+ const state = {
65
+ version: '1.0.0',
66
+ buildTime: Date.now(),
67
+ assets: {
68
+ 'script': {
69
+ id: 'script',
70
+ originalName: 'script.js',
71
+ originalPath: '/path/to/script.js',
72
+ originalSize: 50 * 1024, // 50KB
73
+ finalSize: 50 * 1024,
74
+ totalCompressionRatio: 0,
75
+ type: 'script',
76
+ processingHistory: [
77
+ {
78
+ stage: 'base-build',
79
+ name: 'script.js',
80
+ size: 50 * 1024,
81
+ optimizations: [], // 没有 minify
82
+ },
83
+ ],
84
+ },
85
+ },
86
+ stages: [],
87
+ };
88
+ const analyzer = new OptimizationAnalyzer(state);
89
+ const result = analyzer.analyze();
90
+ expect(result.suggestions.some(s => s.type === 'enable-minify')).toBe(true);
91
+ });
92
+ it('should group suggestions by severity', () => {
93
+ const state = {
94
+ version: '1.0.0',
95
+ buildTime: Date.now(),
96
+ assets: {
97
+ 'large-uncompressed': {
98
+ id: 'large-uncompressed',
99
+ originalName: 'large.js',
100
+ originalPath: '/path/to/large.js',
101
+ originalSize: 200 * 1024,
102
+ finalSize: 195 * 1024,
103
+ totalCompressionRatio: 0.025,
104
+ type: 'script',
105
+ processingHistory: [
106
+ {
107
+ stage: 'base-build',
108
+ name: 'large.js',
109
+ size: 195 * 1024,
110
+ optimizations: [],
111
+ },
112
+ ],
113
+ },
114
+ 'png-image': {
115
+ id: 'png-image',
116
+ originalName: 'image.png',
117
+ originalPath: '/path/to/image.png',
118
+ originalSize: 100 * 1024,
119
+ finalSize: 100 * 1024,
120
+ totalCompressionRatio: 0,
121
+ type: 'texture',
122
+ processingHistory: [
123
+ {
124
+ stage: 'base-build',
125
+ name: 'image.png',
126
+ size: 100 * 1024,
127
+ optimizations: [],
128
+ },
129
+ ],
130
+ },
131
+ },
132
+ stages: [],
133
+ };
134
+ const analyzer = new OptimizationAnalyzer(state);
135
+ const result = analyzer.analyze();
136
+ expect(result.bySeverity.high.length).toBeGreaterThan(0);
137
+ expect(result.bySeverity.medium.length).toBeGreaterThan(0);
138
+ });
139
+ it('should calculate total estimated savings', () => {
140
+ const state = {
141
+ version: '1.0.0',
142
+ buildTime: Date.now(),
143
+ assets: {
144
+ 'large-file': {
145
+ id: 'large-file',
146
+ originalName: 'large-file.js',
147
+ originalPath: '/path/to/large-file.js',
148
+ originalSize: 200 * 1024,
149
+ finalSize: 195 * 1024,
150
+ totalCompressionRatio: 0.025,
151
+ type: 'script',
152
+ processingHistory: [
153
+ {
154
+ stage: 'base-build',
155
+ name: 'large-file.js',
156
+ size: 195 * 1024,
157
+ optimizations: [],
158
+ },
159
+ ],
160
+ },
161
+ },
162
+ stages: [],
163
+ };
164
+ const analyzer = new OptimizationAnalyzer(state);
165
+ const result = analyzer.analyze();
166
+ expect(result.totalEstimatedSavings).toBeGreaterThan(0);
167
+ expect(result.estimatedOptimizationRate).toBeGreaterThan(0);
168
+ });
169
+ });
@@ -0,0 +1,98 @@
1
+ export interface FileAnalysis {
2
+ path: string;
3
+ relativePath: string;
4
+ size: number;
5
+ sizeFormatted: string;
6
+ dataUrlSize: number;
7
+ dataUrlSizeFormatted: string;
8
+ type: string;
9
+ category: string;
10
+ }
11
+ export interface BuildAnalysisReport {
12
+ totalFiles: number;
13
+ totalSize: number;
14
+ totalSizeFormatted: string;
15
+ estimatedHtmlSize: number;
16
+ estimatedHtmlSizeFormatted: string;
17
+ files: FileAnalysis[];
18
+ byCategory: Record<string, {
19
+ count: number;
20
+ size: number;
21
+ sizeFormatted: string;
22
+ dataUrlSize: number;
23
+ dataUrlSizeFormatted: string;
24
+ }>;
25
+ byType: Record<string, {
26
+ count: number;
27
+ size: number;
28
+ sizeFormatted: string;
29
+ }>;
30
+ }
31
+ /**
32
+ * 构建分析器 - 分析构建产物并生成详细报告
33
+ */
34
+ export declare class BuildAnalyzer {
35
+ private buildDir;
36
+ private outputDir;
37
+ constructor(buildDir: string, outputDir: string);
38
+ /**
39
+ * 分析构建产物
40
+ */
41
+ analyze(): Promise<BuildAnalysisReport>;
42
+ /**
43
+ * 从 build-state.json 分析
44
+ */
45
+ private analyzeFromState;
46
+ /**
47
+ * 从文件系统分析(回退方案)
48
+ */
49
+ private analyzeFromFileSystem;
50
+ /**
51
+ * 估算 data URL 大小
52
+ */
53
+ private estimateDataUrlSize;
54
+ /**
55
+ * 映射资产类型到文件类型
56
+ */
57
+ private mapAssetTypeToFileType;
58
+ /**
59
+ * 映射资产类型到分类
60
+ */
61
+ private mapAssetTypeToCategory;
62
+ /**
63
+ * 生成 HTML 报告
64
+ */
65
+ generateHTMLReport(report: BuildAnalysisReport): Promise<string>;
66
+ /**
67
+ * 扫描目录获取所有文件
68
+ */
69
+ private scanDirectory;
70
+ /**
71
+ * 分析单个文件
72
+ */
73
+ private analyzeFile;
74
+ /**
75
+ * 获取文件类型
76
+ */
77
+ private getFileType;
78
+ /**
79
+ * 获取文件分类
80
+ */
81
+ private getFileCategory;
82
+ /**
83
+ * 获取 data URL 前缀
84
+ */
85
+ private getDataUrlPrefix;
86
+ /**
87
+ * 格式化文件大小
88
+ */
89
+ private formatSize;
90
+ /**
91
+ * 生成树状图数据结构
92
+ */
93
+ private generateTreemapData;
94
+ /**
95
+ * 生成 HTML 报告内容
96
+ */
97
+ private generateReportHTML;
98
+ }