@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.
- package/lib/afterCompile/ux/UxAfterCompile.d.ts +4 -0
- package/lib/afterCompile/ux/UxAfterCompile.js +90 -2
- package/lib/compiler/javascript/JavascriptCompiler.js +11 -4
- package/lib/compiler/javascript/TemplateCompiler.d.ts +29 -0
- package/lib/compiler/javascript/TemplateCompiler.js +564 -0
- package/lib/compiler/javascript/ViteCompiler.d.ts +13 -0
- package/lib/compiler/javascript/ViteCompiler.js +414 -0
- package/lib/compiler/javascript/interface/IJavascriptCompileOption.d.ts +26 -0
- package/lib/compiler/javascript/vela/VelaWebpackConfigurator.d.ts +3 -1
- package/lib/compiler/javascript/vela/VelaWebpackConfigurator.js +16 -1
- package/lib/compiler/javascript/vela/interface/IManifest.d.ts +12 -0
- package/lib/compiler/javascript/vela/plugin/WrapPlugin.d.ts +10 -1
- package/lib/compiler/javascript/vela/plugin/WrapPlugin.js +241 -57
- package/lib/compiler/javascript/vela/utils/UxCompileUtil.d.ts +3 -2
- package/lib/compiler/javascript/vela/utils/UxCompileUtil.js +12 -4
- package/lib/compiler/javascript/vela/utils/VruUtil.d.ts +50 -0
- package/lib/compiler/javascript/vela/utils/VruUtil.js +128 -0
- package/lib/compiler/javascript/vela/utils/ZipUtil.d.ts +9 -0
- package/lib/compiler/javascript/vela/utils/ZipUtil.js +112 -6
- package/lib/compiler/javascript/vela/utils/webpackLoader/WebpackJsLoader.js +1 -1
- package/lib/config/UxConfig.d.ts +12 -5
- package/lib/config/UxConfig.js +7 -6
- package/lib/loader/ux/JsLoader.d.ts +7 -0
- package/lib/loader/ux/JsLoader.js +38 -8
- package/lib/loader/ux/vela/HmlLoader.d.ts +6 -6
- package/lib/loader/ux/vela/HmlLoader.js +30 -13
- package/lib/prerender/PrerenderVM.d.ts +86 -0
- package/lib/prerender/PrerenderVM.js +677 -0
- package/lib/prerender/StyleSerializer.d.ts +18 -0
- package/lib/prerender/StyleSerializer.js +92 -0
- package/lib/prerender/TemplateSerializer.d.ts +26 -0
- package/lib/prerender/TemplateSerializer.js +122 -0
- package/lib/prerender/index.d.ts +20 -0
- package/lib/prerender/index.js +519 -0
- package/lib/prerender/interface/IPrerenderOption.d.ts +15 -0
- package/lib/prerender/interface/IPrerenderOption.js +1 -0
- package/lib/utils/BeforeCompileUtils.d.ts +1 -1
- package/lib/utils/BeforeCompileUtils.js +52 -9
- package/lib/utils/ux/ManifestSchema.js +0 -1
- package/lib/utils/ux/UxFileUtils.js +1 -1
- package/lib/utils/ux/UxLoaderUtils.js +8 -3
- package/package.json +9 -6
|
@@ -5,81 +5,265 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.default = void 0;
|
|
7
7
|
var _core = require("@rspack/core");
|
|
8
|
+
var _TemplateCompiler = require("../../TemplateCompiler");
|
|
8
9
|
var _webpackSources = require("webpack-sources");
|
|
10
|
+
var _path = _interopRequireDefault(require("path"));
|
|
11
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
9
12
|
class WrapPlugin {
|
|
10
13
|
constructor(compilerOption) {
|
|
11
14
|
this.compilerOption = compilerOption;
|
|
12
15
|
}
|
|
13
16
|
apply(compiler) {
|
|
14
|
-
// 给入口文件加上包裹函数
|
|
15
17
|
compiler.hooks.compilation.tap('WrapPlugin', compilation => {
|
|
16
18
|
compilation.hooks.processAssets.tap({
|
|
17
19
|
name: 'WrapPlugin',
|
|
18
20
|
stage: _core.Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE
|
|
19
|
-
}, () =>
|
|
20
|
-
this.wrap(compilation);
|
|
21
|
-
});
|
|
21
|
+
}, () => this.wrap(compilation));
|
|
22
22
|
});
|
|
23
23
|
}
|
|
24
|
+
getComponentName(entry) {
|
|
25
|
+
return _path.default.parse(entry).name;
|
|
26
|
+
}
|
|
27
|
+
findMatching(code, start, open, close) {
|
|
28
|
+
let depth = 0,
|
|
29
|
+
inStr = null,
|
|
30
|
+
esc = false;
|
|
31
|
+
for (let i = start; i < code.length; i++) {
|
|
32
|
+
const ch = code[i];
|
|
33
|
+
if (esc) {
|
|
34
|
+
esc = false;
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
if (ch === '\\') {
|
|
38
|
+
esc = true;
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
if (inStr) {
|
|
42
|
+
if (ch === inStr) inStr = null;
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
if (ch === '"' || ch === "'" || ch === '`') {
|
|
46
|
+
inStr = ch;
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
if (ch === open) depth++;else if (ch === close) {
|
|
50
|
+
depth--;
|
|
51
|
+
if (depth === 0) return i;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return -1;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Extract keyed modules from rspack's __webpack_modules__ object
|
|
58
|
+
*/
|
|
59
|
+
extractModules(code) {
|
|
60
|
+
const idx = code.indexOf('var __webpack_modules__');
|
|
61
|
+
if (idx === -1) return [{
|
|
62
|
+
key: '',
|
|
63
|
+
body: code
|
|
64
|
+
}];
|
|
65
|
+
const braceIdx = code.indexOf('{', idx + 23);
|
|
66
|
+
let openIdx = code.indexOf('(', idx + 23);
|
|
67
|
+
if (openIdx === -1 || braceIdx !== -1 && braceIdx < openIdx) openIdx = braceIdx;
|
|
68
|
+
if (openIdx === -1) return [{
|
|
69
|
+
key: '',
|
|
70
|
+
body: code
|
|
71
|
+
}];
|
|
72
|
+
const closeIdx = code[openIdx] === '(' ? this.findMatching(code, openIdx, '(', ')') : this.findMatching(code, openIdx, '{', '}');
|
|
73
|
+
if (closeIdx === -1) return [{
|
|
74
|
+
key: '',
|
|
75
|
+
body: code
|
|
76
|
+
}];
|
|
77
|
+
const inner = code.slice(openIdx + 1, closeIdx);
|
|
78
|
+
const results = [];
|
|
79
|
+
let pos = 0;
|
|
80
|
+
while (pos < inner.length) {
|
|
81
|
+
const kStart = inner.indexOf('"', pos);
|
|
82
|
+
if (kStart === -1) break;
|
|
83
|
+
const kEnd = inner.indexOf('"', kStart + 1);
|
|
84
|
+
if (kEnd === -1) break;
|
|
85
|
+
const key = inner.slice(kStart + 1, kEnd);
|
|
86
|
+
pos = kEnd + 1;
|
|
87
|
+
const fIdx = inner.indexOf('function', pos);
|
|
88
|
+
if (fIdx === -1) break;
|
|
89
|
+
const bOpen = inner.indexOf('{', fIdx);
|
|
90
|
+
if (bOpen === -1) break;
|
|
91
|
+
const bClose = this.findMatching(inner, bOpen, '{', '}');
|
|
92
|
+
if (bClose === -1) break;
|
|
93
|
+
results.push({
|
|
94
|
+
key,
|
|
95
|
+
body: inner.slice(bOpen + 1, bClose).trim()
|
|
96
|
+
});
|
|
97
|
+
pos = bClose + 1;
|
|
98
|
+
}
|
|
99
|
+
return results.length > 0 ? results : [{
|
|
100
|
+
key: '',
|
|
101
|
+
body: code
|
|
102
|
+
}];
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Clean a module body into blueos-pack format component block
|
|
106
|
+
*/
|
|
107
|
+
buildBlock(body, defineId, styleId) {
|
|
108
|
+
let s = body;
|
|
109
|
+
// Remove ALL _interopRequireDefault function definitions FIRST (before unwrapping calls)
|
|
110
|
+
while (true) {
|
|
111
|
+
const iIdx = s.indexOf('function _interopRequireDefault');
|
|
112
|
+
if (iIdx === -1) break;
|
|
113
|
+
const bStart = s.indexOf('{', iIdx);
|
|
114
|
+
if (bStart === -1) break;
|
|
115
|
+
const bEnd = this.findMatching(s, bStart, '{', '}');
|
|
116
|
+
if (bEnd === -1) break;
|
|
117
|
+
s = s.slice(0, iIdx) + s.slice(bEnd + 1);
|
|
118
|
+
}
|
|
119
|
+
// Then unwrap _interopRequireDefault() calls
|
|
120
|
+
const interopVars = [];
|
|
121
|
+
s = s.replace(/_interopRequireDefault\(([^)]+)\)/g, (_, inner) => inner);
|
|
122
|
+
// Remove .default from interop vars
|
|
123
|
+
for (const v of interopVars) {
|
|
124
|
+
s = s.replace(new RegExp(`${v}\\.default\\.`, 'g'), `${v}.`);
|
|
125
|
+
s = s.replace(new RegExp(`${v}\\.default([^.]|$)`, 'g'), `${v}$1`);
|
|
126
|
+
}
|
|
127
|
+
// Remove boilerplate
|
|
128
|
+
// Replace $app_style$ array with @info reference using unique per-component name
|
|
129
|
+
const styleIdx = s.indexOf('var $app_style$');
|
|
130
|
+
if (styleIdx !== -1) {
|
|
131
|
+
const bi = s.indexOf('[', styleIdx);
|
|
132
|
+
if (bi !== -1) {
|
|
133
|
+
const be = this.findMatching(s, bi, '[', ']');
|
|
134
|
+
if (be !== -1) {
|
|
135
|
+
let se = s.indexOf(';', be);
|
|
136
|
+
if (se === -1) se = be;
|
|
137
|
+
// Remove the entire var $app_style$ line (we use $app_style$<id> instead)
|
|
138
|
+
s = s.slice(0, styleIdx) + s.slice(se + 1);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
// Also remove any remaining var $app_style$ = {...} (already @info format)
|
|
143
|
+
s = s.replace(/var \$app_style\$\s*=[^;]*;\s*/g, '');
|
|
144
|
+
s = s.replace(/module\.exports[^;]*;\s*/g, '');
|
|
145
|
+
// Preserve $app_template$ for prerender (will be stripped after template.json is generated)
|
|
146
|
+
let templateCode = '';
|
|
147
|
+
const tplIdx = body.indexOf('var $app_template$');
|
|
148
|
+
if (tplIdx !== -1) {
|
|
149
|
+
const fnStart = body.indexOf('function', tplIdx);
|
|
150
|
+
if (fnStart !== -1) {
|
|
151
|
+
const braceStart = body.indexOf('{', fnStart);
|
|
152
|
+
if (braceStart !== -1) {
|
|
153
|
+
const braceEnd = this.findMatching(body, braceStart, '{', '}');
|
|
154
|
+
if (braceEnd !== -1) {
|
|
155
|
+
templateCode = body.slice(tplIdx, braceEnd + 1) + ';';
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
s = s.replace(/\$app_exports\$\[[^\]]*\][^;]*;\s*/g, '');
|
|
161
|
+
s = s.replace(/var \$app_exports\$[^;]*;\s*/g, '');
|
|
162
|
+
s = s.replace(/\$app_exports\$\.default[^;]*;\s*/g, '');
|
|
163
|
+
s = s.replace(/"use strict";\s*/g, '');
|
|
164
|
+
s = s.replace(/Object\.defineProperty\(exports,\s*"__esModule"[^;]*;\s*/g, '');
|
|
165
|
+
s = s.replace(/exports\["default"\]\s*=\s*void 0;\s*/g, '');
|
|
166
|
+
s = s.replace(/const moduleOwn[\s\S]*?}\s*}\s*}\s*/g, '');
|
|
167
|
+
s = s.replace(/var exports\s*=\s*module\.exports;\s*/g, '');
|
|
168
|
+
// Remove __webpack_require__ calls (including the var declaration if present)
|
|
169
|
+
s = s.replace(/(?:var|const|let)\s+\w+\s*=\s*__webpack_require__\([^)]*\);?\s*/g, '');
|
|
170
|
+
s = s.replace(/__webpack_require__\([^)]*\);?\s*/g, '');
|
|
171
|
+
// Extract component object
|
|
172
|
+
let obj = '{}';
|
|
173
|
+
const m = s.match(/(?:var _default\s*=\s*)?exports\["default"\]\s*=\s*(\{[\s\S]*\}|[\w.]+);?\s*$/);
|
|
174
|
+
if (m) {
|
|
175
|
+
obj = m[1];
|
|
176
|
+
s = s.slice(0, s.indexOf(m[0])).trim();
|
|
177
|
+
}
|
|
178
|
+
const lines = [`let $style$${styleId} = {"@info":{"styleObjectId":${styleId}}};`, `const $app_style$${styleId} = $style$${styleId};`, ...(s.trim() ? [s.trim()] : []), ...(templateCode ? [templateCode] : []), `const $app_script$${styleId} = ${obj};`, `$app_define$("${defineId}", [], function($app_require$, $app_exports$, $app_module$) {`, ` $app_module$.exports = $app_script$${styleId}.default || $app_script$${styleId};`, ` $app_module$.exports.style = $app_style$${styleId};`, ...(templateCode ? [` $app_module$.exports.template = $app_template$;`] : []), `});`];
|
|
179
|
+
return lines.join('\n');
|
|
180
|
+
}
|
|
24
181
|
wrap(compilation) {
|
|
25
|
-
const {
|
|
26
|
-
enableE2e
|
|
27
|
-
} = this.compilerOption;
|
|
28
|
-
// 获取入口文件
|
|
29
182
|
const entrys = Object.keys(compilation.options.entry).map(item => `${item}.js`);
|
|
30
|
-
// 从chunk找到所有入口文件,添加包裹函数
|
|
31
183
|
entrys.forEach(entry => {
|
|
32
|
-
if (compilation.assets[entry])
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
184
|
+
if (!compilation.assets[entry]) return;
|
|
185
|
+
const sourceCode = compilation.assets[entry].source().toString();
|
|
186
|
+
const isApp = entry === 'app.js';
|
|
187
|
+
const componentName = this.getComponentName(entry);
|
|
188
|
+
const bootstrapId = isApp ? '@app-application/app' : `@app-component/${componentName}`;
|
|
189
|
+
const modules = this.extractModules(sourceCode);
|
|
190
|
+
// Generate css.json from style arrays before buildBlock replaces them
|
|
191
|
+
const cssJsonData = {};
|
|
192
|
+
for (const mod of modules) {
|
|
193
|
+
const si = mod.body.indexOf('var $app_style$');
|
|
194
|
+
if (si === -1) continue;
|
|
195
|
+
const bi = mod.body.indexOf('[', si);
|
|
196
|
+
if (bi === -1) continue;
|
|
197
|
+
const be = this.findMatching(mod.body, bi, '[', ']');
|
|
198
|
+
if (be === -1) continue;
|
|
199
|
+
try {
|
|
200
|
+
const styleStr = mod.body.slice(bi, be + 1);
|
|
201
|
+
const sid = (0, _TemplateCompiler.getStyleObjectId)(mod.key || entry);
|
|
202
|
+
const cssObj = (0, _TemplateCompiler.parseStyleArray)(styleStr);
|
|
203
|
+
if (Object.keys(cssObj).length > 0) cssJsonData[String(sid)] = cssObj;
|
|
204
|
+
} catch {}
|
|
205
|
+
}
|
|
206
|
+
const cssJsonPath = entry.replace(/\.js$/, '.css.json');
|
|
207
|
+
compilation.assets[cssJsonPath] = new _webpackSources.RawSource(JSON.stringify(cssJsonData, null, 2));
|
|
208
|
+
// Emit component import map for template.json generation
|
|
209
|
+
const importMap = {};
|
|
210
|
+
for (const mod of modules) {
|
|
211
|
+
if (!mod.key.includes('?uxType=') && mod.key !== '' && mod.key.endsWith('.ux')) {
|
|
212
|
+
const entryM = modules.find(m => m.key.includes('?uxType=') || m.key === '');
|
|
213
|
+
const escaped = mod.key.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
214
|
+
const nm = entryM?.body.match(new RegExp(`\\$app_exports\\$\\['([^']+)'\\]\\s*=\\s*__webpack_require__\\([^)]*"${escaped}"\\)`));
|
|
215
|
+
const name = nm ? nm[1] : _path.default.parse(mod.key.replace(/\.ux$/, '')).name.toLowerCase();
|
|
216
|
+
// Convert "./src/components/Card.ux" to "components/Card"
|
|
217
|
+
const importPath = mod.key.replace(/^\.\/src\//, '').replace(/\.ux$/, '');
|
|
218
|
+
importMap[name] = importPath;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
if (Object.keys(importMap).length > 0) {
|
|
222
|
+
const mapPath = entry.replace(/\.js$/, '.imports.json');
|
|
223
|
+
compilation.assets[mapPath] = new _webpackSources.RawSource(JSON.stringify(importMap));
|
|
224
|
+
}
|
|
225
|
+
const blocks = [];
|
|
226
|
+
// Find entry module to extract component name mappings
|
|
227
|
+
const entryMod = modules.find(m => m.key.includes('?uxType=') || m.key === '');
|
|
228
|
+
for (const mod of modules) {
|
|
229
|
+
// Check if this entry has non-.ux JS dependencies
|
|
230
|
+
const hasJsDeps = modules.some(m => m.key && !m.key.endsWith('.ux') && !m.key.includes('?uxType=') && m.key !== '' && !m.key.endsWith('.json'));
|
|
45
231
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
232
|
+
// If entry has JS dependencies, keep the full rspack output (don't decompose)
|
|
233
|
+
if (hasJsDeps && modules.length > 1) {
|
|
234
|
+
// Just wrap the entire rspack output with $app_define$/$app_bootstrap$
|
|
235
|
+
const styleId = (0, _TemplateCompiler.getStyleObjectId)(entry);
|
|
236
|
+
const defineId = isApp ? '@app-component/app' : `@app-component/${componentName}`;
|
|
237
|
+
blocks.push(`let $style$${styleId} = {"@info":{"styleObjectId":${styleId}}};`);
|
|
238
|
+
blocks.push(`const $app_style$${styleId} = $style$${styleId};`);
|
|
239
|
+
blocks.push(`$app_define$("${defineId}", [], function($app_require$, $app_exports$, $app_module$) {`);
|
|
240
|
+
blocks.push(`var exports = $app_module$.exports;`);
|
|
241
|
+
blocks.push(`var module = $app_module$;`);
|
|
242
|
+
blocks.push(sourceCode);
|
|
243
|
+
blocks.push(`$app_module$.exports.style = $app_style$${styleId};`);
|
|
244
|
+
blocks.push(`});`);
|
|
245
|
+
break;
|
|
246
|
+
}
|
|
247
|
+
// Non-.ux modules (utility JS files) are handled by webpack runtime above
|
|
248
|
+
if (mod.key && !mod.key.endsWith('.ux') && !mod.key.includes('?uxType=') && mod.key !== '') {
|
|
249
|
+
continue;
|
|
250
|
+
}
|
|
251
|
+
let compName;
|
|
252
|
+
if (mod.key.includes('?uxType=') || mod.key === '') {
|
|
253
|
+
compName = componentName;
|
|
254
|
+
} else {
|
|
255
|
+
// Find component name from: $app_exports$['name'] = __webpack_require__(/*...*/ "key")
|
|
256
|
+
const escaped = mod.key.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
257
|
+
const nm = entryMod?.body.match(new RegExp(`\\$app_exports\\$\\['([^']+)'\\]\\s*=\\s*__webpack_require__\\([^)]*"${escaped}"\\)`));
|
|
258
|
+
compName = nm ? nm[1] : _path.default.parse(mod.key.replace(/\.ux$/, '')).name.toLowerCase();
|
|
259
|
+
}
|
|
260
|
+
const defineId = isApp && mod === entryMod ? '@app-component/app' : `@app-component/${compName}`;
|
|
261
|
+
const styleId = (0, _TemplateCompiler.getStyleObjectId)(mod.key || entry);
|
|
262
|
+
blocks.push(this.buildBlock(mod.body, defineId, styleId));
|
|
54
263
|
}
|
|
264
|
+
blocks.push(`$app_bootstrap$("${bootstrapId}");`);
|
|
265
|
+
compilation.assets[entry] = new _webpackSources.RawSource(blocks.join('\n') + '\n');
|
|
55
266
|
});
|
|
56
267
|
}
|
|
57
|
-
translateStyleFunc() {
|
|
58
|
-
return `
|
|
59
|
-
var $translateStyle$ = function (value) {
|
|
60
|
-
if (typeof value === 'string') {
|
|
61
|
-
return Object.fromEntries(
|
|
62
|
-
value
|
|
63
|
-
.split(';')
|
|
64
|
-
.filter((item) => Boolean(item && item.trim()))
|
|
65
|
-
.map((item) => {
|
|
66
|
-
const matchs = item.match(/([^:]+):(.*)/);
|
|
67
|
-
if (matchs && matchs.length > 2) {
|
|
68
|
-
return [
|
|
69
|
-
matchs[1]
|
|
70
|
-
.trim()
|
|
71
|
-
.replace(/-([a-z])/g, (_, match) => match.toUpperCase()),
|
|
72
|
-
matchs[2].trim(),
|
|
73
|
-
];
|
|
74
|
-
}
|
|
75
|
-
return [];
|
|
76
|
-
})
|
|
77
|
-
);
|
|
78
|
-
}
|
|
79
|
-
return value;
|
|
80
|
-
};
|
|
81
|
-
global.$translateStyle$ = $translateStyle$
|
|
82
|
-
`;
|
|
83
|
-
}
|
|
84
268
|
}
|
|
85
269
|
var _default = exports.default = WrapPlugin;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Dictionary } from '@aiot-toolkit/shared-utils';
|
|
2
|
+
import IManifest from '../interface/IManifest';
|
|
2
3
|
declare class UxCompileUtil {
|
|
3
4
|
static readonly DIGEST_ZIP_DIR = "META-INF";
|
|
4
5
|
static clean(dirList: string[]): void;
|
|
@@ -7,9 +8,9 @@ declare class UxCompileUtil {
|
|
|
7
8
|
* @param config 项目配置文件的内容,应为json对象
|
|
8
9
|
* @param codeDir 源码目录
|
|
9
10
|
* @param projectPath 项目目录
|
|
10
|
-
* @returns {[
|
|
11
|
+
* @returns `{[entryName]:entryPath}`
|
|
11
12
|
*/
|
|
12
|
-
static resolveEntries(config:
|
|
13
|
+
static resolveEntries(config: IManifest, codeDir: string, projectPath: string): Dictionary<string>;
|
|
13
14
|
/**
|
|
14
15
|
* 通过无后缀的文件名路径获取存在的文件路径
|
|
15
16
|
*
|
|
@@ -36,7 +36,7 @@ class UxCompileUtil {
|
|
|
36
36
|
* @param config 项目配置文件的内容,应为json对象
|
|
37
37
|
* @param codeDir 源码目录
|
|
38
38
|
* @param projectPath 项目目录
|
|
39
|
-
* @returns {[
|
|
39
|
+
* @returns `{[entryName]:entryPath}`
|
|
40
40
|
*/
|
|
41
41
|
static resolveEntries(config, codeDir, projectPath) {
|
|
42
42
|
const {
|
|
@@ -114,11 +114,10 @@ class UxCompileUtil {
|
|
|
114
114
|
if (Array.isArray(services)) {
|
|
115
115
|
services.forEach(item => {
|
|
116
116
|
const {
|
|
117
|
-
name,
|
|
118
117
|
path
|
|
119
118
|
} = item;
|
|
120
|
-
if (
|
|
121
|
-
result[
|
|
119
|
+
if (path) {
|
|
120
|
+
result[path] = './src/' + path + `?uxType=${_EntryType.default.APP}`;
|
|
122
121
|
}
|
|
123
122
|
});
|
|
124
123
|
}
|
|
@@ -130,6 +129,15 @@ class UxCompileUtil {
|
|
|
130
129
|
}
|
|
131
130
|
}
|
|
132
131
|
}
|
|
132
|
+
// 5. 添加 widget_provider
|
|
133
|
+
const {
|
|
134
|
+
widgetProvider
|
|
135
|
+
} = config;
|
|
136
|
+
if (widgetProvider?.length) {
|
|
137
|
+
for (const widgetItem of widgetProvider) {
|
|
138
|
+
result[widgetItem.path] = './src/' + widgetItem.path;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
133
141
|
return result;
|
|
134
142
|
}
|
|
135
143
|
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VRU (Vela Union) file format utility.
|
|
3
|
+
*
|
|
4
|
+
* Pack/unpack a multi-file binary container used to bundle app resources
|
|
5
|
+
* inside a release RPK. Format is byte-compatible with vivo's VRU (only
|
|
6
|
+
* the magic differs: we use 'vela' instead of 'vivo').
|
|
7
|
+
* Layout:
|
|
8
|
+
* 0x00-0x0F: 'vela union file\0' (16 bytes magic)
|
|
9
|
+
* 0x10-0x3F: 48 bytes zero padding
|
|
10
|
+
* 0x40-0x43: entries-table size (uint32 LE) = header_end - 0xB0
|
|
11
|
+
* 0x44-0x47: total VRU file size (uint32 LE)
|
|
12
|
+
* 0x48-0xA7: package name (96 bytes, null-padded UTF-8)
|
|
13
|
+
* 0xA8-0xAB: 4 bytes zero padding
|
|
14
|
+
* 0xAC-0xAF: entry count (uint32 LE)
|
|
15
|
+
* 0xB0-...: entries table, for each entry:
|
|
16
|
+
* 4 bytes: filename length (uint32 LE)
|
|
17
|
+
* N bytes: filename (UTF-8)
|
|
18
|
+
* 4 bytes: data offset from start of file (uint32 LE)
|
|
19
|
+
* 4 bytes: data size (uint32 LE)
|
|
20
|
+
* after entries: file data (concatenated in entry order)
|
|
21
|
+
*/
|
|
22
|
+
export interface VruEntry {
|
|
23
|
+
name: string;
|
|
24
|
+
data: Buffer;
|
|
25
|
+
}
|
|
26
|
+
export declare class VruUtil {
|
|
27
|
+
static readonly MAGIC = "vela union file";
|
|
28
|
+
static readonly PACKAGE_NAME_OFFSET = 72;
|
|
29
|
+
static readonly PACKAGE_NAME_SIZE = 96;
|
|
30
|
+
static readonly ENTRY_COUNT_OFFSET = 172;
|
|
31
|
+
static readonly ENTRIES_TABLE_OFFSET = 176;
|
|
32
|
+
/**
|
|
33
|
+
* Pack multiple files into a VRU buffer.
|
|
34
|
+
* @param entries Array of {name, data} pairs
|
|
35
|
+
* @param packageName Application package name (max 95 chars)
|
|
36
|
+
*/
|
|
37
|
+
static pack(entries: VruEntry[], packageName: string): Buffer;
|
|
38
|
+
/**
|
|
39
|
+
* Get the VRU filename from a manifest package name.
|
|
40
|
+
*/
|
|
41
|
+
static getVruName(packageName: string): string;
|
|
42
|
+
/**
|
|
43
|
+
* Parse a VRU buffer back into entries + package name.
|
|
44
|
+
* Useful for round-trip verification and reading existing VRU files.
|
|
45
|
+
*/
|
|
46
|
+
static unpack(buf: Buffer): {
|
|
47
|
+
entries: VruEntry[];
|
|
48
|
+
packageName: string;
|
|
49
|
+
};
|
|
50
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.VruUtil = void 0;
|
|
7
|
+
/**
|
|
8
|
+
* VRU (Vela Union) file format utility.
|
|
9
|
+
*
|
|
10
|
+
* Pack/unpack a multi-file binary container used to bundle app resources
|
|
11
|
+
* inside a release RPK. Format is byte-compatible with vivo's VRU (only
|
|
12
|
+
* the magic differs: we use 'vela' instead of 'vivo').
|
|
13
|
+
* Layout:
|
|
14
|
+
* 0x00-0x0F: 'vela union file\0' (16 bytes magic)
|
|
15
|
+
* 0x10-0x3F: 48 bytes zero padding
|
|
16
|
+
* 0x40-0x43: entries-table size (uint32 LE) = header_end - 0xB0
|
|
17
|
+
* 0x44-0x47: total VRU file size (uint32 LE)
|
|
18
|
+
* 0x48-0xA7: package name (96 bytes, null-padded UTF-8)
|
|
19
|
+
* 0xA8-0xAB: 4 bytes zero padding
|
|
20
|
+
* 0xAC-0xAF: entry count (uint32 LE)
|
|
21
|
+
* 0xB0-...: entries table, for each entry:
|
|
22
|
+
* 4 bytes: filename length (uint32 LE)
|
|
23
|
+
* N bytes: filename (UTF-8)
|
|
24
|
+
* 4 bytes: data offset from start of file (uint32 LE)
|
|
25
|
+
* 4 bytes: data size (uint32 LE)
|
|
26
|
+
* after entries: file data (concatenated in entry order)
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
class VruUtil {
|
|
30
|
+
static MAGIC = 'vela union file';
|
|
31
|
+
static PACKAGE_NAME_OFFSET = 0x48;
|
|
32
|
+
static PACKAGE_NAME_SIZE = 96;
|
|
33
|
+
static ENTRY_COUNT_OFFSET = 0xAC;
|
|
34
|
+
static ENTRIES_TABLE_OFFSET = 0xB0;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Pack multiple files into a VRU buffer.
|
|
38
|
+
* @param entries Array of {name, data} pairs
|
|
39
|
+
* @param packageName Application package name (max 95 chars)
|
|
40
|
+
*/
|
|
41
|
+
static pack(entries, packageName) {
|
|
42
|
+
if (Buffer.byteLength(packageName, 'utf-8') >= VruUtil.PACKAGE_NAME_SIZE) {
|
|
43
|
+
throw new Error(`Package name too long: ${packageName}`);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Compute table size
|
|
47
|
+
let tableSize = 0;
|
|
48
|
+
for (const e of entries) {
|
|
49
|
+
tableSize += 4 + Buffer.byteLength(e.name, 'utf-8') + 8;
|
|
50
|
+
}
|
|
51
|
+
const headerEnd = VruUtil.ENTRIES_TABLE_OFFSET + tableSize;
|
|
52
|
+
|
|
53
|
+
// Compute total size
|
|
54
|
+
let totalSize = headerEnd;
|
|
55
|
+
for (const e of entries) totalSize += e.data.length;
|
|
56
|
+
const buf = Buffer.alloc(totalSize);
|
|
57
|
+
// Magic
|
|
58
|
+
buf.write(VruUtil.MAGIC, 0, 'utf-8');
|
|
59
|
+
// 0x40: entries-table size (header_end - 0xB0)
|
|
60
|
+
buf.writeUInt32LE(tableSize, 0x40);
|
|
61
|
+
// 0x44: total file size
|
|
62
|
+
buf.writeUInt32LE(totalSize, 0x44);
|
|
63
|
+
// 0x48: package name (null-padded)
|
|
64
|
+
buf.write(packageName, VruUtil.PACKAGE_NAME_OFFSET, 'utf-8');
|
|
65
|
+
// 0xAC: entry count
|
|
66
|
+
buf.writeUInt32LE(entries.length, VruUtil.ENTRY_COUNT_OFFSET);
|
|
67
|
+
|
|
68
|
+
// Write entries table and accumulate data offsets
|
|
69
|
+
let entryOffset = VruUtil.ENTRIES_TABLE_OFFSET;
|
|
70
|
+
let dataOffset = headerEnd;
|
|
71
|
+
for (const e of entries) {
|
|
72
|
+
const nameBuf = Buffer.from(e.name, 'utf-8');
|
|
73
|
+
buf.writeUInt32LE(nameBuf.length, entryOffset);
|
|
74
|
+
entryOffset += 4;
|
|
75
|
+
nameBuf.copy(buf, entryOffset);
|
|
76
|
+
entryOffset += nameBuf.length;
|
|
77
|
+
buf.writeUInt32LE(dataOffset, entryOffset);
|
|
78
|
+
entryOffset += 4;
|
|
79
|
+
buf.writeUInt32LE(e.data.length, entryOffset);
|
|
80
|
+
entryOffset += 4;
|
|
81
|
+
e.data.copy(buf, dataOffset);
|
|
82
|
+
dataOffset += e.data.length;
|
|
83
|
+
}
|
|
84
|
+
return buf;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Get the VRU filename from a manifest package name.
|
|
89
|
+
*/
|
|
90
|
+
static getVruName(packageName) {
|
|
91
|
+
return `${packageName}.vru`;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Parse a VRU buffer back into entries + package name.
|
|
96
|
+
* Useful for round-trip verification and reading existing VRU files.
|
|
97
|
+
*/
|
|
98
|
+
static unpack(buf) {
|
|
99
|
+
const magic = buf.slice(0, VruUtil.MAGIC.length).toString('utf-8');
|
|
100
|
+
if (magic !== VruUtil.MAGIC) {
|
|
101
|
+
throw new Error(`Invalid VRU magic: expected "${VruUtil.MAGIC}", got "${magic}"`);
|
|
102
|
+
}
|
|
103
|
+
const pkgEnd = buf.indexOf(0, VruUtil.PACKAGE_NAME_OFFSET);
|
|
104
|
+
const packageName = buf.slice(VruUtil.PACKAGE_NAME_OFFSET, pkgEnd >= 0 ? pkgEnd : VruUtil.PACKAGE_NAME_OFFSET + VruUtil.PACKAGE_NAME_SIZE).toString('utf-8');
|
|
105
|
+
const count = buf.readUInt32LE(VruUtil.ENTRY_COUNT_OFFSET);
|
|
106
|
+
const entries = [];
|
|
107
|
+
let offset = VruUtil.ENTRIES_TABLE_OFFSET;
|
|
108
|
+
for (let i = 0; i < count; i++) {
|
|
109
|
+
const nameLen = buf.readUInt32LE(offset);
|
|
110
|
+
offset += 4;
|
|
111
|
+
const name = buf.slice(offset, offset + nameLen).toString('utf-8');
|
|
112
|
+
offset += nameLen;
|
|
113
|
+
const dataOffset = buf.readUInt32LE(offset);
|
|
114
|
+
offset += 4;
|
|
115
|
+
const dataSize = buf.readUInt32LE(offset);
|
|
116
|
+
offset += 4;
|
|
117
|
+
entries.push({
|
|
118
|
+
name,
|
|
119
|
+
data: Buffer.from(buf.slice(dataOffset, dataOffset + dataSize))
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
return {
|
|
123
|
+
entries,
|
|
124
|
+
packageName
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
exports.VruUtil = VruUtil;
|
|
@@ -32,6 +32,15 @@ declare class ZipUtil {
|
|
|
32
32
|
* @returns 生成的 rpk 文件名
|
|
33
33
|
*/
|
|
34
34
|
static createRpk(dist: string, param: IJavascriptCompileOption): Promise<string | undefined>;
|
|
35
|
+
/**
|
|
36
|
+
* Build the blueos-pack compatible "wrapped release" RPK.
|
|
37
|
+
* Outer RPK (zip) contains:
|
|
38
|
+
* - manifest.json (top-level metadata)
|
|
39
|
+
* - logo.<ext> (icon - kept as png since VUG conversion is out of scope)
|
|
40
|
+
* - META-INF/CERT (signature)
|
|
41
|
+
* - <package>.vru (multi-file VRU containing all build artifacts)
|
|
42
|
+
*/
|
|
43
|
+
private static createWrappedReleaseRpk;
|
|
35
44
|
private static getFileName;
|
|
36
45
|
private static packageToZipBuffer;
|
|
37
46
|
/**
|