@nativescript/angular 21.0.1-alpha.7 → 21.0.1-alpha.9
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.
|
@@ -22,6 +22,7 @@ class InvisibleNode extends View {
|
|
|
22
22
|
this.name = name;
|
|
23
23
|
this.nodeType = 1;
|
|
24
24
|
this.nodeName = getClassName(this);
|
|
25
|
+
this.tagName = this.nodeName;
|
|
25
26
|
}
|
|
26
27
|
toString() {
|
|
27
28
|
return `${this.nodeName}(${this.id})-${this.name}`;
|
|
@@ -2533,6 +2534,61 @@ function runNativeScriptAngularApp(options) {
|
|
|
2533
2534
|
disposeLastModules('hotreload');
|
|
2534
2535
|
disposePlatform('hotreload');
|
|
2535
2536
|
};
|
|
2537
|
+
// Pre-import hook for HMR runtimes. Must be called BEFORE the changed
|
|
2538
|
+
// component modules are re-imported, otherwise their ɵɵdefineComponent
|
|
2539
|
+
// calls fire against the OLD `GENERATED_COMP_IDS` map and Angular emits
|
|
2540
|
+
// a benign-but-noisy NG0912 "Component ID generation collision" warning
|
|
2541
|
+
// for every component the user has touched. Calling
|
|
2542
|
+
// `ɵresetCompiledComponents` here clears the map (and the related
|
|
2543
|
+
// ownerNgModule / verifiedNgModule WeakMaps) so the fresh defs register
|
|
2544
|
+
// into an empty table.
|
|
2545
|
+
//
|
|
2546
|
+
// The post-reboot call inside `bootstrapRoot('hotreload')` remains in
|
|
2547
|
+
// place as a safety net: a project that doesn't wire its HMR runtime to
|
|
2548
|
+
// this hook still gets the reset (just one cycle late, after the warning
|
|
2549
|
+
// has already surfaced).
|
|
2550
|
+
global['__reset_ng_compiled_components__'] = () => {
|
|
2551
|
+
resetAngularHmrCompiledComponents(getAngularCoreForHmrReset(i0, globalThis));
|
|
2552
|
+
};
|
|
2553
|
+
// Suppress benign HMR-induced NG0912 ("Component ID generation collision")
|
|
2554
|
+
// warnings. On a `.ts` edit Angular Live Reload's
|
|
2555
|
+
// `ListenNowComponent_UpdateMetadata` function in the freshly re-imported
|
|
2556
|
+
// module calls `ɵɵreplaceMetadata` → `ɵɵdefineComponent` → `getComponentId`
|
|
2557
|
+
// against a class that shares its name with the just-rebooted instance but
|
|
2558
|
+
// not its identity (one comes from the route-loaded module, the other from
|
|
2559
|
+
// the dynamically-fetched `/@ng/component?c=…` metadata chunk). The check
|
|
2560
|
+
// surfaces every component the user touches as a noisy warning even though
|
|
2561
|
+
// there's no real collision — same logical class, two transient identities
|
|
2562
|
+
// during the HMR cycle.
|
|
2563
|
+
//
|
|
2564
|
+
// Real collisions — different classes that happen to hash to the same id —
|
|
2565
|
+
// produce a warning where `'X' and 'Y'` (different class names) appear in
|
|
2566
|
+
// the message. We only filter when both names match, so genuine duplicates
|
|
2567
|
+
// still reach the user.
|
|
2568
|
+
//
|
|
2569
|
+
// Install once per process; the filter self-detaches if the warning text
|
|
2570
|
+
// changes shape (defensive against future Angular wording tweaks).
|
|
2571
|
+
(() => {
|
|
2572
|
+
const w = global;
|
|
2573
|
+
if (w.__NS_ANGULAR_NG0912_FILTER_INSTALLED__)
|
|
2574
|
+
return;
|
|
2575
|
+
w.__NS_ANGULAR_NG0912_FILTER_INSTALLED__ = true;
|
|
2576
|
+
const origWarn = console.warn.bind(console);
|
|
2577
|
+
// Pattern: "Components 'Foo' and 'Bar' with selector 'xyz'" — capture
|
|
2578
|
+
// both class names and compare. We suppress only when they're identical
|
|
2579
|
+
// (the HMR pseudo-collision signature).
|
|
2580
|
+
const NG0912_NAME_MATCH = /NG0912[\s\S]*?Components '([^']+)' and '([^']+)' with selector/;
|
|
2581
|
+
console.warn = (...args) => {
|
|
2582
|
+
const msg = String(args[0] ?? '');
|
|
2583
|
+
if (msg.includes('NG0912')) {
|
|
2584
|
+
const m = NG0912_NAME_MATCH.exec(msg);
|
|
2585
|
+
if (m && m[1] === m[2]) {
|
|
2586
|
+
return;
|
|
2587
|
+
}
|
|
2588
|
+
}
|
|
2589
|
+
origWarn(...args);
|
|
2590
|
+
};
|
|
2591
|
+
})();
|
|
2536
2592
|
global['__reboot_ng_modules__'] = (shouldDisposePlatform = false) => {
|
|
2537
2593
|
// Bump the global HMR cycle counter so subsequent diagnostic log
|
|
2538
2594
|
// lines (class registry, dialog services) can be cross-referenced
|
|
@@ -3144,6 +3200,12 @@ class ViewUtil {
|
|
|
3144
3200
|
}
|
|
3145
3201
|
const ngView = view;
|
|
3146
3202
|
ngView.nodeName = name;
|
|
3203
|
+
// Angular 21+ reads `rootElement.tagName.toLowerCase()` during component bootstrap
|
|
3204
|
+
// (`locateHostElement`) to reject `<script>` host elements. Native Views have no
|
|
3205
|
+
// intrinsic `tagName`, so without this assignment the boot throws
|
|
3206
|
+
// `Cannot read properties of undefined (reading 'toLowerCase')`. Mirror DOM
|
|
3207
|
+
// conventions where `tagName` equals `nodeName` for element nodes.
|
|
3208
|
+
ngView.tagName = name;
|
|
3147
3209
|
ngView.meta = getViewMeta(name);
|
|
3148
3210
|
// we're setting the node type of the view
|
|
3149
3211
|
// to 'element' because of checks done in the
|
|
@@ -3545,22 +3607,35 @@ class NativeScriptRenderer {
|
|
|
3545
3607
|
if (NativeScriptDebug.enabled) {
|
|
3546
3608
|
NativeScriptDebug.rendererLog(`NativeScriptRenderer.selectRootElement: ${selectorOrNode}`);
|
|
3547
3609
|
}
|
|
3610
|
+
// Angular 21+ reads `rootElement.tagName.toLowerCase()` after this call
|
|
3611
|
+
// (`locateHostElement`) to reject `<script>` hosts. Guarantee every return
|
|
3612
|
+
// path produces a View with a non-empty string `tagName`; otherwise the
|
|
3613
|
+
// bootstrap throws `Cannot read properties of undefined (reading 'toLowerCase')`.
|
|
3614
|
+
const ensureTagName = (view, fallback) => {
|
|
3615
|
+
if (view && typeof view.tagName !== 'string') {
|
|
3616
|
+
try {
|
|
3617
|
+
view.tagName = view.nodeName || fallback || 'view';
|
|
3618
|
+
}
|
|
3619
|
+
catch { }
|
|
3620
|
+
}
|
|
3621
|
+
return view;
|
|
3622
|
+
};
|
|
3548
3623
|
if (selectorOrNode instanceof View) {
|
|
3549
|
-
return selectorOrNode;
|
|
3624
|
+
return ensureTagName(selectorOrNode, '');
|
|
3550
3625
|
}
|
|
3551
3626
|
if (selectorOrNode && selectorOrNode[0] === '#') {
|
|
3552
3627
|
const result = getViewById(this.rootView, selectorOrNode.slice(1));
|
|
3553
|
-
return (result || this.rootView);
|
|
3628
|
+
return ensureTagName((result || this.rootView), selectorOrNode);
|
|
3554
3629
|
}
|
|
3555
3630
|
if (typeof selectorOrNode === 'string') {
|
|
3556
3631
|
const view = this.viewUtil.createView(selectorOrNode);
|
|
3557
3632
|
if (getFirstNativeLikeView(view) === view) {
|
|
3558
3633
|
// view is nativelike!
|
|
3559
3634
|
this.appendChild(this.rootView, view);
|
|
3560
|
-
return view;
|
|
3635
|
+
return ensureTagName(view, selectorOrNode);
|
|
3561
3636
|
}
|
|
3562
3637
|
}
|
|
3563
|
-
return this.rootView;
|
|
3638
|
+
return ensureTagName(this.rootView, '');
|
|
3564
3639
|
}
|
|
3565
3640
|
parentNode(node) {
|
|
3566
3641
|
if (NativeScriptDebug.enabled) {
|
|
@@ -9892,29 +9967,65 @@ function writeAngularHmrRouteState(value, options) {
|
|
|
9892
9967
|
function captureAngularHmrPendingStartPath(value, source = 'hmr-reboot') {
|
|
9893
9968
|
return writeAngularHmrRouteState(value, { pending: true, source });
|
|
9894
9969
|
}
|
|
9970
|
+
/**
|
|
9971
|
+
* Match Angular Router's named-outlet syntax in a serialized URL.
|
|
9972
|
+
*
|
|
9973
|
+
* The router emits named outlets as `(outletName:segments[//otherName:segments])`
|
|
9974
|
+
* — see `DefaultUrlSerializer`. Any URL the captures match `/\(\w+:`
|
|
9975
|
+
* contains at least one named-outlet segment.
|
|
9976
|
+
*
|
|
9977
|
+
* Used to gate the start-path deferral below: when a captured URL has named
|
|
9978
|
+
* outlets it CANNOT be used as the initial-navigation path on the next boot
|
|
9979
|
+
* (the outlet directives are inside child components that don't exist yet at
|
|
9980
|
+
* `router.initialNavigation()` time, so `PageRouterOutlet.activateWith`
|
|
9981
|
+
* returns early with "No outlet found relative to activated route" and the
|
|
9982
|
+
* app renders a white screen).
|
|
9983
|
+
*/
|
|
9984
|
+
function hasNamedOutletsInUrl(url) {
|
|
9985
|
+
if (typeof url !== 'string') {
|
|
9986
|
+
return false;
|
|
9987
|
+
}
|
|
9988
|
+
return /\([A-Za-z0-9_-]+:/.test(url);
|
|
9989
|
+
}
|
|
9895
9990
|
function readAngularHmrPendingStartPath() {
|
|
9896
|
-
//
|
|
9897
|
-
//
|
|
9898
|
-
//
|
|
9899
|
-
//
|
|
9991
|
+
// HMR-DX policy: restore only the user's CURRENT URL. NativeScript Frames
|
|
9992
|
+
// own the back-stack, not the URL, so walking captured history URLs forward
|
|
9993
|
+
// doesn't reconstruct the page stack — it just causes visible re-navigation
|
|
9994
|
+
// sequences (especially with tab-based named outlets) that the user has to
|
|
9995
|
+
// sit through after every save. We pick the last captured URL as the
|
|
9996
|
+
// restoration target and bail on the history walk entirely. The
|
|
9997
|
+
// `forward-navigations` reader returns at most one URL (the deferred
|
|
9998
|
+
// named-outlet case), so the replay service performs zero or one
|
|
9999
|
+
// post-bootstrap navigation, not N.
|
|
9900
10000
|
const pendingHistory = readHistoryArray(PENDING_HISTORY_KEY);
|
|
9901
10001
|
if (pendingHistory.length > 0) {
|
|
9902
|
-
|
|
9903
|
-
|
|
9904
|
-
//
|
|
9905
|
-
//
|
|
9906
|
-
//
|
|
9907
|
-
//
|
|
9908
|
-
|
|
9909
|
-
|
|
10002
|
+
const target = pendingHistory[pendingHistory.length - 1];
|
|
10003
|
+
beginAngularHmrRouteRestore(target);
|
|
10004
|
+
// Named-outlet URLs cannot be served as the initial navigation URL.
|
|
10005
|
+
// The outlet directives (e.g. `<page-router-outlet name="listenNowTab">`)
|
|
10006
|
+
// live inside child components that only render AFTER the primary
|
|
10007
|
+
// outlet activates. On `router.initialNavigation()` with a URL like
|
|
10008
|
+
// `/(listenNowTab:listen-now)`, Angular tries to activate `listenNowTab`
|
|
10009
|
+
// immediately and `PageRouterOutlet.activateWith` returns early because
|
|
10010
|
+
// no outlet is registered yet — white screen. Defer to a single forward
|
|
10011
|
+
// navigation that fires AFTER the first NavigationEnd, by which time the
|
|
10012
|
+
// outlet directives have registered.
|
|
10013
|
+
if (hasNamedOutletsInUrl(target)) {
|
|
10014
|
+
return '/';
|
|
10015
|
+
}
|
|
10016
|
+
return target;
|
|
9910
10017
|
}
|
|
9911
10018
|
const g = getGlobalState();
|
|
9912
10019
|
const fallback = normalizeAngularHmrRouteUrl(g[PENDING_START_PATH_KEY]?.url ?? g[PENDING_START_PATH_KEY]) || '';
|
|
9913
10020
|
if (fallback) {
|
|
9914
|
-
//
|
|
9915
|
-
|
|
9916
|
-
|
|
9917
|
-
|
|
10021
|
+
// Same deferral as above for the legacy single-URL slot.
|
|
10022
|
+
if (hasNamedOutletsInUrl(fallback)) {
|
|
10023
|
+
beginAngularHmrRouteRestore(fallback);
|
|
10024
|
+
// Stash the deferred URL so the forward-navigations reader picks it
|
|
10025
|
+
// up after the initial '/' navigation lands.
|
|
10026
|
+
writeHistoryArray(PENDING_HISTORY_KEY, [fallback]);
|
|
10027
|
+
return '/';
|
|
10028
|
+
}
|
|
9918
10029
|
beginAngularHmrRouteRestore(fallback);
|
|
9919
10030
|
}
|
|
9920
10031
|
return fallback;
|
|
@@ -10067,15 +10178,29 @@ function readAngularHmrPendingRouteHistory() {
|
|
|
10067
10178
|
}
|
|
10068
10179
|
/**
|
|
10069
10180
|
* Read URLs to navigate forward through after the initial navigation finishes.
|
|
10070
|
-
*
|
|
10071
|
-
*
|
|
10181
|
+
*
|
|
10182
|
+
* HMR-DX policy: at most one post-bootstrap navigation. We only need a forward
|
|
10183
|
+
* navigation when `readAngularHmrPendingStartPath` had to return '/' because
|
|
10184
|
+
* the user's current URL contains named outlets (the outlet directives don't
|
|
10185
|
+
* exist yet at initial-navigation time, so we defer to a single nav after the
|
|
10186
|
+
* primary outlet has registered them). For URLs with no named outlets the
|
|
10187
|
+
* start path IS the user's current URL and no forward step is needed.
|
|
10188
|
+
*
|
|
10189
|
+
* We intentionally do NOT walk the captured back-stack of intermediate URLs —
|
|
10190
|
+
* NativeScript Frames own the page stack, not the URL serializer, so URL
|
|
10191
|
+
* replay never reconstructs the Frame stack anyway and only creates visible
|
|
10192
|
+
* mid-save re-navigations.
|
|
10072
10193
|
*/
|
|
10073
10194
|
function readAngularHmrPendingForwardNavigations() {
|
|
10074
10195
|
const pending = readHistoryArray(PENDING_HISTORY_KEY);
|
|
10075
|
-
if (pending.length
|
|
10196
|
+
if (pending.length === 0) {
|
|
10076
10197
|
return [];
|
|
10077
10198
|
}
|
|
10078
|
-
|
|
10199
|
+
const target = pending[pending.length - 1];
|
|
10200
|
+
if (hasNamedOutletsInUrl(target)) {
|
|
10201
|
+
return [target];
|
|
10202
|
+
}
|
|
10203
|
+
return [];
|
|
10079
10204
|
}
|
|
10080
10205
|
/**
|
|
10081
10206
|
* Clear the pending snapshot. The router replay calls this once it finishes
|
|
@@ -10169,14 +10294,18 @@ function endAngularHmrRouteRestore() {
|
|
|
10169
10294
|
*/
|
|
10170
10295
|
const REPLAY_COMPLETED_GRACE_MS = 1000;
|
|
10171
10296
|
/**
|
|
10172
|
-
*
|
|
10173
|
-
*
|
|
10174
|
-
*
|
|
10175
|
-
* back
|
|
10297
|
+
* Restores the user's CURRENT URL after an HMR reboot.
|
|
10298
|
+
*
|
|
10299
|
+
* HMR-DX policy: at most one post-bootstrap navigation. The framework no
|
|
10300
|
+
* longer walks the captured back-stack (`stack[1..n]`) — NativeScript Frames
|
|
10301
|
+
* own the page stack, not the URL serializer, so the URL walk never rebuilt
|
|
10302
|
+
* the Frame stack anyway, it only created visible mid-save re-navigation
|
|
10303
|
+
* sequences (especially with tab-based named outlets) that the user had to
|
|
10304
|
+
* sit through. Now `readAngularHmrPendingForwardNavigations()` returns at
|
|
10305
|
+
* most one URL — the deferred named-outlet case — and we replay only that.
|
|
10176
10306
|
*
|
|
10177
|
-
*
|
|
10178
|
-
*
|
|
10179
|
-
* — the user keeps whichever subset of the stack we successfully re-pushed.
|
|
10307
|
+
* Any failure (cancelled navigation, unrouteable URL) closes the restoring
|
|
10308
|
+
* window with `replay-aborted` so default navigations can resume.
|
|
10180
10309
|
*/
|
|
10181
10310
|
class NativeScriptAngularHmrRouteReplay {
|
|
10182
10311
|
constructor(router) {
|