@aiot-toolkit/aiotpack 2.1.0-prender.1 → 2.1.0-prender.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.
@@ -6,10 +6,6 @@ import IJavascriptCompileOption from '../../compiler/javascript/interface/IJavas
6
6
  declare class UxAfterCompile {
7
7
  static compileJavascript: FollowWork<IJavascriptCompileOption>;
8
8
  static protobuf: FollowWork<IJavascriptCompileOption>;
9
- /**
10
- * 预渲染:在 VM 沙箱中执行编译后的模板函数,生成 .template.json + .css.json
11
- */
12
- static prerender: FollowWork<IJavascriptCompileOption>;
13
9
  static jsc: FollowWork<IJavascriptCompileOption>;
14
10
  static toRpk: FollowWork<IJavascriptCompileOption>;
15
11
  /**
@@ -19,7 +19,6 @@ var _ZipFileUtil = _interopRequireDefault(require("@aiot-toolkit/shared-utils/li
19
19
  var _ImageIcu = _interopRequireDefault(require("../../compiler/tools/icu/ImageIcu"));
20
20
  var _LiteCard = _interopRequireDefault(require("../../compiler/javascript/vela/utils/LiteCard"));
21
21
  var _UxUtil = _interopRequireDefault(require("@aiot-toolkit/parser/lib/ux/utils/UxUtil"));
22
- var _prerender = require("../../prerender");
23
22
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
24
23
  const BinaryPlugin = require('@aiot-toolkit/parser/lib/ux/translate/vela/protobuf/BinaryPlugin');
25
24
 
@@ -90,70 +89,6 @@ class UxAfterCompile {
90
89
  BinaryPlugin.createBinFiles();
91
90
  }
92
91
  };
93
-
94
- /**
95
- * 预渲染:在 VM 沙箱中执行编译后的模板函数,生成 .template.json + .css.json
96
- */
97
- static prerender = async params => {
98
- const {
99
- compilerOption,
100
- onLog,
101
- compilation
102
- } = params;
103
- if (!compilerOption || compilerOption.enablePrerender === false) {
104
- return;
105
- }
106
-
107
- // In watch mode, clear prerender caches for changed pages
108
- if (compilation && compilation.trigger !== _FileLaneTriggerType.default.START) {
109
- const {
110
- sourceRoot
111
- } = compilerOption;
112
- const srcPath = _path.default.join(compilerOption.projectPath, sourceRoot);
113
- const changedPages = (compilation.changedFiles || []).filter(f => compilation.entries?.includes(f)).map(f => {
114
- const rel = _path.default.relative(srcPath, f).replace(/\\/g, '/');
115
- return rel.replace(/\.[^.]+$/, '');
116
- });
117
- (0, _prerender.watchChange)(changedPages.length > 0 ? changedPages : undefined);
118
- }
119
- const {
120
- projectPath,
121
- outputPath,
122
- sourceRoot
123
- } = compilerOption;
124
- const buildPath = _path.default.join(projectPath, outputPath);
125
- const manifestPath = _path.default.join(projectPath, sourceRoot, 'manifest.json');
126
- if (!_fsExtra.default.existsSync(manifestPath)) {
127
- return;
128
- }
129
- const excludeList = compilerOption.prerenderExclude || [];
130
- const manifest = _fsExtra.default.readJSONSync(manifestPath);
131
- const pages = Object.keys(manifest.router?.pages || {}).filter(pageName => {
132
- if (excludeList.some(pattern => pageName.startsWith(pattern))) {
133
- onLog?.([{
134
- level: _sharedUtils.Loglevel.INFO,
135
- message: [`prerender: skip excluded ${pageName}`]
136
- }]);
137
- return false;
138
- }
139
- return true;
140
- }).map(pageName => {
141
- const pageConf = manifest.router.pages[pageName];
142
- const component = pageConf.component || 'index';
143
- return `${pageName}/${component}`;
144
- });
145
- if (!pages.length) {
146
- return;
147
- }
148
- const deviceTypes = manifest.deviceTypeList?.length ? manifest.deviceTypeList : ['default'];
149
- await (0, _prerender.prerender)({
150
- buildPath,
151
- sourcePath: _path.default.join(projectPath, sourceRoot),
152
- pages,
153
- prerenderSubComp: compilerOption.prerenderSubComp !== false,
154
- deviceTypes
155
- }, onLog);
156
- };
157
92
  static jsc = async params => {
158
93
  const {
159
94
  context,
@@ -57,9 +57,9 @@ class ViteCompiler {
57
57
  fileName: () => 'output.js'
58
58
  },
59
59
  rollupOptions: {
60
- external: id => id.startsWith('@app-module/') || id.startsWith('@system.'),
60
+ external: id => id.startsWith('@app-module/') || /^@(system|service|android|hap)\./.test(id),
61
61
  output: {
62
- globals: id => `$app_require$("@app-module/${id.replace(/^@(system|app-module)\./, '')}")`
62
+ globals: id => `$app_require$("@app-module/${id.replace(/^@(system|service|android|hap|app-module)\./, '')}")`
63
63
  }
64
64
  },
65
65
  commonjsOptions: {
@@ -88,10 +88,15 @@ class ViteCompiler {
88
88
  name: 'system-to-app-require',
89
89
  enforce: 'pre',
90
90
  transform(code, id) {
91
- if (!code.includes('@system.')) return null;
91
+ if (!/@(system|service|android|hap)\.|@app-module\//.test(code)) return null;
92
+ const NS = '(system|service|android|hap)';
92
93
  let t = code;
93
- t = t.replace(/import\s+(\w+)\s+from\s+['"]@system\.([^'"]+)['"]\s*;?/g, 'const $1 = $app_require$("@app-module/system.$2");');
94
- t = t.replace(/import\s+\{([^}]+)\}\s+from\s+['"]@system\.([^'"]+)['"]\s*;?/g, 'const {$1} = $app_require$("@app-module/system.$2");');
94
+ t = t.replace(new RegExp(`import\\s+(\\w+)\\s+from\\s+['"]@${NS}\\.([^'"]+)['"]\\s*;?`, 'g'), 'const $1 = $app_require$("@app-module/$2.$3");');
95
+ t = t.replace(new RegExp(`import\\s+\\{([^}]+)\\}\\s+from\\s+['"]@${NS}\\.([^'"]+)['"]\\s*;?`, 'g'), 'const {$1} = $app_require$("@app-module/$2.$3");');
96
+ t = t.replace(/import\s+(\w+)\s+from\s+['"]@app-module\/([^'"]+)['"]\s*;?/g, 'const $1 = $app_require$("@app-module/$2");');
97
+ t = t.replace(/import\s+\{([^}]+)\}\s+from\s+['"]@app-module\/([^'"]+)['"]\s*;?/g, 'const {$1} = $app_require$("@app-module/$2");');
98
+ t = t.replace(/import\s+['"]@app-module\/([^'"]+)['"]\s*;?/g, '$app_require$("@app-module/$1");');
99
+ t = t.replace(new RegExp(`import\\s+['"]@${NS}\\.([^'"]+)['"]\\s*;?`, 'g'), '$app_require$("@app-module/$1.$2");');
95
100
  return t !== code ? {
96
101
  code: t,
97
102
  map: null
@@ -164,53 +169,83 @@ class ViteCompiler {
164
169
  _fsExtra.default.writeJSONSync(tplPath, (0, _TemplateCompiler.uxToTemplateJson)(templateNode, sid, styleSheet, importMap, _path.default.dirname(pageName)), param.mode === 'production' ? undefined : {
165
170
  spaces: 2
166
171
  });
167
- // Generate sub-component template.json files
172
+ // Worklist BFS over nested <import> chain so transitively imported
173
+ // components (entry → compA → compB → compC) also get template.json
174
+ const worklist = [];
175
+ const visited = new Set();
168
176
  for (const [compName, compPath] of Object.entries(importMap)) {
169
177
  const compUxPath = _path.default.resolve(_path.default.dirname(id), `../../${compPath}.ux`);
170
- if (_fsExtra.default.existsSync(compUxPath)) {
171
- const compContent = _fsExtra.default.readFileSync(compUxPath, 'utf-8');
172
- const compDoc = parse5.parseFragment(compContent, {
173
- scriptingEnabled: false
174
- });
175
- const compTpl = compDoc.childNodes.find(n => n.nodeName === 'template');
176
- if (compTpl) {
177
- const compTplPath = _path.default.join(buildPath, `${compPath}.template.json`);
178
- _fsExtra.default.ensureDirSync(_path.default.dirname(compTplPath));
179
- // Get component styles
180
- const compResult = await _UxLoaderUtils.default.compileUxToJavascript({
181
- path: compUxPath,
182
- content: compContent
183
- }, {
184
- projectPath: originalProjectPath,
185
- sourceRoot
186
- }, false, param, compilation);
187
- let compStyleSheet = {};
188
- const compCode = compResult.files[0]?.content || '';
189
- const csm = compCode.match(/var \$app_style\$ = (\[[\s\S]*?\]);?\s*(?:import|export|var |const |$)/);
190
- if (csm) {
191
- compStyleSheet = (0, _TemplateCompiler.parseStyleArray)(csm[1]);
178
+ worklist.push({
179
+ compName,
180
+ compPath,
181
+ compUxPath
182
+ });
183
+ }
184
+ while (worklist.length) {
185
+ const {
186
+ compName,
187
+ compPath,
188
+ compUxPath
189
+ } = worklist.shift();
190
+ if (visited.has(compPath)) continue;
191
+ visited.add(compPath);
192
+ if (!_fsExtra.default.existsSync(compUxPath)) continue;
193
+ const compContent = _fsExtra.default.readFileSync(compUxPath, 'utf-8');
194
+ const compDoc = parse5.parseFragment(compContent, {
195
+ scriptingEnabled: false
196
+ });
197
+ let compTpl = null;
198
+ const compImportMap = {};
199
+ for (const node of compDoc.childNodes) {
200
+ if (node.nodeName === 'template') compTpl = node;else if (node.nodeName === 'import') {
201
+ const n = node.attrs?.find(a => a.name === 'name');
202
+ const s = node.attrs?.find(a => a.name === 'src');
203
+ if (n && s) {
204
+ const nestedAbsPath = _path.default.resolve(_path.default.dirname(compUxPath), s.value).replace(/\.ux$/, '');
205
+ const nestedPath = _path.default.relative(srcPath, nestedAbsPath).replace(/\\/g, '/');
206
+ compImportMap[n.value.toLowerCase()] = nestedPath;
207
+ if (!visited.has(nestedPath)) {
208
+ worklist.push({
209
+ compName: n.value.toLowerCase(),
210
+ compPath: nestedPath,
211
+ compUxPath: _path.default.resolve(_path.default.dirname(compUxPath), s.value)
212
+ });
213
+ }
192
214
  }
193
- const compSid = (0, _TemplateCompiler.getStyleObjectId)(compPath);
194
- _fsExtra.default.writeJSONSync(compTplPath, (0, _TemplateCompiler.uxToTemplateJson)(compTpl, compSid, compStyleSheet, undefined, _path.default.dirname(compPath)), param.mode === 'production' ? undefined : {
195
- spaces: 2
196
- });
197
- // Generate component css.json
198
- const compCssPath = _path.default.join(buildPath, `${compPath}.css.json`);
199
- _fsExtra.default.writeJSONSync(compCssPath, Object.keys(compStyleSheet).length ? {
200
- [String(compSid)]: compStyleSheet
201
- } : {}, param.mode === 'production' ? undefined : {
202
- spaces: 2
203
- });
204
- // Generate component js (script only)
205
- const compJsPath = _path.default.join(buildPath, `${compPath}.js`);
206
- // Extract the component object from the compiled code
207
- const exportMatch = compCode.match(/export\s+default\s+([\s\S]*?);?\s*$/);
208
- const compObj = exportMatch ? exportMatch[1].trim() : '{}';
209
- const compVarName = compName.replace(/-/g, '_') + '_default';
210
- const compJsContent = `let $style$${compSid} = {"@info":{"styleObjectId":${compSid}}};\nconst $app_style$${compSid} = $style$${compSid};\nvar ${compVarName} = ${compObj};\n$app_define$("@app-component/${compName}", [], function($app_require$, $app_exports$, $app_module$) {\n $app_module$.exports = ${compVarName}.default || ${compVarName};\n $app_module$.exports.style = $app_style$${compSid};\n});\n`;
211
- _fsExtra.default.writeFileSync(compJsPath, compJsContent);
212
215
  }
213
216
  }
217
+ if (!compTpl) continue;
218
+ const compTplPath = _path.default.join(buildPath, `${compPath}.template.json`);
219
+ _fsExtra.default.ensureDirSync(_path.default.dirname(compTplPath));
220
+ const compResult = await _UxLoaderUtils.default.compileUxToJavascript({
221
+ path: compUxPath,
222
+ content: compContent
223
+ }, {
224
+ projectPath: originalProjectPath,
225
+ sourceRoot
226
+ }, false, param, compilation);
227
+ let compStyleSheet = {};
228
+ const compCode = compResult.files[0]?.content || '';
229
+ const csm = compCode.match(/var \$app_style\$ = (\[[\s\S]*?\]);?\s*(?:import|export|var |const |$)/);
230
+ if (csm) {
231
+ compStyleSheet = (0, _TemplateCompiler.parseStyleArray)(csm[1]);
232
+ }
233
+ const compSid = (0, _TemplateCompiler.getStyleObjectId)(compPath);
234
+ _fsExtra.default.writeJSONSync(compTplPath, (0, _TemplateCompiler.uxToTemplateJson)(compTpl, compSid, compStyleSheet, compImportMap, _path.default.dirname(compPath)), param.mode === 'production' ? undefined : {
235
+ spaces: 2
236
+ });
237
+ const compCssPath = _path.default.join(buildPath, `${compPath}.css.json`);
238
+ _fsExtra.default.writeJSONSync(compCssPath, Object.keys(compStyleSheet).length ? {
239
+ [String(compSid)]: compStyleSheet
240
+ } : {}, param.mode === 'production' ? undefined : {
241
+ spaces: 2
242
+ });
243
+ const compJsPath = _path.default.join(buildPath, `${compPath}.js`);
244
+ const exportMatch = compCode.match(/export\s+default\s+([\s\S]*?);?\s*$/);
245
+ const compObj = exportMatch ? exportMatch[1].trim() : '{}';
246
+ const compVarName = compName.replace(/-/g, '_') + '_default';
247
+ const compJsContent = `let $style$${compSid} = {"@info":{"styleObjectId":${compSid}}};\nconst $app_style$${compSid} = $style$${compSid};\nvar ${compVarName} = ${compObj};\n$app_define$("@app-component/${compName}", [], function($app_require$, $app_exports$, $app_module$) {\n $app_module$.exports = ${compVarName}.default || ${compVarName};\n $app_module$.exports.style = $app_style$${compSid};\n});\n`;
248
+ _fsExtra.default.writeFileSync(compJsPath, compJsContent);
214
249
  }
215
250
  }
216
251
  }
@@ -80,23 +80,6 @@ interface IJavascriptCompileOption extends ICompileParam {
80
80
  * @example log,warn
81
81
  */
82
82
  dropConsole?: boolean | string;
83
- /**
84
- * 启用预渲染
85
- *
86
- * 编译后在 VM 沙箱中执行模板函数,生成 .template.json + .css.json
87
- * @default true
88
- */
89
- enablePrerender?: boolean;
90
- /**
91
- * 是否预渲染子组件(import 引用的组件)
92
- * @default true
93
- */
94
- prerenderSubComp?: boolean;
95
- /**
96
- * 排除不预渲染的页面路径列表
97
- * 支持前缀匹配,如 ['pages/Dynamic'] 会排除 pages/Dynamic/index 等
98
- */
99
- prerenderExclude?: string[];
100
83
  /**
101
84
  * 启动页
102
85
  */
@@ -83,9 +83,6 @@ class UxConfig {
83
83
  }, {
84
84
  worker: _UxAfterCompile.default.compileJavascript,
85
85
  workerDescribe: 'Compile javascript project'
86
- }, {
87
- worker: _UxAfterCompile.default.prerender,
88
- workerDescribe: 'Prerender pages to template.json + css.json'
89
86
  }, {
90
87
  worker: _UxAfterCompile.default.copyResource,
91
88
  workerDescribe: 'Copy resource files'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aiot-toolkit/aiotpack",
3
- "version": "2.1.0-prender.1",
3
+ "version": "2.1.0-prender.2",
4
4
  "description": "The process tool for packaging aiot projects.",
5
5
  "keywords": [
6
6
  "aiotpack"
@@ -19,16 +19,16 @@
19
19
  "test": "node ./__tests__/aiotpack.test.js"
20
20
  },
21
21
  "dependencies": {
22
- "@aiot-toolkit/generator": "2.1.0-prender.1",
23
- "@aiot-toolkit/parser": "2.1.0-prender.1",
24
- "@aiot-toolkit/shared-utils": "2.1.0-prender.1",
22
+ "@aiot-toolkit/generator": "2.1.0-prender.2",
23
+ "@aiot-toolkit/parser": "2.1.0-prender.2",
24
+ "@aiot-toolkit/shared-utils": "2.1.0-prender.2",
25
25
  "@hap-toolkit/aaptjs": "^2.0.0",
26
26
  "@rspack/core": "^1.3.9",
27
27
  "acorn": "^8.16.0",
28
28
  "aiot-parse5": "^1.0.2",
29
29
  "astring": "^1.9.0",
30
30
  "babel-loader": "^9.1.3",
31
- "file-lane": "2.1.0-prender.1",
31
+ "file-lane": "2.1.0-prender.2",
32
32
  "file-loader": "^6.2.0",
33
33
  "fs-extra": "^11.2.0",
34
34
  "jsrsasign": "^11.1.0",
@@ -45,5 +45,5 @@
45
45
  "@types/jsrsasign": "^10.5.12",
46
46
  "@types/webpack-sources": "^3.2.3"
47
47
  },
48
- "gitHead": "8bb39a59fbe7a7c22c1167e69d44c78024330cec"
48
+ "gitHead": "a0849da638ea3a9a6abb95a9cbcad400cbb6903a"
49
49
  }
@@ -1,86 +0,0 @@
1
- import { ILog } from '@aiot-toolkit/shared-utils';
2
- /** 预渲染 DOM 节点 */
3
- export interface PrerenderNode {
4
- type: string;
5
- attr?: Record<string, any>;
6
- class?: string;
7
- style?: Record<string, string>;
8
- styleObjectId?: number;
9
- children?: PrerenderNode[];
10
- events?: Record<string, string>;
11
- bind?: number;
12
- $repeat?: string;
13
- repeat?: any[];
14
- repeat_items?: PrerenderNode[];
15
- import?: string;
16
- }
17
- /** 绑定标记:文本/属性绑定 */
18
- export interface BindingMarker {
19
- $value: string;
20
- bind: 1;
21
- _staticValue?: any;
22
- [key: string]: any;
23
- }
24
- /** 循环标记 */
25
- export interface RepeatMarker {
26
- $repeat: string;
27
- repeat: any[];
28
- }
29
- /** 事件标记 */
30
- export interface EventMarker {
31
- [key: `$${string}`]: string;
32
- }
33
- /**
34
- * PrerenderVM - 在 Node.js VM 沙箱中执行编译后的模板函数,收集 DOM 树
35
- */
36
- export default class PrerenderVM {
37
- private components;
38
- private styleMap;
39
- private bindCounter;
40
- private styleSerializer;
41
- private accessedKeys;
42
- /** 创建 data Proxy,拦截访问并返回绑定标记(支持嵌套和数组) */
43
- createDataProxy(data: Record<string, any>, parentPath?: string): Record<string, any>;
44
- /** 获取已访问的 key 列表 */
45
- getAccessedKeys(): string[];
46
- /** Track binding markers accessed during a function call */
47
- private _bindingAccess;
48
- /** Create a binding marker with toString for string concatenation */
49
- private createBindingMarker;
50
- /** 文本绑定标记 */
51
- static createTextBinding(key: string): BindingMarker;
52
- /** 属性绑定标记 */
53
- static createAttrBinding(attr: string, key: string): Record<string, any>;
54
- /** 循环标记 */
55
- static createRepeatMarker(listName: string): RepeatMarker;
56
- /** 事件标记 */
57
- static createEventMarker(event: string, handler: string): EventMarker;
58
- /**
59
- * 执行编译后的 JS,收集组件定义
60
- */
61
- execute(jsCode: string, onLog?: (logs: ILog[]) => void): {
62
- tree: PrerenderNode | null;
63
- styles: Record<number, any>;
64
- };
65
- private unwrapCode;
66
- private createSandbox;
67
- private collectStyles;
68
- private normalizeStyleSheet;
69
- private createMockVM;
70
- private createNode;
71
- private createConditionalNode;
72
- private createForNode;
73
- private createBlockNode;
74
- private executeTemplate;
75
- private parseInlineStyle;
76
- private extractBindingExpression;
77
- /** Replace $item.xxx references in event handler strings with actual values */
78
- private bakeItemRefsInEvents;
79
- /**
80
- * Get all registered sub-component templates (excluding the bootstrapped main component)
81
- */
82
- getSubComponentTemplates(mainName?: string): Map<string, {
83
- tree: PrerenderNode | null;
84
- styles: Record<number, any>;
85
- }>;
86
- }