@aiot-toolkit/aiotpack 2.0.6-beta.9 → 2.1.0-prender.1

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 (42) hide show
  1. package/lib/afterCompile/ux/UxAfterCompile.d.ts +4 -0
  2. package/lib/afterCompile/ux/UxAfterCompile.js +90 -2
  3. package/lib/compiler/javascript/JavascriptCompiler.js +11 -4
  4. package/lib/compiler/javascript/TemplateCompiler.d.ts +29 -0
  5. package/lib/compiler/javascript/TemplateCompiler.js +564 -0
  6. package/lib/compiler/javascript/ViteCompiler.d.ts +13 -0
  7. package/lib/compiler/javascript/ViteCompiler.js +414 -0
  8. package/lib/compiler/javascript/interface/IJavascriptCompileOption.d.ts +26 -0
  9. package/lib/compiler/javascript/vela/VelaWebpackConfigurator.d.ts +3 -1
  10. package/lib/compiler/javascript/vela/VelaWebpackConfigurator.js +16 -1
  11. package/lib/compiler/javascript/vela/interface/IManifest.d.ts +12 -0
  12. package/lib/compiler/javascript/vela/plugin/WrapPlugin.d.ts +10 -1
  13. package/lib/compiler/javascript/vela/plugin/WrapPlugin.js +241 -57
  14. package/lib/compiler/javascript/vela/utils/UxCompileUtil.d.ts +3 -2
  15. package/lib/compiler/javascript/vela/utils/UxCompileUtil.js +12 -4
  16. package/lib/compiler/javascript/vela/utils/VruUtil.d.ts +50 -0
  17. package/lib/compiler/javascript/vela/utils/VruUtil.js +128 -0
  18. package/lib/compiler/javascript/vela/utils/ZipUtil.d.ts +9 -0
  19. package/lib/compiler/javascript/vela/utils/ZipUtil.js +112 -6
  20. package/lib/compiler/javascript/vela/utils/webpackLoader/WebpackJsLoader.js +1 -1
  21. package/lib/config/UxConfig.d.ts +12 -5
  22. package/lib/config/UxConfig.js +7 -6
  23. package/lib/loader/ux/JsLoader.d.ts +7 -0
  24. package/lib/loader/ux/JsLoader.js +38 -8
  25. package/lib/loader/ux/vela/HmlLoader.d.ts +6 -6
  26. package/lib/loader/ux/vela/HmlLoader.js +30 -13
  27. package/lib/prerender/PrerenderVM.d.ts +86 -0
  28. package/lib/prerender/PrerenderVM.js +677 -0
  29. package/lib/prerender/StyleSerializer.d.ts +18 -0
  30. package/lib/prerender/StyleSerializer.js +92 -0
  31. package/lib/prerender/TemplateSerializer.d.ts +26 -0
  32. package/lib/prerender/TemplateSerializer.js +122 -0
  33. package/lib/prerender/index.d.ts +20 -0
  34. package/lib/prerender/index.js +519 -0
  35. package/lib/prerender/interface/IPrerenderOption.d.ts +15 -0
  36. package/lib/prerender/interface/IPrerenderOption.js +1 -0
  37. package/lib/utils/BeforeCompileUtils.d.ts +1 -1
  38. package/lib/utils/BeforeCompileUtils.js +52 -9
  39. package/lib/utils/ux/ManifestSchema.js +0 -1
  40. package/lib/utils/ux/UxFileUtils.js +1 -1
  41. package/lib/utils/ux/UxLoaderUtils.js +8 -3
  42. package/package.json +9 -6
@@ -0,0 +1,519 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ Object.defineProperty(exports, "PrerenderVM", {
7
+ enumerable: true,
8
+ get: function () {
9
+ return _PrerenderVM.default;
10
+ }
11
+ });
12
+ Object.defineProperty(exports, "TemplateSerializer", {
13
+ enumerable: true,
14
+ get: function () {
15
+ return _TemplateSerializer.default;
16
+ }
17
+ });
18
+ exports.prerender = prerender;
19
+ exports.watchChange = watchChange;
20
+ var _fsExtra = _interopRequireDefault(require("fs-extra"));
21
+ var _path = _interopRequireDefault(require("path"));
22
+ var _sharedUtils = require("@aiot-toolkit/shared-utils");
23
+ var _PrerenderVM = _interopRequireDefault(require("./PrerenderVM"));
24
+ var _TemplateSerializer = _interopRequireDefault(require("./TemplateSerializer"));
25
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
26
+ /** Cache: deviceType -> entryKey -> true (avoids re-prerendering same page per device) */
27
+ let prerenderEntryKeyCache = {};
28
+ /** Cache: resourcePath$$name -> true (avoids re-prerendering same component) */
29
+ let preRenderCache = {};
30
+ /** Cache: page path -> true (tracks pages whose css.json has been written) */
31
+ let cssCache = {};
32
+
33
+ /**
34
+ * Skip rules: app and services should not be prerendered
35
+ */
36
+ function shouldSkip(name) {
37
+ return name === 'app' || name === 'services';
38
+ }
39
+
40
+ /**
41
+ * Recursively find and prerender sub-components (import nodes).
42
+ * Tracks ancestors to detect circular dependencies.
43
+ */
44
+ function processSubComponents(node, buildPath, sourcePath, deviceType, prerenderSubComp, vm, serializer, onLog, ancestors) {
45
+ if (!prerenderSubComp) return;
46
+ if (node.import) {
47
+ const compPath = node.import;
48
+ const cacheKey = `${buildPath}$$${compPath}`;
49
+ if (!preRenderCache[cacheKey]) {
50
+ prerenderPage(compPath, buildPath, sourcePath, deviceType, prerenderSubComp, vm, serializer, onLog, ancestors);
51
+ }
52
+ }
53
+ if (node.children) {
54
+ for (const child of node.children) {
55
+ processSubComponents(child, buildPath, sourcePath, deviceType, prerenderSubComp, vm, serializer, onLog, ancestors);
56
+ }
57
+ }
58
+ }
59
+
60
+ /**
61
+ * Prerender a single page/component entry.
62
+ * @param ancestors - Set of ancestor component paths for circular dependency detection
63
+ */
64
+ function prerenderPage(page, buildPath, sourcePath, deviceType, prerenderSubComp, vm, serializer, onLog, ancestors) {
65
+ // Skip app and services
66
+ const name = page.split('/')[0];
67
+ if (shouldSkip(name)) return;
68
+
69
+ // Circular dependency detection
70
+ if (ancestors?.has(page)) {
71
+ onLog?.([{
72
+ level: _sharedUtils.Loglevel.WARN,
73
+ message: [`prerender: circular dependency detected for ${page}, skip`]
74
+ }]);
75
+ return;
76
+ }
77
+
78
+ // Check component-level cache
79
+ const cacheKey = `${buildPath}$$${page}`;
80
+ if (preRenderCache[cacheKey]) return;
81
+ preRenderCache[cacheKey] = true;
82
+
83
+ // Check device-level entry cache
84
+ if (!prerenderEntryKeyCache[deviceType]) {
85
+ prerenderEntryKeyCache[deviceType] = {};
86
+ }
87
+ if (prerenderEntryKeyCache[deviceType][page]) return;
88
+ prerenderEntryKeyCache[deviceType][page] = true;
89
+
90
+ // Load sub-component JS
91
+ const jsPath = _path.default.join(buildPath, `${page}.js`);
92
+ if (!_fsExtra.default.existsSync(jsPath)) {
93
+ onLog?.([{
94
+ level: _sharedUtils.Loglevel.WARN,
95
+ message: [`prerender: ${jsPath} not found, skip`]
96
+ }]);
97
+ return;
98
+ }
99
+ const jsCode = _fsExtra.default.readFileSync(jsPath, 'utf-8');
100
+ const {
101
+ tree,
102
+ styles
103
+ } = vm.execute(jsCode, onLog);
104
+ if (!tree) {
105
+ onLog?.([{
106
+ level: _sharedUtils.Loglevel.WARN,
107
+ message: [`prerender: failed to render ${page}, skip`]
108
+ }]);
109
+ return;
110
+ }
111
+
112
+ // Build css.json
113
+ const styleIds = Object.keys(styles).map(Number);
114
+ const mainStyleId = tree.styleObjectId ?? styleIds[styleIds.length - 1];
115
+ let cssJson = serializer.serializeCss(styles);
116
+
117
+ // Fix css.json keys: replace default "0" with actual styleObjectId from JS
118
+ const styleIdMatches = [...jsCode.matchAll(/let \$style\$(\d+)/g)];
119
+ if (styleIdMatches.length > 0 && cssJson['0']) {
120
+ const fixedCss = {};
121
+ const cssKeys = Object.keys(cssJson);
122
+ for (let i = 0; i < cssKeys.length; i++) {
123
+ const newId = styleIdMatches[i] ? styleIdMatches[i][1] : cssKeys[i];
124
+ fixedCss[newId] = cssJson[cssKeys[i]];
125
+ }
126
+ cssJson = fixedCss;
127
+ }
128
+
129
+ // Merge all styleSheets for class -> style resolution
130
+ // Use css.json (generated by WrapPlugin) which has the actual style data
131
+ const mergedSheet = {};
132
+ const pageCssPath = _path.default.join(_path.default.dirname(jsPath), `${_path.default.basename(page)}.css.json`);
133
+ if (_fsExtra.default.existsSync(pageCssPath)) {
134
+ const cssData = _fsExtra.default.readJSONSync(pageCssPath);
135
+ for (const sheet of Object.values(cssData)) {
136
+ if (sheet && typeof sheet === 'object') {
137
+ Object.assign(mergedSheet, sheet);
138
+ }
139
+ }
140
+ } else {
141
+ for (const sheet of Object.values(styles)) {
142
+ Object.assign(mergedSheet, sheet);
143
+ }
144
+ }
145
+
146
+ // Serialize template.json
147
+ const templateJson = serializer.serializeTemplate(tree, mergedSheet, mainStyleId);
148
+
149
+ // Add import paths to custom component nodes
150
+ const importsPath = jsPath.replace(/\.js$/, '.imports.json');
151
+ let importMap = {};
152
+ if (_fsExtra.default.existsSync(importsPath)) {
153
+ importMap = _fsExtra.default.readJSONSync(importsPath);
154
+ addImportPaths(templateJson, importMap);
155
+ _fsExtra.default.removeSync(importsPath); // Clean up the temp file
156
+ }
157
+
158
+ // Write files
159
+ const dir = _path.default.dirname(jsPath);
160
+ const baseName = _path.default.basename(page);
161
+ const templatePath = _path.default.join(dir, `${baseName}.template.json`);
162
+ const cssPath = _path.default.join(dir, `${baseName}.css.json`);
163
+ _fsExtra.default.ensureDirSync(dir);
164
+ _fsExtra.default.writeJSONSync(templatePath, templateJson, {
165
+ spaces: 2
166
+ });
167
+ // Only write css.json if it doesn't already have content (WrapPlugin may have generated it)
168
+ if (!_fsExtra.default.existsSync(cssPath) || _fsExtra.default.readFileSync(cssPath, 'utf-8').trim() === '{}') {
169
+ _fsExtra.default.writeJSONSync(cssPath, cssJson, {
170
+ spaces: 2
171
+ });
172
+ }
173
+ cssCache[page] = true;
174
+
175
+ // Generate template.json for sub-components from VM's component registry
176
+ for (const [compName, compImportPath] of Object.entries(importMap)) {
177
+ const compTemplatePath = _path.default.join(buildPath, `${compImportPath}.template.json`);
178
+ if (_fsExtra.default.existsSync(compTemplatePath)) continue;
179
+
180
+ // Get sub-component templates from the VM (they were registered during $app_define$ execution)
181
+ const subTemplates = vm.getSubComponentTemplates();
182
+ const compDefineId = `@app-component/${compName}`;
183
+ const subData = subTemplates.get(compDefineId);
184
+ if (subData?.tree) {
185
+ // Get the correct styleObjectId from the css.json (matches the JS $style$<id>)
186
+ const cssJsonContent = _fsExtra.default.existsSync(cssPath) ? _fsExtra.default.readJSONSync(cssPath) : cssJson;
187
+ const cssKeys = Object.keys(cssJsonContent).map(Number);
188
+ // The sub-component's styleObjectId is the one that's NOT the main page's
189
+ const subStyleId = cssKeys.find(k => k !== mainStyleId) || cssKeys[0] || 0;
190
+ const subMergedSheet = {};
191
+ if (cssJsonContent[String(subStyleId)]) {
192
+ Object.assign(subMergedSheet, cssJsonContent[String(subStyleId)]);
193
+ }
194
+ const subTemplateJson = serializer.serializeTemplate(subData.tree, subMergedSheet, subStyleId);
195
+ _fsExtra.default.ensureDirSync(_path.default.dirname(compTemplatePath));
196
+ _fsExtra.default.writeJSONSync(compTemplatePath, subTemplateJson, {
197
+ spaces: 2
198
+ });
199
+ }
200
+ }
201
+ onLog?.([{
202
+ level: _sharedUtils.Loglevel.SUCCESS,
203
+ message: [`prerender: ${page} -> template.json + css.json`]
204
+ }]);
205
+
206
+ // Recursively prerender sub-components
207
+ const nextAncestors = new Set(ancestors);
208
+ nextAncestors.add(page);
209
+ processSubComponents(tree, buildPath, sourcePath, deviceType, prerenderSubComp, vm, serializer, onLog, nextAncestors);
210
+ }
211
+
212
+ /**
213
+ * 预渲染 app.ux 的全局样式,生成 app.css.json
214
+ * app.ux 只有样式没有模板,因此只需提取 styles 并写入 css.json
215
+ */
216
+ function prerenderAppCss(buildPath, vm, serializer, onLog) {
217
+ const appJsPath = _path.default.join(buildPath, 'app.js');
218
+ if (!_fsExtra.default.existsSync(appJsPath)) return;
219
+ const jsCode = _fsExtra.default.readFileSync(appJsPath, 'utf-8');
220
+ const {
221
+ styles
222
+ } = vm.execute(jsCode, onLog);
223
+ const styleIds = Object.keys(styles);
224
+ if (!styleIds.length) return;
225
+ let cssJson = serializer.serializeCss(styles);
226
+
227
+ // Fix css.json keys: replace default "0" with actual styleObjectId from JS
228
+ const styleIdMatch = jsCode.match(/let \$style\$(\d+)/);
229
+ if (styleIdMatch && cssJson['0']) {
230
+ cssJson = {
231
+ [styleIdMatch[1]]: cssJson['0']
232
+ };
233
+ }
234
+ const cssPath = _path.default.join(buildPath, 'app.css.json');
235
+ // Only write if not already generated by WrapPlugin
236
+ if (!_fsExtra.default.existsSync(cssPath) || _fsExtra.default.readFileSync(cssPath, 'utf-8').trim() === '{}') {
237
+ _fsExtra.default.writeJSONSync(cssPath, cssJson, {
238
+ spaces: 2
239
+ });
240
+ }
241
+
242
+ // Strip style array from app.js (replace with @info reference)
243
+ stripStyleFromFile(appJsPath);
244
+ onLog?.([{
245
+ level: _sharedUtils.Loglevel.SUCCESS,
246
+ message: ['prerender: app -> app.css.json']
247
+ }]);
248
+ }
249
+
250
+ /**
251
+ * 预渲染入口
252
+ *
253
+ * 读取编译后的 JS 产物,在 VM 沙箱中执行模板函数,
254
+ * 将静态 DOM 结构序列化为 .template.json + .css.json
255
+ * 支持子组件递归预渲染和多级缓存
256
+ */
257
+ async function prerender(option, onLog) {
258
+ const {
259
+ buildPath,
260
+ sourcePath,
261
+ pages,
262
+ prerenderSubComp = true,
263
+ deviceTypes
264
+ } = option;
265
+ const vm = new _PrerenderVM.default();
266
+ const serializer = new _TemplateSerializer.default();
267
+ const types = deviceTypes?.length ? deviceTypes : ['default'];
268
+ for (const deviceType of types) {
269
+ for (const page of pages) {
270
+ prerenderPage(page, buildPath, sourcePath, deviceType, prerenderSubComp, vm, serializer, onLog, new Set());
271
+ }
272
+ }
273
+
274
+ // Generate app.css.json for global styles defined in app.ux
275
+ prerenderAppCss(buildPath, vm, serializer, onLog);
276
+
277
+ // Strip $app_template$ from JS files (template is now in template.json)
278
+ stripTemplatesFromJs(buildPath, pages, onLog);
279
+ }
280
+
281
+ /**
282
+ * Remove $app_template$ variable and module.exports.template assignment from JS files.
283
+ * After prerender generates template.json, the template function is no longer needed in JS.
284
+ */
285
+ function stripTemplatesFromJs(buildPath, pages, onLog) {
286
+ for (const page of pages) {
287
+ const jsPath = _path.default.join(buildPath, `${page}.js`);
288
+ if (!_fsExtra.default.existsSync(jsPath)) continue;
289
+
290
+ // Only strip if template.json was generated for this page
291
+ const templateJsonPath = _path.default.join(_path.default.dirname(jsPath), `${_path.default.basename(page)}.template.json`);
292
+ if (!_fsExtra.default.existsSync(templateJsonPath)) continue;
293
+ let code = _fsExtra.default.readFileSync(jsPath, 'utf-8');
294
+ let modified = false;
295
+
296
+ // Remove all occurrences of: var $app_template$ = function(vm) { ... };
297
+ while (true) {
298
+ const templateStart = code.indexOf('var $app_template$');
299
+ if (templateStart === -1) break;
300
+ let end = templateStart;
301
+ let depth = 0;
302
+ let started = false;
303
+ for (let i = templateStart; i < code.length; i++) {
304
+ if (code[i] === '{') {
305
+ depth++;
306
+ started = true;
307
+ } else if (code[i] === '}') {
308
+ depth--;
309
+ }
310
+ if (started && depth === 0) {
311
+ end = code.indexOf(';', i);
312
+ if (end === -1) end = i;else end = end + 1;
313
+ break;
314
+ }
315
+ }
316
+ code = code.slice(0, templateStart) + code.slice(end);
317
+ modified = true;
318
+ }
319
+
320
+ // Remove: module.exports.template = $app_template$; or $app_module$.exports.template = $app_template$;
321
+ const newCode = code.replace(/\s*(?:module|\$app_module\$)\.exports\.template\s*=\s*\$app_template\$;?\s*/g, '\n');
322
+ if (newCode !== code) {
323
+ code = newCode;
324
+ modified = true;
325
+ }
326
+
327
+ // Replace $app_style$ or $app_style_<id>$ arrays with @info reference
328
+ while (true) {
329
+ const styleMatch = code.match(/var \$app_style_?(\d*)\$/);
330
+ if (!styleMatch) break;
331
+ const styleStart = code.indexOf(styleMatch[0]);
332
+ const eqIdx = code.indexOf('=', styleStart);
333
+ if (eqIdx === -1) break;
334
+
335
+ // Find the opening [ or {
336
+ let openIdx = -1;
337
+ let openChar = '';
338
+ let closeChar = '';
339
+ for (let i = eqIdx + 1; i < code.length; i++) {
340
+ if (code[i] === '[') {
341
+ openIdx = i;
342
+ openChar = '[';
343
+ closeChar = ']';
344
+ break;
345
+ }
346
+ if (code[i] === '{') {
347
+ openIdx = i;
348
+ openChar = '{';
349
+ closeChar = '}';
350
+ break;
351
+ }
352
+ }
353
+ if (openIdx === -1) break;
354
+
355
+ // Find matching close
356
+ let depth = 0;
357
+ let closeIdx = -1;
358
+ let inStr = null;
359
+ let esc = false;
360
+ for (let i = openIdx; i < code.length; i++) {
361
+ const ch = code[i];
362
+ if (esc) {
363
+ esc = false;
364
+ continue;
365
+ }
366
+ if (ch === '\\') {
367
+ esc = true;
368
+ continue;
369
+ }
370
+ if (inStr) {
371
+ if (ch === inStr) inStr = null;
372
+ continue;
373
+ }
374
+ if (ch === '"' || ch === "'" || ch === '`') {
375
+ inStr = ch;
376
+ continue;
377
+ }
378
+ if (ch === openChar) depth++;else if (ch === closeChar) {
379
+ depth--;
380
+ if (depth === 0) {
381
+ closeIdx = i;
382
+ break;
383
+ }
384
+ }
385
+ }
386
+ if (closeIdx === -1) break;
387
+
388
+ // Find the styleObjectId from the variable name ($app_style_<id>$)
389
+ const varId = styleMatch[1];
390
+ let styleId = varId;
391
+ if (!styleId) {
392
+ const idM = code.match(/let \$style\$(\d+)/);
393
+ styleId = idM ? idM[1] : '0';
394
+ }
395
+
396
+ // Find semicolon after
397
+ let semiIdx = code.indexOf(';', closeIdx);
398
+ if (semiIdx === -1) semiIdx = closeIdx;
399
+ code = code.slice(0, eqIdx + 1) + ` {"@info":{"styleObjectId":${styleId}}}` + code.slice(semiIdx);
400
+ modified = true;
401
+ break; // Only one $app_style$ per component block typically
402
+ }
403
+ if (modified) {
404
+ _fsExtra.default.writeFileSync(jsPath, code);
405
+ }
406
+ }
407
+ }
408
+
409
+ /**
410
+ * Replace $app_style$ array with @info reference in a JS file
411
+ */
412
+ function stripStyleFromFile(jsPath) {
413
+ let code = _fsExtra.default.readFileSync(jsPath, 'utf-8');
414
+ const styleStart = code.indexOf('var $app_style$');
415
+ if (styleStart === -1) return;
416
+ const eqIdx = code.indexOf('=', styleStart);
417
+ if (eqIdx === -1) return;
418
+
419
+ // Find opening [ or {
420
+ let openIdx = -1,
421
+ openChar = '',
422
+ closeChar = '';
423
+ for (let i = eqIdx + 1; i < code.length; i++) {
424
+ if (code[i] === '[') {
425
+ openIdx = i;
426
+ openChar = '[';
427
+ closeChar = ']';
428
+ break;
429
+ }
430
+ if (code[i] === '{') {
431
+ openIdx = i;
432
+ openChar = '{';
433
+ closeChar = '}';
434
+ break;
435
+ }
436
+ }
437
+ if (openIdx === -1) return;
438
+
439
+ // Find matching close with brace counting
440
+ let depth = 0,
441
+ inStr = null,
442
+ esc = false,
443
+ closeIdx = -1;
444
+ for (let i = openIdx; i < code.length; i++) {
445
+ const ch = code[i];
446
+ if (esc) {
447
+ esc = false;
448
+ continue;
449
+ }
450
+ if (ch === '\\') {
451
+ esc = true;
452
+ continue;
453
+ }
454
+ if (inStr) {
455
+ if (ch === inStr) inStr = null;
456
+ continue;
457
+ }
458
+ if (ch === '"' || ch === "'" || ch === '`') {
459
+ inStr = ch;
460
+ continue;
461
+ }
462
+ if (ch === openChar) depth++;else if (ch === closeChar) {
463
+ depth--;
464
+ if (depth === 0) {
465
+ closeIdx = i;
466
+ break;
467
+ }
468
+ }
469
+ }
470
+ if (closeIdx === -1) return;
471
+
472
+ // Get styleObjectId from the $style$ variable
473
+ const idMatch = code.match(/let \$style\$(\d+)/);
474
+ const styleId = idMatch ? idMatch[1] : '0';
475
+ let semiIdx = code.indexOf(';', closeIdx);
476
+ if (semiIdx === -1) semiIdx = closeIdx;
477
+ code = code.slice(0, eqIdx + 1) + ` {"@info":{"styleObjectId":${styleId}}}` + code.slice(semiIdx);
478
+ _fsExtra.default.writeFileSync(jsPath, code);
479
+ }
480
+
481
+ /**
482
+ * Add import paths to custom component nodes in template.json
483
+ */
484
+ function addImportPaths(node, importMap) {
485
+ if (!node) return;
486
+ if (importMap[node.type]) {
487
+ node.import = importMap[node.type];
488
+ }
489
+ if (node.children) {
490
+ for (const child of node.children) {
491
+ addImportPaths(child, importMap);
492
+ }
493
+ }
494
+ }
495
+
496
+ /**
497
+ * Clear prerender caches for watch mode.
498
+ * - No args or empty array: full clear (e.g. style file changed)
499
+ * - With page paths: incremental clear for those pages only
500
+ */
501
+ function watchChange(changedPages) {
502
+ if (!changedPages || changedPages.length === 0) {
503
+ prerenderEntryKeyCache = {};
504
+ preRenderCache = {};
505
+ cssCache = {};
506
+ return;
507
+ }
508
+ for (const page of changedPages) {
509
+ for (const deviceEntries of Object.values(prerenderEntryKeyCache)) {
510
+ delete deviceEntries[page];
511
+ }
512
+ for (const key of Object.keys(preRenderCache)) {
513
+ if (key.endsWith(`$$${page}`)) {
514
+ delete preRenderCache[key];
515
+ }
516
+ }
517
+ delete cssCache[page];
518
+ }
519
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * 预渲染配置
3
+ */
4
+ export default interface IPrerenderOption {
5
+ /** 编译产物目录(绝对路径) */
6
+ buildPath: string;
7
+ /** 源码目录(绝对路径) */
8
+ sourcePath: string;
9
+ /** 页面入口列表,相对 buildPath,如 ['pages/Demo/index'] */
10
+ pages: string[];
11
+ /** 是否递归预渲染子组件,默认 true */
12
+ prerenderSubComp?: boolean;
13
+ /** 设备类型列表,来自 manifest.json deviceTypeList,默认 ['default'] */
14
+ deviceTypes?: string[];
15
+ }
@@ -0,0 +1 @@
1
+ "use strict";
@@ -10,7 +10,7 @@ declare class BeforeCompileUtils {
10
10
  * @param fileList
11
11
  * @returns
12
12
  */
13
- static getEntries: PreWork;
13
+ static getEntries: PreWork<IJavascriptCompileOption>;
14
14
  static clean: PreWork;
15
15
  /**
16
16
  * 获取项目的全局样式变量配置
@@ -11,6 +11,7 @@ var _path = _interopRequireDefault(require("path"));
11
11
  var _TranslateCache = _interopRequireDefault(require("@aiot-toolkit/parser/lib/ux/translate/vela/TranslateCache"));
12
12
  var _UxFileUtils = _interopRequireDefault(require("./ux/UxFileUtils"));
13
13
  var _IManifest = require("../compiler/javascript/vela/interface/IManifest");
14
+ var _UxUtil = _interopRequireDefault(require("@aiot-toolkit/parser/lib/ux/utils/UxUtil"));
14
15
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
15
16
  const BinaryPlugin = require('@aiot-toolkit/parser/lib/ux/translate/vela/protobuf/BinaryPlugin');
16
17
 
@@ -28,7 +29,8 @@ class BeforeCompileUtils {
28
29
  const {
29
30
  context,
30
31
  compilerOption,
31
- compilation
32
+ compilation,
33
+ onLog
32
34
  } = params;
33
35
  const {
34
36
  projectPath
@@ -45,8 +47,11 @@ class BeforeCompileUtils {
45
47
  let serviceList = [];
46
48
  const {
47
49
  router,
48
- services
50
+ services,
51
+ widgetProvider
49
52
  } = manifestContent;
53
+ // 存储widgetProvider
54
+ let widgetProviderList = [];
50
55
  if (router) {
51
56
  const {
52
57
  pages,
@@ -62,12 +67,14 @@ class BeforeCompileUtils {
62
67
  entryList.push(_path.default.join(entryDir, entry));
63
68
  } else {
64
69
  // 路径不存在
65
- _sharedUtils.ColorConsole.throw(`### manifest ### path '${_path.default.join(entryDir, entryPages.join(' | '))}' does not exist`);
70
+ onLog?.([{
71
+ level: _sharedUtils.Loglevel.THROW,
72
+ message: ['### manifest ### path', {
73
+ word: _path.default.join(entryDir, entryPages.join(' | '))
74
+ }, 'does not exist']
75
+ }]);
66
76
  }
67
77
  });
68
- } else {
69
- // 没有pages配置
70
- _sharedUtils.ColorConsole.throw(`### manifest ### No pages configuration`);
71
78
  }
72
79
  //获取轻卡路由
73
80
  if (widgets) {
@@ -78,23 +85,59 @@ class BeforeCompileUtils {
78
85
  if (_fsExtra.default.existsSync(cardPath)) {
79
86
  liteCardList.push(card + _path.default.posix.sep + cardContent.component);
80
87
  } else {
81
- // 报错
82
- _sharedUtils.ColorConsole.throw(`### manifest ### lite card path '${cardPath}' does not exist`);
88
+ onLog?.([{
89
+ level: _sharedUtils.Loglevel.THROW,
90
+ message: [`### manifest ### lite card path`, {
91
+ word: cardPath
92
+ }, `does not exist`]
93
+ }]);
83
94
  }
84
95
  }
85
96
  });
86
97
  }
87
98
  } else {
88
99
  // 没有router配置
89
- _sharedUtils.ColorConsole.throw(`### manifest ### No router configuration`);
100
+ onLog?.([{
101
+ level: _sharedUtils.Loglevel.THROW,
102
+ message: ['### manifest ### No router configuration']
103
+ }]);
104
+ }
105
+
106
+ // e2e测试入口
107
+ if (compilerOption?.enableE2e && compilerOption?.e2eConfigPath) {
108
+ const e2eConfig = _UxUtil.default.getE2eConfig({
109
+ projectPath: context.projectPath,
110
+ e2eConfigPath: compilerOption.e2eConfigPath
111
+ });
112
+ entryList.push(_path.default.join(e2eConfig.dir, e2eConfig.entry.path));
90
113
  }
91
114
  if (services) {
92
115
  serviceList = Array.isArray(services) ? services : Object.values(services);
93
116
  }
117
+ if (widgetProvider) {
118
+ const EXTENSION_JS = '.js';
119
+ for (const providerItem of widgetProvider) {
120
+ const {
121
+ path
122
+ } = providerItem;
123
+ const itemPath = _path.default.join(srcPath, path + EXTENSION_JS);
124
+ if (_fsExtra.default.existsSync(itemPath)) {
125
+ widgetProviderList.push(path + EXTENSION_JS);
126
+ } else {
127
+ onLog?.([{
128
+ level: _sharedUtils.Loglevel.THROW,
129
+ message: ['### manifest ### widgetProvider path', {
130
+ word: itemPath
131
+ }, 'does not exist']
132
+ }]);
133
+ }
134
+ }
135
+ }
94
136
  if (compilation) {
95
137
  compilation['entries'] = entryList;
96
138
  compilation['liteCards'] = liteCardList;
97
139
  compilation['services'] = serviceList;
140
+ context['widgetProvider'] = widgetProviderList;
98
141
  }
99
142
  return Promise.resolve();
100
143
  };
@@ -69,7 +69,6 @@ const ManifestSchema = {
69
69
  router: {
70
70
  // TODO 更详细的后台运行配置信息,
71
71
  type: 'object',
72
- required: ['entry', 'pages'],
73
72
  properties: {
74
73
  entry: {
75
74
  type: 'string'
@@ -67,7 +67,7 @@ class UxFileUtils {
67
67
  entry,
68
68
  pages
69
69
  } = jsonData.router;
70
- if (!pages[entry]) {
70
+ if (entry && !pages?.[entry]) {
71
71
  errors.push(new TypeError(`router.entry content: ${entry}, is missing in router.pages`));
72
72
  }
73
73
  }