@nativescript/vite 8.0.0-alpha.11 → 8.0.0-alpha.12

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.
@@ -0,0 +1,288 @@
1
+ /**
2
+ * Re-inject `/* @vite-ignore *\/` into Angular's HMR initializer dynamic
3
+ * imports.
4
+ *
5
+ * # Why this exists
6
+ *
7
+ * Angular's compiler (`@angular/compiler`'s `compileHmrInitializer`) emits
8
+ * each `@Component`-decorated class's HMR loader as:
9
+ *
10
+ * ```js
11
+ * function FooComponent_HmrLoad(t) {
12
+ * import(\/* @vite-ignore *\/ i0.ɵɵgetReplaceMetadataURL(id, t, import.meta.url))
13
+ * .then((m) => m.default && i0.ɵɵreplaceMetadata(FooComponent, m.default, ...));
14
+ * }
15
+ * ```
16
+ *
17
+ * The `\/* @vite-ignore *\/` annotation tells Vite "do not try to
18
+ * statically analyze this dynamic import" — the URL is computed at
19
+ * runtime by `ɵɵgetReplaceMetadataURL`, which produces something like
20
+ * `http://host/ns/m/<componentDir>/@ng/component?c=<id>&t=<ts>` to be
21
+ * resolved by Analog's `liveReloadPlugin` middleware on the dev server.
22
+ *
23
+ * Somewhere along the post-Angular transform chain — empirically the
24
+ * `compact: false` Babel pass driven by the Angular linker, but
25
+ * potentially other plugins as well — the leading-argument comment is
26
+ * being dropped. By the time the file lands on the device, the
27
+ * compiled emit reads:
28
+ *
29
+ * ```js
30
+ * import(i0.ɵɵgetReplaceMetadataURL(id, t, import.meta.url))
31
+ * ```
32
+ *
33
+ * Vite's static analyzer logs:
34
+ *
35
+ * > The above dynamic import cannot be analyzed by Vite.
36
+ *
37
+ * and rewrites the call site to route through Vite's runtime resolver,
38
+ * which fails on the iOS runtime because the resolver expects a
39
+ * statically-known module specifier. The HMR loader IIFE runs at every
40
+ * component module evaluation (gated by `ngDevMode`), so the failure
41
+ * fires at boot for the FIRST `@Component` whose module is evaluated —
42
+ * typically a base/utility component like `ConfirmationDialogBaseComponent`
43
+ * — and aborts session startup with:
44
+ *
45
+ * > TypeError at Module.ɵɵgetReplaceMetadataURL
46
+ *
47
+ * Re-inserting the annotation downstream of every other transform makes
48
+ * us tolerant of upstream comment-loss without depending on the linker's
49
+ * comment behaviour. The fix is purely additive: if the comment is still
50
+ * present (Angular versions that emit it differently, or future
51
+ * compilers that wrap the URL in an alternate helper), `appendIfMissing`
52
+ * leaves the import untouched.
53
+ *
54
+ * # Idempotence
55
+ *
56
+ * The helper is safe to call repeatedly on the same source — once the
57
+ * annotation is present, subsequent calls become a no-op match by match.
58
+ * Vite's transform pipeline can replay cached transforms during a
59
+ * single dev session, so idempotence is required, not optional.
60
+ *
61
+ * # Surface area
62
+ *
63
+ * We only touch `import()` calls whose argument expression contains
64
+ * `ɵɵgetReplaceMetadataURL` (matching either the literal Unicode form
65
+ * or the escaped `\u0275\u0275getReplaceMetadataURL`). Every other
66
+ * dynamic import is left alone — an over-broad sweep would suppress
67
+ * Vite warnings on user dynamic imports that genuinely should be
68
+ * statically analyzed.
69
+ */
70
+ const ANGULAR_HMR_IDENTIFIER = 'getReplaceMetadataURL';
71
+ const VITE_IGNORE_COMMENT = '/* @vite-ignore */';
72
+ /**
73
+ * Inject `/* @vite-ignore *\/` into every `import()` whose argument
74
+ * references Angular's `ɵɵgetReplaceMetadataURL`. Returns the original
75
+ * code unchanged when no qualifying imports are found.
76
+ */
77
+ export function injectAngularHmrViteIgnore(code) {
78
+ if (!code)
79
+ return code;
80
+ // Cheap pre-check: bail out before walking the source if neither
81
+ // the unicode nor the escape form of the identifier is anywhere in
82
+ // the file. The vast majority of files aren't components, so this
83
+ // short-circuit is the hot path.
84
+ if (!code.includes(ANGULAR_HMR_IDENTIFIER))
85
+ return code;
86
+ let output = '';
87
+ let cursor = 0;
88
+ let changed = false;
89
+ while (cursor < code.length) {
90
+ const importIndex = findNextImportCall(code, cursor);
91
+ if (importIndex === -1) {
92
+ output += code.slice(cursor);
93
+ break;
94
+ }
95
+ const openParenIndex = findOpenParenAfter(code, importIndex + 'import'.length);
96
+ if (openParenIndex === -1) {
97
+ output += code.slice(cursor, importIndex + 'import'.length);
98
+ cursor = importIndex + 'import'.length;
99
+ continue;
100
+ }
101
+ const closeParenIndex = findMatchingDelimiter(code, openParenIndex, '(', ')');
102
+ if (closeParenIndex === -1) {
103
+ output += code.slice(cursor, openParenIndex + 1);
104
+ cursor = openParenIndex + 1;
105
+ continue;
106
+ }
107
+ const argumentBody = code.slice(openParenIndex + 1, closeParenIndex);
108
+ if (!referencesReplaceMetadataUrl(argumentBody)) {
109
+ output += code.slice(cursor, closeParenIndex + 1);
110
+ cursor = closeParenIndex + 1;
111
+ continue;
112
+ }
113
+ if (alreadyAnnotated(argumentBody)) {
114
+ output += code.slice(cursor, closeParenIndex + 1);
115
+ cursor = closeParenIndex + 1;
116
+ continue;
117
+ }
118
+ // Insert the annotation immediately after `import(` so the
119
+ // original argument expression — including any leading
120
+ // whitespace the upstream emitter chose — keeps its byte
121
+ // layout. This preserves source-map line stability for the
122
+ // rest of the file: only column offsets after the injection
123
+ // shift, never line numbers.
124
+ output += code.slice(cursor, openParenIndex + 1);
125
+ output += ` ${VITE_IGNORE_COMMENT} `;
126
+ output += code.slice(openParenIndex + 1, closeParenIndex + 1);
127
+ cursor = closeParenIndex + 1;
128
+ changed = true;
129
+ }
130
+ return changed ? output : code;
131
+ }
132
+ function findNextImportCall(source, startIndex) {
133
+ let i = startIndex;
134
+ while (i < source.length) {
135
+ const next = source.indexOf('import', i);
136
+ if (next === -1)
137
+ return -1;
138
+ // Reject `import.meta` and `import ` keyword forms; only
139
+ // `import(` (with optional whitespace) is a dynamic import.
140
+ const tail = next + 'import'.length;
141
+ const before = source.charCodeAt(next - 1);
142
+ const isWordCharBefore = isIdentifierPart(before);
143
+ if (!isWordCharBefore) {
144
+ let scan = tail;
145
+ while (scan < source.length && isWhitespace(source.charCodeAt(scan)))
146
+ scan++;
147
+ if (source.charCodeAt(scan) === 0x28 /* '(' */) {
148
+ return next;
149
+ }
150
+ }
151
+ i = tail;
152
+ }
153
+ return -1;
154
+ }
155
+ function findOpenParenAfter(source, index) {
156
+ let i = index;
157
+ while (i < source.length && isWhitespace(source.charCodeAt(i)))
158
+ i++;
159
+ if (source.charCodeAt(i) === 0x28 /* '(' */)
160
+ return i;
161
+ return -1;
162
+ }
163
+ function alreadyAnnotated(argumentBody) {
164
+ // Trim only the leading whitespace + comments — body may have many
165
+ // non-`@vite-ignore` block comments later that we don't want to
166
+ // confuse for an already-applied annotation.
167
+ let i = 0;
168
+ while (i < argumentBody.length) {
169
+ const c = argumentBody.charCodeAt(i);
170
+ if (isWhitespace(c)) {
171
+ i++;
172
+ continue;
173
+ }
174
+ if (c === 0x2f /* '/' */ && argumentBody.charCodeAt(i + 1) === 0x2a /* '*' */) {
175
+ const closeIndex = argumentBody.indexOf('*/', i + 2);
176
+ if (closeIndex === -1)
177
+ return false;
178
+ const commentBody = argumentBody.slice(i + 2, closeIndex);
179
+ if (commentBody.includes('@vite-ignore'))
180
+ return true;
181
+ i = closeIndex + 2;
182
+ continue;
183
+ }
184
+ // First non-whitespace, non-block-comment token — there's no
185
+ // annotation in the leading whitespace window.
186
+ return false;
187
+ }
188
+ return false;
189
+ }
190
+ function referencesReplaceMetadataUrl(argumentBody) {
191
+ if (!argumentBody)
192
+ return false;
193
+ if (argumentBody.includes(ANGULAR_HMR_IDENTIFIER))
194
+ return true;
195
+ // `\u0275\u0275getReplaceMetadataURL` — unicode-escaped form some
196
+ // transforms emit. The substring above already covers the suffix
197
+ // regardless of the prefix encoding, so this branch is mostly
198
+ // defensive — keep it explicit so future changes to the identifier
199
+ // (e.g. a `replaceMetadataURL` rename without `ɵɵ`) don't silently
200
+ // stop matching.
201
+ return /\\u0275\\u0275getReplaceMetadataURL/.test(argumentBody);
202
+ }
203
+ function isWhitespace(code) {
204
+ return code === 0x20 || code === 0x09 || code === 0x0a || code === 0x0d || code === 0x0b || code === 0x0c;
205
+ }
206
+ function isIdentifierPart(code) {
207
+ if (Number.isNaN(code))
208
+ return false;
209
+ if (code === 0x5f /* '_' */ || code === 0x24 /* '$' */)
210
+ return true;
211
+ if (code >= 0x30 && code <= 0x39)
212
+ return true;
213
+ if (code >= 0x41 && code <= 0x5a)
214
+ return true;
215
+ if (code >= 0x61 && code <= 0x7a)
216
+ return true;
217
+ return false;
218
+ }
219
+ /**
220
+ * Comment- and string-aware paren matcher. Used to find the closing
221
+ * `)` for `import(` even when the argument expression contains
222
+ * commented-out parens, template literals, or nested calls. Imported
223
+ * inline (rather than from `synthesize-decorator-ctor-parameters.ts`'s
224
+ * private helper) so this file has no internal dependencies and can
225
+ * be tested in isolation.
226
+ */
227
+ function findMatchingDelimiter(source, openIndex, openChar, closeChar) {
228
+ if (openIndex < 0 || source[openIndex] !== openChar)
229
+ return -1;
230
+ let depth = 0;
231
+ let quote = null;
232
+ let escape = false;
233
+ let inLineComment = false;
234
+ let inBlockComment = false;
235
+ for (let index = openIndex; index < source.length; index++) {
236
+ const char = source[index];
237
+ const next = source[index + 1];
238
+ if (inLineComment) {
239
+ if (char === '\n')
240
+ inLineComment = false;
241
+ continue;
242
+ }
243
+ if (inBlockComment) {
244
+ if (char === '*' && next === '/') {
245
+ inBlockComment = false;
246
+ index++;
247
+ }
248
+ continue;
249
+ }
250
+ if (quote) {
251
+ if (escape) {
252
+ escape = false;
253
+ continue;
254
+ }
255
+ if (char === '\\') {
256
+ escape = true;
257
+ continue;
258
+ }
259
+ if (char === quote)
260
+ quote = null;
261
+ continue;
262
+ }
263
+ if (char === '/' && next === '/') {
264
+ inLineComment = true;
265
+ index++;
266
+ continue;
267
+ }
268
+ if (char === '/' && next === '*') {
269
+ inBlockComment = true;
270
+ index++;
271
+ continue;
272
+ }
273
+ if (char === '"' || char === "'" || char === '`') {
274
+ quote = char;
275
+ continue;
276
+ }
277
+ if (char === openChar) {
278
+ depth++;
279
+ }
280
+ else if (char === closeChar) {
281
+ depth--;
282
+ if (depth === 0)
283
+ return index;
284
+ }
285
+ }
286
+ return -1;
287
+ }
288
+ //# sourceMappingURL=inject-hmr-vite-ignore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inject-hmr-vite-ignore.js","sourceRoot":"","sources":["../../../../../packages/vite/helpers/angular/inject-hmr-vite-ignore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoEG;AAEH,MAAM,sBAAsB,GAAG,uBAAuB,CAAC;AACvD,MAAM,mBAAmB,GAAG,oBAAoB,CAAC;AAEjD;;;;GAIG;AACH,MAAM,UAAU,0BAA0B,CAAC,IAAY;IACtD,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IACvB,iEAAiE;IACjE,mEAAmE;IACnE,kEAAkE;IAClE,iCAAiC;IACjC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,sBAAsB,CAAC;QAAE,OAAO,IAAI,CAAC;IAExD,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,IAAI,OAAO,GAAG,KAAK,CAAC;IAEpB,OAAO,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;QAC7B,MAAM,WAAW,GAAG,kBAAkB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACrD,IAAI,WAAW,KAAK,CAAC,CAAC,EAAE,CAAC;YACxB,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YAC7B,MAAM;QACP,CAAC;QAED,MAAM,cAAc,GAAG,kBAAkB,CAAC,IAAI,EAAE,WAAW,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;QAC/E,IAAI,cAAc,KAAK,CAAC,CAAC,EAAE,CAAC;YAC3B,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,WAAW,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;YAC5D,MAAM,GAAG,WAAW,GAAG,QAAQ,CAAC,MAAM,CAAC;YACvC,SAAS;QACV,CAAC;QAED,MAAM,eAAe,GAAG,qBAAqB,CAAC,IAAI,EAAE,cAAc,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QAC9E,IAAI,eAAe,KAAK,CAAC,CAAC,EAAE,CAAC;YAC5B,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,cAAc,GAAG,CAAC,CAAC,CAAC;YACjD,MAAM,GAAG,cAAc,GAAG,CAAC,CAAC;YAC5B,SAAS;QACV,CAAC;QAED,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,GAAG,CAAC,EAAE,eAAe,CAAC,CAAC;QACrE,IAAI,CAAC,4BAA4B,CAAC,YAAY,CAAC,EAAE,CAAC;YACjD,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,eAAe,GAAG,CAAC,CAAC,CAAC;YAClD,MAAM,GAAG,eAAe,GAAG,CAAC,CAAC;YAC7B,SAAS;QACV,CAAC;QAED,IAAI,gBAAgB,CAAC,YAAY,CAAC,EAAE,CAAC;YACpC,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,eAAe,GAAG,CAAC,CAAC,CAAC;YAClD,MAAM,GAAG,eAAe,GAAG,CAAC,CAAC;YAC7B,SAAS;QACV,CAAC;QAED,2DAA2D;QAC3D,uDAAuD;QACvD,yDAAyD;QACzD,2DAA2D;QAC3D,4DAA4D;QAC5D,6BAA6B;QAC7B,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,cAAc,GAAG,CAAC,CAAC,CAAC;QACjD,MAAM,IAAI,IAAI,mBAAmB,GAAG,CAAC;QACrC,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC,cAAc,GAAG,CAAC,EAAE,eAAe,GAAG,CAAC,CAAC,CAAC;QAC9D,MAAM,GAAG,eAAe,GAAG,CAAC,CAAC;QAC7B,OAAO,GAAG,IAAI,CAAC;IAChB,CAAC;IAED,OAAO,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;AAChC,CAAC;AAED,SAAS,kBAAkB,CAAC,MAAc,EAAE,UAAkB;IAC7D,IAAI,CAAC,GAAG,UAAU,CAAC;IACnB,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC;QAC1B,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;QACzC,IAAI,IAAI,KAAK,CAAC,CAAC;YAAE,OAAO,CAAC,CAAC,CAAC;QAC3B,yDAAyD;QACzD,4DAA4D;QAC5D,MAAM,IAAI,GAAG,IAAI,GAAG,QAAQ,CAAC,MAAM,CAAC;QACpC,MAAM,MAAM,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC;QAC3C,MAAM,gBAAgB,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;QAClD,IAAI,CAAC,gBAAgB,EAAE,CAAC;YACvB,IAAI,IAAI,GAAG,IAAI,CAAC;YAChB,OAAO,IAAI,GAAG,MAAM,CAAC,MAAM,IAAI,YAAY,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;gBAAE,IAAI,EAAE,CAAC;YAC7E,IAAI,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,SAAS,EAAE,CAAC;gBAChD,OAAO,IAAI,CAAC;YACb,CAAC;QACF,CAAC;QACD,CAAC,GAAG,IAAI,CAAC;IACV,CAAC;IACD,OAAO,CAAC,CAAC,CAAC;AACX,CAAC;AAED,SAAS,kBAAkB,CAAC,MAAc,EAAE,KAAa;IACxD,IAAI,CAAC,GAAG,KAAK,CAAC;IACd,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,IAAI,YAAY,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QAAE,CAAC,EAAE,CAAC;IACpE,IAAI,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,SAAS;QAAE,OAAO,CAAC,CAAC;IACtD,OAAO,CAAC,CAAC,CAAC;AACX,CAAC;AAED,SAAS,gBAAgB,CAAC,YAAoB;IAC7C,mEAAmE;IACnE,gEAAgE;IAChE,6CAA6C;IAC7C,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,OAAO,CAAC,GAAG,YAAY,CAAC,MAAM,EAAE,CAAC;QAChC,MAAM,CAAC,GAAG,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QACrC,IAAI,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC;YACrB,CAAC,EAAE,CAAC;YACJ,SAAS;QACV,CAAC;QACD,IAAI,CAAC,KAAK,IAAI,CAAC,SAAS,IAAI,YAAY,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,SAAS,EAAE,CAAC;YAC/E,MAAM,UAAU,GAAG,YAAY,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;YACrD,IAAI,UAAU,KAAK,CAAC,CAAC;gBAAE,OAAO,KAAK,CAAC;YACpC,MAAM,WAAW,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,EAAE,UAAU,CAAC,CAAC;YAC1D,IAAI,WAAW,CAAC,QAAQ,CAAC,cAAc,CAAC;gBAAE,OAAO,IAAI,CAAC;YACtD,CAAC,GAAG,UAAU,GAAG,CAAC,CAAC;YACnB,SAAS;QACV,CAAC;QACD,6DAA6D;QAC7D,+CAA+C;QAC/C,OAAO,KAAK,CAAC;IACd,CAAC;IACD,OAAO,KAAK,CAAC;AACd,CAAC;AAED,SAAS,4BAA4B,CAAC,YAAoB;IACzD,IAAI,CAAC,YAAY;QAAE,OAAO,KAAK,CAAC;IAChC,IAAI,YAAY,CAAC,QAAQ,CAAC,sBAAsB,CAAC;QAAE,OAAO,IAAI,CAAC;IAC/D,kEAAkE;IAClE,iEAAiE;IACjE,8DAA8D;IAC9D,mEAAmE;IACnE,mEAAmE;IACnE,iBAAiB;IACjB,OAAO,qCAAqC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;AACjE,CAAC;AAED,SAAS,YAAY,CAAC,IAAY;IACjC,OAAO,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,IAAI,CAAC;AAC3G,CAAC;AAED,SAAS,gBAAgB,CAAC,IAAY;IACrC,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IACrC,IAAI,IAAI,KAAK,IAAI,CAAC,SAAS,IAAI,IAAI,KAAK,IAAI,CAAC,SAAS;QAAE,OAAO,IAAI,CAAC;IACpE,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI;QAAE,OAAO,IAAI,CAAC;IAC9C,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI;QAAE,OAAO,IAAI,CAAC;IAC9C,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI;QAAE,OAAO,IAAI,CAAC;IAC9C,OAAO,KAAK,CAAC;AACd,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,qBAAqB,CAAC,MAAc,EAAE,SAAiB,EAAE,QAAgB,EAAE,SAAiB;IACpG,IAAI,SAAS,GAAG,CAAC,IAAI,MAAM,CAAC,SAAS,CAAC,KAAK,QAAQ;QAAE,OAAO,CAAC,CAAC,CAAC;IAE/D,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,KAAK,GAAkB,IAAI,CAAC;IAChC,IAAI,MAAM,GAAG,KAAK,CAAC;IACnB,IAAI,aAAa,GAAG,KAAK,CAAC;IAC1B,IAAI,cAAc,GAAG,KAAK,CAAC;IAE3B,KAAK,IAAI,KAAK,GAAG,SAAS,EAAE,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC;QAC5D,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;QAC3B,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;QAE/B,IAAI,aAAa,EAAE,CAAC;YACnB,IAAI,IAAI,KAAK,IAAI;gBAAE,aAAa,GAAG,KAAK,CAAC;YACzC,SAAS;QACV,CAAC;QACD,IAAI,cAAc,EAAE,CAAC;YACpB,IAAI,IAAI,KAAK,GAAG,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;gBAClC,cAAc,GAAG,KAAK,CAAC;gBACvB,KAAK,EAAE,CAAC;YACT,CAAC;YACD,SAAS;QACV,CAAC;QACD,IAAI,KAAK,EAAE,CAAC;YACX,IAAI,MAAM,EAAE,CAAC;gBACZ,MAAM,GAAG,KAAK,CAAC;gBACf,SAAS;YACV,CAAC;YACD,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;gBACnB,MAAM,GAAG,IAAI,CAAC;gBACd,SAAS;YACV,CAAC;YACD,IAAI,IAAI,KAAK,KAAK;gBAAE,KAAK,GAAG,IAAI,CAAC;YACjC,SAAS;QACV,CAAC;QAED,IAAI,IAAI,KAAK,GAAG,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;YAClC,aAAa,GAAG,IAAI,CAAC;YACrB,KAAK,EAAE,CAAC;YACR,SAAS;QACV,CAAC;QACD,IAAI,IAAI,KAAK,GAAG,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;YAClC,cAAc,GAAG,IAAI,CAAC;YACtB,KAAK,EAAE,CAAC;YACR,SAAS;QACV,CAAC;QACD,IAAI,IAAI,KAAK,GAAG,IAAI,IAAI,KAAK,GAAG,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;YAClD,KAAK,GAAG,IAAI,CAAC;YACb,SAAS;QACV,CAAC;QAED,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;YACvB,KAAK,EAAE,CAAC;QACT,CAAC;aAAM,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YAC/B,KAAK,EAAE,CAAC;YACR,IAAI,KAAK,KAAK,CAAC;gBAAE,OAAO,KAAK,CAAC;QAC/B,CAAC;IACF,CAAC;IAED,OAAO,CAAC,CAAC,CAAC;AACX,CAAC"}
@@ -1,14 +1,22 @@
1
1
  import path from 'path';
2
2
  import { resolveNativeScriptPlatformFile } from './utils.js';
3
+ const normalizeImporterId = (importer) => {
4
+ const cleanImporter = importer.split('?', 1)[0];
5
+ if (!cleanImporter.startsWith('/@fs/')) {
6
+ return cleanImporter;
7
+ }
8
+ return /^\/\@fs\/[A-Za-z]:/.test(cleanImporter) ? cleanImporter.slice('/@fs/'.length) : cleanImporter.slice('/@fs'.length);
9
+ };
3
10
  export default function NativeScriptPlugin(options) {
4
11
  return {
5
12
  name: 'vite:nativescript',
13
+ enforce: 'pre',
6
14
  resolveId(source, importer) {
7
15
  const platform = options.platform;
8
16
  if (!platform || !importer || source.startsWith('.') === false) {
9
17
  return null;
10
18
  }
11
- const resolved = path.resolve(path.dirname(importer), source);
19
+ const resolved = path.resolve(path.dirname(normalizeImporterId(importer)), source);
12
20
  const extVariants = ['.ts', '.js'];
13
21
  for (const ext of extVariants) {
14
22
  const file = resolveNativeScriptPlatformFile(resolved + ext, platform);
@@ -1 +1 @@
1
- {"version":3,"file":"resolver.js","sourceRoot":"","sources":["../../../../packages/vite/helpers/resolver.ts"],"names":[],"mappings":"AACA,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,+BAA+B,EAAE,MAAM,YAAY,CAAC;AAE7D,MAAM,CAAC,OAAO,UAAU,kBAAkB,CAAC,OAAqD;IAC/F,OAAO;QACN,IAAI,EAAE,mBAAmB;QAEzB,SAAS,CAAC,MAAM,EAAE,QAAQ;YACzB,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;YAClC,IAAI,CAAC,QAAQ,IAAI,CAAC,QAAQ,IAAI,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,KAAK,EAAE,CAAC;gBAChE,OAAO,IAAI,CAAC;YACb,CAAC;YAED,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC;YAC9D,MAAM,WAAW,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;YAEnC,KAAK,MAAM,GAAG,IAAI,WAAW,EAAE,CAAC;gBAC/B,MAAM,IAAI,GAAG,+BAA+B,CAAC,QAAQ,GAAG,GAAG,EAAE,QAAQ,CAAC,CAAC;gBACvE,IAAI,IAAI,EAAE,CAAC;oBACV,OAAO,IAAI,CAAC;gBACb,CAAC;YACF,CAAC;YAED,OAAO,IAAI,CAAC;QACb,CAAC;QAED,SAAS,CAAC,IAAI,EAAE,EAAE;YACjB,IAAI,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;gBACzB,+EAA+E;gBAC/E,OAAO;oBACN,IAAI;oBACJ,GAAG,EAAE,IAAI;iBACT,CAAC;YACH,CAAC;QACF,CAAC;KACD,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"resolver.js","sourceRoot":"","sources":["../../../../packages/vite/helpers/resolver.ts"],"names":[],"mappings":"AACA,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,+BAA+B,EAAE,MAAM,YAAY,CAAC;AAE7D,MAAM,mBAAmB,GAAG,CAAC,QAAgB,EAAU,EAAE;IACxD,MAAM,aAAa,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAEhD,IAAI,CAAC,aAAa,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QACxC,OAAO,aAAa,CAAC;IACtB,CAAC;IAED,OAAO,oBAAoB,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;AAC5H,CAAC,CAAC;AAEF,MAAM,CAAC,OAAO,UAAU,kBAAkB,CAAC,OAAqD;IAC/F,OAAO;QACN,IAAI,EAAE,mBAAmB;QACzB,OAAO,EAAE,KAAK;QAEd,SAAS,CAAC,MAAM,EAAE,QAAQ;YACzB,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;YAClC,IAAI,CAAC,QAAQ,IAAI,CAAC,QAAQ,IAAI,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,KAAK,EAAE,CAAC;gBAChE,OAAO,IAAI,CAAC;YACb,CAAC;YAED,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,mBAAmB,CAAC,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;YACnF,MAAM,WAAW,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;YAEnC,KAAK,MAAM,GAAG,IAAI,WAAW,EAAE,CAAC;gBAC/B,MAAM,IAAI,GAAG,+BAA+B,CAAC,QAAQ,GAAG,GAAG,EAAE,QAAQ,CAAC,CAAC;gBACvE,IAAI,IAAI,EAAE,CAAC;oBACV,OAAO,IAAI,CAAC;gBACb,CAAC;YACF,CAAC;YAED,OAAO,IAAI,CAAC;QACb,CAAC;QAED,SAAS,CAAC,IAAI,EAAE,EAAE;YACjB,IAAI,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;gBACzB,+EAA+E;gBAC/E,OAAO;oBACN,IAAI;oBACJ,GAAG,EAAE,IAAI;iBACT,CAAC;YACH,CAAC;QACF,CAAC;KACD,CAAC;AACH,CAAC"}
@@ -1717,6 +1717,104 @@ async function handleHmrMessage(ev) {
1717
1717
  return;
1718
1718
  }
1719
1719
  else {
1720
+ // Vite custom-event dispatch.
1721
+ //
1722
+ // `server.ws.send('event-name', payload)` from any Vite plugin lands
1723
+ // on the wire as `{ type: 'custom', event: 'event-name', data: payload }`.
1724
+ // On the web, Vite's stock client owns a `customListenersMap` that
1725
+ // fires every `import.meta.hot.on('event-name', cb)` callback. We
1726
+ // don't run Vite's stock client on device — the iOS runtime owns
1727
+ // the listener registry via `__NS_DISPATCH_HOT_EVENT__` (the
1728
+ // counterpart to `import.meta.hot.on` populated by user code +
1729
+ // compiled Angular components). Forwarding `type: 'custom'` here
1730
+ // is the only thing standing between server-emitted events and
1731
+ // the listeners they were meant for.
1732
+ //
1733
+ // `angular:component-update` is the canonical example. Analog's
1734
+ // plugin sends it on `.html` / component-style edits; the
1735
+ // compiled component `.mjs` registered a listener that
1736
+ // dynamic-imports `/@ng/component?c=<id>&t=<ts>` and calls
1737
+ // `ɵɵreplaceMetadata` on the live class — swapping the template
1738
+ // definition AND walking live `LView`s to recreate matching views
1739
+ // in-place. The page stays mounted and only the changed bits
1740
+ // re-render. We MUST `return` after dispatch so the reboot path
1741
+ // (`handleAngularHotUpdateMessage` → `__reboot_ng_modules__`)
1742
+ // never runs for these updates — that's the whole point of the
1743
+ // component-replacement pipeline.
1744
+ //
1745
+ // All other custom events are forwarded but NOT short-circuited
1746
+ // (Vite spec: custom events are additive — they don't replace
1747
+ // any framework-specific handling). The reboot path falls through
1748
+ // for `ns:angular-update` (the legacy/`.ts`-edit broadcast) and
1749
+ // for any framework not yet using the in-place replacement path.
1750
+ if (msg.type === 'custom' && typeof msg.event === 'string') {
1751
+ // Dispatch every Vite "custom" event through the runtime's
1752
+ // `__NS_DISPATCH_HOT_EVENT__` bridge so `import.meta.hot.on(event, cb)`
1753
+ // callbacks fire on the device. Critical contract: this is the
1754
+ // ONLY route by which Analog's `angular:component-update` reaches
1755
+ // the compiled component's `(d) => d.id === id && Component_HmrLoad(...)`
1756
+ // listener — without it, server-side broadcasts log green
1757
+ // (`(client) hmr update`) while the device sees nothing happen.
1758
+ //
1759
+ // Diagnostic policy: log "no dispatcher" loud (boot-time rt-bridge
1760
+ // failure), and listener exceptions loud (compiled HmrLoad
1761
+ // fetch/parse error). Successful dispatches are silent — the
1762
+ // runtime's `[import.meta.hot] dispatch summary` line carries
1763
+ // the per-event match-count diagnostic.
1764
+ try {
1765
+ const dispatch = globalThis.__NS_DISPATCH_HOT_EVENT__;
1766
+ if (typeof dispatch === 'function') {
1767
+ dispatch(msg.event, msg.data);
1768
+ }
1769
+ else {
1770
+ console.warn(`[hmr-client][custom] no __NS_DISPATCH_HOT_EVENT__ available for '${msg.event}'`);
1771
+ }
1772
+ }
1773
+ catch (err) {
1774
+ console.warn('[hmr-client][custom] dispatch threw for', msg.event, err);
1775
+ }
1776
+ if (msg.event === 'angular:component-update') {
1777
+ if (VERBOSE)
1778
+ console.log('[hmr-client][custom] dispatched angular:component-update — skipping reboot path');
1779
+ // Walk the apply-progress overlay through its
1780
+ // remaining stages for the in-place template-swap
1781
+ // path. The full reboot path
1782
+ // (`handleAngularHotUpdateMessage`) drives the
1783
+ // overlay itself ('received' → 'evicting' →
1784
+ // 'reimporting' → 'rebooting' → 'complete'); the
1785
+ // in-place path bypasses that handler entirely
1786
+ // because the work happens inside Angular's
1787
+ // `ɵɵreplaceMetadata` after the runtime forwards the
1788
+ // `angular:component-update` event to the compiled
1789
+ // component's listener. Without this update the
1790
+ // overlay would freeze at 5% ('received') even
1791
+ // though the visual swap completes a few frames
1792
+ // later — exactly the "Preparing update (5%)" stuck
1793
+ // frame we have been chasing.
1794
+ //
1795
+ // We transition straight to 'reimporting' to
1796
+ // communicate that metadata is being fetched (the
1797
+ // runtime listener fires `__ns_import('/@ng/component?c=...&t=...')`),
1798
+ // then schedule 'complete' on the next macrotask so
1799
+ // the auto-hide timer kicks in. The actual
1800
+ // template swap is fire-and-forget from this point;
1801
+ // the user sees the overlay close at the same time
1802
+ // as Angular re-renders the bound text/structure.
1803
+ try {
1804
+ const filePath = typeof msg.data?.id === 'string' ? decodeURIComponent(msg.data.id).split('@')[0] : undefined;
1805
+ const detail = filePath ? `Applying template update to ${filePath}` : 'Applying template update';
1806
+ setUpdateOverlayStage('reimporting', { detail });
1807
+ setTimeout(() => {
1808
+ try {
1809
+ setUpdateOverlayStage('complete', { detail: filePath ? `Updated ${filePath}` : 'Update applied' });
1810
+ }
1811
+ catch { }
1812
+ }, 16);
1813
+ }
1814
+ catch { }
1815
+ return;
1816
+ }
1817
+ }
1720
1818
  if (msg.type === 'ns:angular-update' && typeof msg.version === 'number') {
1721
1819
  setGraphVersion(Number(msg.version || getGraphVersion() || 0));
1722
1820
  }