@aiot-toolkit/aiotpack 2.1.0-prender.6 → 2.1.0-prender.8
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.
|
@@ -281,6 +281,50 @@ function addThisPrefix(expr, extraReserved) {
|
|
|
281
281
|
}).join('');
|
|
282
282
|
}
|
|
283
283
|
}
|
|
284
|
+
function emitTextValueAttr(rawText) {
|
|
285
|
+
const text = rawText.trim();
|
|
286
|
+
if (!/\{\{[\s\S]*?\}\}/.test(text)) {
|
|
287
|
+
return {
|
|
288
|
+
attr: {
|
|
289
|
+
value: text.replace(/\s*\n\s*/g, ' ')
|
|
290
|
+
},
|
|
291
|
+
needsBind: false
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
const parts = text.split(/(\{\{[\s\S]*?\}\})/);
|
|
295
|
+
const exprs = parts.filter(Boolean).map(p => {
|
|
296
|
+
const m = p.match(/^\{\{([\s\S]*?)\}\}$/);
|
|
297
|
+
if (m) return addThisPrefix(m[1].trim());
|
|
298
|
+
return `'${p.replace(/'/g, "\\'")}'`;
|
|
299
|
+
});
|
|
300
|
+
if (exprs.length === 1 && pathTestRE.test(exprs[0].replace(/^this\./, ''))) {
|
|
301
|
+
return {
|
|
302
|
+
attr: {
|
|
303
|
+
$value: exprs[0].replace(/^this\./, '')
|
|
304
|
+
},
|
|
305
|
+
needsBind: true
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
if (exprs.length === 1) {
|
|
309
|
+
return {
|
|
310
|
+
attr: {
|
|
311
|
+
$value: `function () { return ${exprs[0]}; }`
|
|
312
|
+
},
|
|
313
|
+
needsBind: true
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
const wrapped = exprs.map(e => {
|
|
317
|
+
if (e.startsWith("'") || e.startsWith('"')) return e;
|
|
318
|
+
if (/(\|\||&&|\?\s|\+)/.test(e) && !e.startsWith('(')) return `(${e})`;
|
|
319
|
+
return e;
|
|
320
|
+
});
|
|
321
|
+
return {
|
|
322
|
+
attr: {
|
|
323
|
+
$value: `function () { return '' + ${wrapped.join(' + ')}; }`
|
|
324
|
+
},
|
|
325
|
+
needsBind: true
|
|
326
|
+
};
|
|
327
|
+
}
|
|
284
328
|
function elementToJson(el, styleSheet, importMap, scopeVars, pageDir) {
|
|
285
329
|
const tagName = el.tagName === 'img' ? 'image' : el.tagName;
|
|
286
330
|
const node = {
|
|
@@ -491,8 +535,11 @@ function elementToJson(el, styleSheet, importMap, scopeVars, pageDir) {
|
|
|
491
535
|
hasBind = true;
|
|
492
536
|
} else {
|
|
493
537
|
let staticVal = value ? value.replace(/ {2,}/g, ' ') : '';
|
|
494
|
-
// Normalize relative path attrs (src, href) to absolute paths from src root
|
|
495
|
-
|
|
538
|
+
// Normalize relative path attrs (src, href, alt) to absolute paths from src root.
|
|
539
|
+
// alt can also carry prose (e.g. "blank") — only rewrite when the value starts with
|
|
540
|
+
// ./ or ../ so image alt-text prose passes through untouched.
|
|
541
|
+
const isRelPath = staticVal.startsWith('./') || staticVal.startsWith('../');
|
|
542
|
+
if (staticVal && isRelPath && (name === 'src' || name === 'href' || name === 'alt') && pageDir) {
|
|
496
543
|
// Resolve relative to pageDir, then make absolute from src root
|
|
497
544
|
const segments = pageDir.split('/').filter(Boolean).concat(staticVal.split('/'));
|
|
498
545
|
const stack = [];
|
|
@@ -509,34 +556,9 @@ function elementToJson(el, styleSheet, importMap, scopeVars, pageDir) {
|
|
|
509
556
|
for (const child of el.childNodes || []) {
|
|
510
557
|
const textElements = new Set(['text', 'span', 'a', 'input', 'qrcode', 'barcode', 'marquee', 'arc-text', 'option', 'button', 'label', 'textarea', 'richtext']);
|
|
511
558
|
if (child.value?.trim() && !child.tagName && !(el.childNodes || []).some(c => c.tagName) && textElements.has(tagName)) {
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
if (
|
|
515
|
-
// Build function expression from template literal
|
|
516
|
-
// Trim surrounding whitespace before splitting (vivo ignores indentation whitespace)
|
|
517
|
-
const trimmedText = text.trim();
|
|
518
|
-
const parts = trimmedText.split(/(\{\{[\s\S]*?\}\})/);
|
|
519
|
-
const exprs = parts.filter(Boolean).map(p => {
|
|
520
|
-
const m = p.match(/^\{\{([\s\S]*?)\}\}$/);
|
|
521
|
-
if (m) return addThisPrefix(m[1].trim());
|
|
522
|
-
return `'${p.replace(/'/g, "\\'")}'`;
|
|
523
|
-
});
|
|
524
|
-
if (exprs.length === 1 && pathTestRE.test(exprs[0].replace(/^this\./, ''))) {
|
|
525
|
-
attrObj['$value'] = exprs[0].replace(/^this\./, '');
|
|
526
|
-
} else if (exprs.length === 1) {
|
|
527
|
-
attrObj['$value'] = `function () { return ${exprs[0]}; }`;
|
|
528
|
-
} else {
|
|
529
|
-
const wrappedExprs = exprs.map(e => {
|
|
530
|
-
if (e.startsWith("'") || e.startsWith('"')) return e;
|
|
531
|
-
if (/(\|\||&&|\?\s|\+)/.test(e) && !e.startsWith('(')) return `(${e})`;
|
|
532
|
-
return e;
|
|
533
|
-
});
|
|
534
|
-
attrObj['$value'] = `function () { return '' + ${wrappedExprs.join(' + ')}; }`;
|
|
535
|
-
}
|
|
536
|
-
hasBind = true;
|
|
537
|
-
} else {
|
|
538
|
-
attrObj['value'] = text.replace(/\s*\n\s*/g, ' ');
|
|
539
|
-
}
|
|
559
|
+
const emitted = emitTextValueAttr(child.value);
|
|
560
|
+
Object.assign(attrObj, emitted.attr);
|
|
561
|
+
if (emitted.needsBind) hasBind = true;
|
|
540
562
|
}
|
|
541
563
|
}
|
|
542
564
|
// Output in vivo order: attr → bind → class → events → import → style → children
|
|
@@ -572,13 +594,19 @@ function elementToJson(el, styleSheet, importMap, scopeVars, pageDir) {
|
|
|
572
594
|
}
|
|
573
595
|
if (Object.keys(events).length) node.events = events;
|
|
574
596
|
// Inline style from styleSheet (class selector + tag selector) + static portion of style="..."
|
|
597
|
+
// Inline style from styleSheet (class selector + tag selector) + static portion of style="...".
|
|
575
598
|
// Only base (non-@media) selectors are inlined; @media rules are applied at runtime by SDK.
|
|
599
|
+
// Class rules apply in stylesheet declaration order (later declarations override earlier),
|
|
600
|
+
// NOT in class-attribute order.
|
|
576
601
|
if (styleSheet) {
|
|
577
602
|
const merged = {};
|
|
578
603
|
if (styleSheet[el.tagName]) Object.assign(merged, styleSheet[el.tagName]);
|
|
579
604
|
if (className && !hasDynClass) {
|
|
580
|
-
|
|
581
|
-
|
|
605
|
+
const classSet = new Set(className.split(/\s+/).filter(Boolean));
|
|
606
|
+
for (const key of Object.keys(styleSheet)) {
|
|
607
|
+
if (key.length > 1 && key.startsWith('.') && classSet.has(key.slice(1))) {
|
|
608
|
+
Object.assign(merged, styleSheet[key]);
|
|
609
|
+
}
|
|
582
610
|
}
|
|
583
611
|
}
|
|
584
612
|
Object.assign(merged, staticInlineStyle);
|
|
@@ -597,14 +625,12 @@ function elementToJson(el, styleSheet, importMap, scopeVars, pageDir) {
|
|
|
597
625
|
if (child.tagName) {
|
|
598
626
|
childNodes.push(elementToJson(child, styleSheet, importMap, scopeVars, pageDir));
|
|
599
627
|
} else if (isMixedContent && child.value?.trim()) {
|
|
600
|
-
|
|
601
|
-
const text = child.value.replace(/[ \t]*\n[ \t]*/g, ' ').replace(/ {2,}/g, ' ');
|
|
628
|
+
const emitted = emitTextValueAttr(child.value);
|
|
602
629
|
const spanNode = {
|
|
603
630
|
type: 'span',
|
|
604
|
-
attr:
|
|
605
|
-
value: text
|
|
606
|
-
}
|
|
631
|
+
attr: emitted.attr
|
|
607
632
|
};
|
|
633
|
+
if (emitted.needsBind) spanNode.bind = 1;
|
|
608
634
|
childNodes.push(spanNode);
|
|
609
635
|
}
|
|
610
636
|
}
|
|
@@ -10,4 +10,8 @@ declare class ViteCompiler implements ICompiler {
|
|
|
10
10
|
compile(param: IJavascriptCompileOption): Promise<void>;
|
|
11
11
|
clean(param: ICompileParam & IJavascriptCompileOption): Promise<void>;
|
|
12
12
|
}
|
|
13
|
+
declare function stripDeadDefProp(code: string): string;
|
|
14
|
+
export declare const __test: {
|
|
15
|
+
stripDeadDefProp: typeof stripDeadDefProp;
|
|
16
|
+
};
|
|
13
17
|
export default ViteCompiler;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.default = void 0;
|
|
6
|
+
exports.default = exports.__test = void 0;
|
|
7
7
|
var _TemplateCompiler = require("./TemplateCompiler");
|
|
8
8
|
var _path = _interopRequireDefault(require("path"));
|
|
9
9
|
var _fsExtra = _interopRequireDefault(require("fs-extra"));
|
|
@@ -208,6 +208,16 @@ class ViteCompiler {
|
|
|
208
208
|
external: id => id.startsWith('@app-module/') || /^@(system|service|android|hap)\./.test(id),
|
|
209
209
|
output: {
|
|
210
210
|
globals: id => `$app_require$("@app-module/${id.replace(/^@(system|service|android|hap|app-module)\./, '')}")`
|
|
211
|
+
},
|
|
212
|
+
onwarn(warning, defaultHandler) {
|
|
213
|
+
// Rolldown silently emits `(void 0)()` for namespace-member accesses whose
|
|
214
|
+
// name is not exported by the target module — leaves runtime with an opaque
|
|
215
|
+
// TypeError instead of the source identifier. Escalate to a build error so
|
|
216
|
+
// the source location surfaces before ship.
|
|
217
|
+
if (warning.code === 'IMPORT_IS_UNDEFINED') {
|
|
218
|
+
throw new Error(`[toolkit] ${warning.message ?? 'IMPORT_IS_UNDEFINED'} — this would silently emit (void 0)() at the call site.`);
|
|
219
|
+
}
|
|
220
|
+
defaultHandler(warning);
|
|
211
221
|
}
|
|
212
222
|
},
|
|
213
223
|
commonjsOptions: {
|
|
@@ -228,6 +238,30 @@ class ViteCompiler {
|
|
|
228
238
|
}
|
|
229
239
|
},
|
|
230
240
|
plugins: [{
|
|
241
|
+
name: 'image-asset-string',
|
|
242
|
+
enforce: 'pre',
|
|
243
|
+
load(id) {
|
|
244
|
+
// require("./x.png") in .ux <script> must resolve to a path string,
|
|
245
|
+
// matching webpack file-loader / vivo blueos-pack semantics. Without
|
|
246
|
+
// this hook rolldown treats each image as an ES module and emits
|
|
247
|
+
// `(init_x(), __toCommonJS(x_exports))` — the site assigns
|
|
248
|
+
// `{ default: fn }` to src and runtime cannot render.
|
|
249
|
+
const match = id.match(/\.(png|jpe?g|gif|svg|webp|bmp|ico)(\?.*)?$/i);
|
|
250
|
+
if (!match) return null;
|
|
251
|
+
const filePath = id.replace(/\?.*$/, '');
|
|
252
|
+
if (!_fsExtra.default.existsSync(filePath)) return null;
|
|
253
|
+
const relFromSrc = _path.default.relative(srcPath, filePath).split(_path.default.sep).join('/');
|
|
254
|
+
// Assets outside src/ (typically node_modules) fall through to the
|
|
255
|
+
// default asset handler — the caller is responsible for their path
|
|
256
|
+
// resolution. Vivo blueos-pack + webpack file-loader use rpk-root
|
|
257
|
+
// absolute paths (`/common/...`, `/dynamicAssets/name-hash.png`);
|
|
258
|
+
// runtime <image src> resolves against the rpk root, so relative
|
|
259
|
+
// `./common/...` from a nested page directory would misdirect.
|
|
260
|
+
if (relFromSrc.startsWith('..')) return null;
|
|
261
|
+
const runtimePath = '/' + relFromSrc;
|
|
262
|
+
return `module.exports = ${JSON.stringify(runtimePath)};`;
|
|
263
|
+
}
|
|
264
|
+
}, {
|
|
231
265
|
name: "cjs-shim",
|
|
232
266
|
enforce: "pre",
|
|
233
267
|
load(id) {
|
|
@@ -249,6 +283,26 @@ class ViteCompiler {
|
|
|
249
283
|
map: null
|
|
250
284
|
} : null;
|
|
251
285
|
}
|
|
286
|
+
}, {
|
|
287
|
+
name: 'namespace-preserve',
|
|
288
|
+
enforce: 'pre',
|
|
289
|
+
transform(code, id) {
|
|
290
|
+
if (!/import\s*\*\s*as\s+\w+\s+from/.test(code)) return null;
|
|
291
|
+
// Rolldown resolves `import * as L from './x'; L.foo()` at compile time —
|
|
292
|
+
// if `foo` isn't exported by `./x` the call collapses to `(void 0)()` and
|
|
293
|
+
// the source identifier is lost. Rewriting the alias to a runtime variable
|
|
294
|
+
// (with webpack-style default-interop) preserves the identifier so runtime
|
|
295
|
+
// errors point at the actual source name.
|
|
296
|
+
const out = code.replace(/import\s*\*\s*as\s+(\w+)\s+from\s+(['"][^'"]+['"])/g, (_m, local, src) => {
|
|
297
|
+
const ns = `__${local}_ns`,
|
|
298
|
+
key = `__${local}_key`;
|
|
299
|
+
return `import * as ${ns} from ${src}; const ${key} = 'default'; const ${local} = ${ns}[${key}] != null ? ${ns}[${key}] : ${ns};`;
|
|
300
|
+
});
|
|
301
|
+
return out !== code ? {
|
|
302
|
+
code: out,
|
|
303
|
+
map: null
|
|
304
|
+
} : null;
|
|
305
|
+
}
|
|
252
306
|
}, {
|
|
253
307
|
name: 'ux-loader',
|
|
254
308
|
resolveId(source, importer) {
|
|
@@ -432,10 +486,13 @@ class ViteCompiler {
|
|
|
432
486
|
});
|
|
433
487
|
}
|
|
434
488
|
}
|
|
435
|
-
if (
|
|
489
|
+
if (entryFailures.length > 0) {
|
|
490
|
+
// Any per-entry failure fails the whole build — silently shipping an rpk with
|
|
491
|
+
// one page missing is exactly the class of bug that lets `(void 0)()` /
|
|
492
|
+
// empty jsc / dropped app.js leak to users.
|
|
436
493
|
const sample = entryFailures.slice(0, 3).map(f => ` ${f.entry}: ${f.error}`).join('\n');
|
|
437
494
|
const more = entryFailures.length > 3 ? `\n ...and ${entryFailures.length - 3} more` : '';
|
|
438
|
-
throw new Error(`vite build failed for
|
|
495
|
+
throw new Error(`vite build failed for ${entryFailures.length}/${entryAttempted} entry page(s).\n` + `Failures:\n${sample}${more}`);
|
|
439
496
|
}
|
|
440
497
|
// Second pass: compile ALL .ux files that weren't entry pages
|
|
441
498
|
// Each .ux file gets its own template.json + css.json + js
|
|
@@ -531,6 +588,10 @@ class ViteCompiler {
|
|
|
531
588
|
_UxCompileUtil.default.clean([outputPath, releasePath].map(item => _path.default.resolve(projectPath, item)));
|
|
532
589
|
}
|
|
533
590
|
}
|
|
591
|
+
function stripDeadDefProp(code) {
|
|
592
|
+
const withoutDefine = code.replace(/var __defProp = Object\.defineProperty;\n?/g, '');
|
|
593
|
+
return /\b__defProp\s*\(/.test(withoutDefine) ? code : withoutDefine;
|
|
594
|
+
}
|
|
534
595
|
function wrapOutput(code, entryName, isApp) {
|
|
535
596
|
const componentName = _path.default.parse(entryName).name;
|
|
536
597
|
const defineId = isApp ? '@app-component/app' : `@app-component/${componentName}`;
|
|
@@ -561,8 +622,10 @@ function wrapOutput(code, entryName, isApp) {
|
|
|
561
622
|
// Remove rolldown region comments
|
|
562
623
|
code = code.replace(/\/\/#region[^\n]*\n/g, '');
|
|
563
624
|
code = code.replace(/\/\/#endregion[^\n]*/g, '');
|
|
564
|
-
// Remove rolldown runtime helpers
|
|
565
|
-
|
|
625
|
+
// Remove rolldown runtime helpers. __defProp is only dead when nothing else calls it;
|
|
626
|
+
// when the CJS→ESM interop chain (__toCommonJS / __copyProps / __publicField) survives
|
|
627
|
+
// tree-shaking, __defProp is referenced by those helpers and must stay.
|
|
628
|
+
code = stripDeadDefProp(code);
|
|
566
629
|
code = code.replace(/var __exportAll = [\s\S]*?return target;\s*\};\n?/g, '');
|
|
567
630
|
// Inline __exportAll calls: __exportAll({key: () => value, ...}) -> {key: value, ...}
|
|
568
631
|
// Match __exportAll(...) or /* @__PURE__ */ __exportAll(...)
|
|
@@ -603,4 +666,7 @@ $app_define$("${defineId}", [], function($app_require$, $app_exports$, $app_modu
|
|
|
603
666
|
$app_bootstrap$("${bootstrapId}");
|
|
604
667
|
`;
|
|
605
668
|
}
|
|
669
|
+
const __test = exports.__test = {
|
|
670
|
+
stripDeadDefProp
|
|
671
|
+
};
|
|
606
672
|
var _default = exports.default = ViteCompiler;
|
|
@@ -20,6 +20,7 @@ class Jsc {
|
|
|
20
20
|
projectPath,
|
|
21
21
|
buildPath
|
|
22
22
|
} = this;
|
|
23
|
+
const beforeJsCount = Jsc.listFiles(buildPath, '.js').length;
|
|
23
24
|
return _sharedUtils.CommonUtil.requireNodeModule(projectPath, `@aiot-toolkit/jsc`).then(async module => {
|
|
24
25
|
this.logBeforeInvoke();
|
|
25
26
|
const start = Date.now();
|
|
@@ -32,6 +33,15 @@ class Jsc {
|
|
|
32
33
|
}
|
|
33
34
|
this.logAfterInvoke(elapsed);
|
|
34
35
|
}).then(() => {
|
|
36
|
+
// aiotjsc silently exits 0 on Windows when the buildPath contains CJK chars
|
|
37
|
+
// (win32_aiotjsc.exe uses ANSI POSIX APIs) — leaves 0 .jsc while the delete step
|
|
38
|
+
// below removes all .js, shipping an empty VRU. Fail loud before the deletion
|
|
39
|
+
// runs so the source path issue surfaces at build time.
|
|
40
|
+
const afterJscCount = Jsc.listFiles(buildPath, '.jsc').length;
|
|
41
|
+
if (beforeJsCount > 0 && afterJscCount < beforeJsCount) {
|
|
42
|
+
_sharedUtils.ColorConsole.throw(`[jsc] silent failure: expected at least ${beforeJsCount} .jsc file(s) but got ${afterJscCount}. ` + `Most common cause on Windows: buildPath contains non-ASCII characters ` + `(rename the project directory to ASCII-only and rebuild).`);
|
|
43
|
+
return Promise.reject(new Error(`[jsc] produced ${afterJscCount} of ${beforeJsCount} expected .jsc files`));
|
|
44
|
+
}
|
|
35
45
|
if (deleteJs) {
|
|
36
46
|
return _sharedUtils.FileUtil.del(`${buildPath}/**/*.js`);
|
|
37
47
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aiot-toolkit/aiotpack",
|
|
3
|
-
"version": "2.1.0-prender.
|
|
3
|
+
"version": "2.1.0-prender.8",
|
|
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.
|
|
23
|
-
"@aiot-toolkit/parser": "2.1.0-prender.
|
|
24
|
-
"@aiot-toolkit/shared-utils": "2.1.0-prender.
|
|
22
|
+
"@aiot-toolkit/generator": "2.1.0-prender.8",
|
|
23
|
+
"@aiot-toolkit/parser": "2.1.0-prender.8",
|
|
24
|
+
"@aiot-toolkit/shared-utils": "2.1.0-prender.8",
|
|
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.
|
|
31
|
+
"file-lane": "2.1.0-prender.8",
|
|
32
32
|
"file-loader": "^6.2.0",
|
|
33
33
|
"fs-extra": "^11.2.0",
|
|
34
34
|
"jsrsasign": "^11.1.0",
|