@nativescript/vite 8.0.0-alpha.1 → 8.0.0-alpha.3

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 (145) hide show
  1. package/configuration/angular.d.ts +1 -1
  2. package/configuration/angular.js +323 -119
  3. package/configuration/angular.js.map +1 -1
  4. package/configuration/base.js +41 -24
  5. package/configuration/base.js.map +1 -1
  6. package/configuration/javascript.js +3 -3
  7. package/configuration/javascript.js.map +1 -1
  8. package/configuration/solid.js +7 -0
  9. package/configuration/solid.js.map +1 -1
  10. package/configuration/typescript.js +3 -3
  11. package/configuration/typescript.js.map +1 -1
  12. package/helpers/angular/angular-linker.js +39 -34
  13. package/helpers/angular/angular-linker.js.map +1 -1
  14. package/helpers/angular/inline-decorator-component-templates.d.ts +3 -0
  15. package/helpers/angular/inline-decorator-component-templates.js +400 -0
  16. package/helpers/angular/inline-decorator-component-templates.js.map +1 -0
  17. package/helpers/angular/shared-linker.d.ts +7 -0
  18. package/helpers/angular/shared-linker.js +37 -1
  19. package/helpers/angular/shared-linker.js.map +1 -1
  20. package/helpers/angular/synthesize-decorator-ctor-parameters.d.ts +1 -0
  21. package/helpers/angular/synthesize-decorator-ctor-parameters.js +256 -0
  22. package/helpers/angular/synthesize-decorator-ctor-parameters.js.map +1 -0
  23. package/helpers/angular/synthesize-injectable-factories.d.ts +3 -0
  24. package/helpers/angular/synthesize-injectable-factories.js +414 -0
  25. package/helpers/angular/synthesize-injectable-factories.js.map +1 -0
  26. package/helpers/commonjs-plugins.d.ts +5 -2
  27. package/helpers/commonjs-plugins.js +126 -0
  28. package/helpers/commonjs-plugins.js.map +1 -1
  29. package/helpers/esbuild-platform-resolver.js +5 -5
  30. package/helpers/esbuild-platform-resolver.js.map +1 -1
  31. package/helpers/external-configs.d.ts +9 -1
  32. package/helpers/external-configs.js +31 -6
  33. package/helpers/external-configs.js.map +1 -1
  34. package/helpers/import-meta-path.d.ts +4 -0
  35. package/helpers/import-meta-path.js +5 -0
  36. package/helpers/import-meta-path.js.map +1 -0
  37. package/helpers/import-specifier.d.ts +1 -0
  38. package/helpers/import-specifier.js +18 -0
  39. package/helpers/import-specifier.js.map +1 -0
  40. package/helpers/main-entry.d.ts +5 -2
  41. package/helpers/main-entry.js +112 -95
  42. package/helpers/main-entry.js.map +1 -1
  43. package/helpers/nativeclass-transform.js +8 -127
  44. package/helpers/nativeclass-transform.js.map +1 -1
  45. package/helpers/nativeclass-transformer-plugin.d.ts +12 -1
  46. package/helpers/nativeclass-transformer-plugin.js +175 -36
  47. package/helpers/nativeclass-transformer-plugin.js.map +1 -1
  48. package/hmr/client/css-handler.js +60 -20
  49. package/hmr/client/css-handler.js.map +1 -1
  50. package/hmr/client/index.js +524 -23
  51. package/hmr/client/index.js.map +1 -1
  52. package/hmr/client/utils.js +57 -6
  53. package/hmr/client/utils.js.map +1 -1
  54. package/hmr/entry-runtime.d.ts +10 -0
  55. package/hmr/entry-runtime.js +263 -21
  56. package/hmr/entry-runtime.js.map +1 -1
  57. package/hmr/frameworks/angular/client/index.d.ts +2 -1
  58. package/hmr/frameworks/angular/client/index.js +72 -19
  59. package/hmr/frameworks/angular/client/index.js.map +1 -1
  60. package/hmr/frameworks/angular/server/linker.js +36 -2
  61. package/hmr/frameworks/angular/server/linker.js.map +1 -1
  62. package/hmr/frameworks/angular/server/strategy.js +20 -5
  63. package/hmr/frameworks/angular/server/strategy.js.map +1 -1
  64. package/hmr/frameworks/typescript/server/strategy.js +8 -2
  65. package/hmr/frameworks/typescript/server/strategy.js.map +1 -1
  66. package/hmr/helpers/ast-normalizer.js +22 -10
  67. package/hmr/helpers/ast-normalizer.js.map +1 -1
  68. package/hmr/server/constants.d.ts +1 -0
  69. package/hmr/server/constants.js +2 -0
  70. package/hmr/server/constants.js.map +1 -1
  71. package/hmr/server/core-sanitize.d.ts +43 -0
  72. package/hmr/server/core-sanitize.js +219 -13
  73. package/hmr/server/core-sanitize.js.map +1 -1
  74. package/hmr/server/import-map.d.ts +65 -0
  75. package/hmr/server/import-map.js +219 -0
  76. package/hmr/server/import-map.js.map +1 -0
  77. package/hmr/server/index.d.ts +2 -1
  78. package/hmr/server/index.js.map +1 -1
  79. package/hmr/server/runtime-graph-filter.d.ts +5 -0
  80. package/hmr/server/runtime-graph-filter.js +21 -0
  81. package/hmr/server/runtime-graph-filter.js.map +1 -0
  82. package/hmr/server/shared-transform-request.d.ts +12 -0
  83. package/hmr/server/shared-transform-request.js +137 -0
  84. package/hmr/server/shared-transform-request.js.map +1 -0
  85. package/hmr/server/vite-plugin.d.ts +21 -1
  86. package/hmr/server/vite-plugin.js +443 -22
  87. package/hmr/server/vite-plugin.js.map +1 -1
  88. package/hmr/server/websocket-angular-entry.d.ts +2 -0
  89. package/hmr/server/websocket-angular-entry.js +68 -0
  90. package/hmr/server/websocket-angular-entry.js.map +1 -0
  91. package/hmr/server/websocket-angular-hot-update.d.ts +61 -0
  92. package/hmr/server/websocket-angular-hot-update.js +239 -0
  93. package/hmr/server/websocket-angular-hot-update.js.map +1 -0
  94. package/hmr/server/websocket-core-bridge.d.ts +23 -0
  95. package/hmr/server/websocket-core-bridge.js +360 -0
  96. package/hmr/server/websocket-core-bridge.js.map +1 -0
  97. package/hmr/server/websocket-graph-upsert.d.ts +6 -0
  98. package/hmr/server/websocket-graph-upsert.js +13 -0
  99. package/hmr/server/websocket-graph-upsert.js.map +1 -0
  100. package/hmr/server/websocket-module-bindings.d.ts +6 -0
  101. package/hmr/server/websocket-module-bindings.js +471 -0
  102. package/hmr/server/websocket-module-bindings.js.map +1 -0
  103. package/hmr/server/websocket-module-specifiers.d.ts +37 -0
  104. package/hmr/server/websocket-module-specifiers.js +637 -0
  105. package/hmr/server/websocket-module-specifiers.js.map +1 -0
  106. package/hmr/server/websocket.d.ts +26 -3
  107. package/hmr/server/websocket.js +1402 -678
  108. package/hmr/server/websocket.js.map +1 -1
  109. package/hmr/shared/package-classifier.d.ts +9 -0
  110. package/hmr/shared/package-classifier.js +58 -0
  111. package/hmr/shared/package-classifier.js.map +1 -0
  112. package/hmr/shared/runtime/browser-runtime-contract.d.ts +64 -0
  113. package/hmr/shared/runtime/browser-runtime-contract.js +54 -0
  114. package/hmr/shared/runtime/browser-runtime-contract.js.map +1 -0
  115. package/hmr/shared/runtime/dev-overlay.d.ts +38 -0
  116. package/hmr/shared/runtime/dev-overlay.js +675 -0
  117. package/hmr/shared/runtime/dev-overlay.js.map +1 -0
  118. package/hmr/shared/runtime/http-only-boot.d.ts +1 -0
  119. package/hmr/shared/runtime/http-only-boot.js +53 -6
  120. package/hmr/shared/runtime/http-only-boot.js.map +1 -1
  121. package/hmr/shared/runtime/module-provenance.d.ts +1 -0
  122. package/hmr/shared/runtime/module-provenance.js +66 -0
  123. package/hmr/shared/runtime/module-provenance.js.map +1 -0
  124. package/hmr/shared/runtime/platform-polyfills.d.ts +26 -0
  125. package/hmr/shared/runtime/platform-polyfills.js +122 -0
  126. package/hmr/shared/runtime/platform-polyfills.js.map +1 -0
  127. package/hmr/shared/runtime/root-placeholder.d.ts +1 -0
  128. package/hmr/shared/runtime/root-placeholder.js +576 -76
  129. package/hmr/shared/runtime/root-placeholder.js.map +1 -1
  130. package/hmr/shared/runtime/session-bootstrap.d.ts +1 -0
  131. package/hmr/shared/runtime/session-bootstrap.js +146 -0
  132. package/hmr/shared/runtime/session-bootstrap.js.map +1 -0
  133. package/hmr/shared/runtime/vendor-bootstrap.js +51 -6
  134. package/hmr/shared/runtime/vendor-bootstrap.js.map +1 -1
  135. package/hmr/shared/vendor/manifest.d.ts +7 -0
  136. package/hmr/shared/vendor/manifest.js +363 -23
  137. package/hmr/shared/vendor/manifest.js.map +1 -1
  138. package/hmr/shared/vendor/registry.js +104 -7
  139. package/hmr/shared/vendor/registry.js.map +1 -1
  140. package/package.json +12 -2
  141. package/runtime/core-aliases-early.js +83 -32
  142. package/runtime/core-aliases-early.js.map +1 -1
  143. package/shims/solid-jsx-runtime.d.ts +7 -0
  144. package/shims/solid-jsx-runtime.js +17 -0
  145. package/shims/solid-jsx-runtime.js.map +1 -0
@@ -1,4 +1,4 @@
1
1
  import { type UserConfig } from 'vite';
2
2
  export declare const angularConfig: ({ mode }: {
3
- mode: any;
3
+ mode: string;
4
4
  }) => UserConfig;
@@ -4,14 +4,40 @@ import fs from 'node:fs';
4
4
  import { createRequire } from 'node:module';
5
5
  import angular from '@analogjs/vite-plugin-angular';
6
6
  import { angularLinkerVitePlugin, angularLinkerVitePluginPost } from '../helpers/angular/angular-linker.js';
7
- import { ensureSharedAngularLinker } from '../helpers/angular/shared-linker.js';
7
+ import { synthesizeMissingInjectableFactories } from '../helpers/angular/synthesize-injectable-factories.js';
8
+ import { ensureSharedAngularLinker, resolveAngularFileSystem } from '../helpers/angular/shared-linker.js';
9
+ import { inlineDecoratorComponentTemplates } from '../helpers/angular/inline-decorator-component-templates.js';
10
+ import { synthesizeDecoratorCtorParameters } from '../helpers/angular/synthesize-decorator-ctor-parameters.js';
8
11
  import { containsRealNgDeclare } from '../helpers/angular/util.js';
9
12
  import { baseConfig } from './base.js';
10
13
  import { getCliFlags } from '../helpers/cli-flags.js';
14
+ import { resolveRelativeToImportMeta } from '../helpers/import-meta-path.js';
15
+ // Lazily import the Angular linker factory function. Used by chunk-level linkers
16
+ // to create FRESH plugin instances per invocation (avoiding stale state in watch mode).
17
+ let _cachedLinkerFactory = null;
18
+ async function importLinkerFactory() {
19
+ if (_cachedLinkerFactory)
20
+ return _cachedLinkerFactory;
21
+ const req = createRequire(process.cwd() + '/package.json');
22
+ try {
23
+ const linkerPath = req.resolve('@angular/compiler-cli/linker/babel');
24
+ const linkerMod = await import(linkerPath);
25
+ _cachedLinkerFactory = linkerMod.createLinkerPlugin || linkerMod.createEs2015LinkerPlugin || null;
26
+ }
27
+ catch {
28
+ try {
29
+ const linkerMod = await import('@angular/compiler-cli/linker/babel');
30
+ _cachedLinkerFactory = linkerMod.createLinkerPlugin || linkerMod.createEs2015LinkerPlugin || null;
31
+ }
32
+ catch { }
33
+ }
34
+ return _cachedLinkerFactory;
35
+ }
11
36
  // Rollup-level linker to guarantee Angular libraries are linked when included in the bundle graph.
12
37
  function angularRollupLinker(projectRoot) {
13
38
  let babel = null;
14
39
  let createLinker = null;
40
+ let angularFileSystem = null;
15
41
  const FILTER = /node_modules\/(?:@angular|@nativescript\/angular)\/.*\.[mc]?js$/;
16
42
  async function ensureDeps() {
17
43
  if (babel && createLinker)
@@ -35,6 +61,9 @@ function angularRollupLinker(projectRoot) {
35
61
  }
36
62
  catch { }
37
63
  }
64
+ if (!angularFileSystem) {
65
+ angularFileSystem = await resolveAngularFileSystem(projectRoot);
66
+ }
38
67
  }
39
68
  return {
40
69
  name: 'ns-angular-linker-rollup',
@@ -56,7 +85,7 @@ function angularRollupLinker(projectRoot) {
56
85
  return null;
57
86
  if (!forceLink && code.indexOf('\u0275\u0275ngDeclare') === -1 && code.indexOf('ɵɵngDeclare') === -1 && code.indexOf('ngDeclare') === -1)
58
87
  return null;
59
- const plugin = createLinker({ sourceMapping: false });
88
+ const plugin = createLinker({ sourceMapping: false, fileSystem: angularFileSystem });
60
89
  if (debug) {
61
90
  try {
62
91
  console.log('[ns-angular-linker][rollup-load] linking', cleanId);
@@ -92,7 +121,7 @@ function angularRollupLinker(projectRoot) {
92
121
  if (!babel || !createLinker)
93
122
  return null;
94
123
  try {
95
- const plugin = createLinker({ sourceMapping: false });
124
+ const plugin = createLinker({ sourceMapping: false, fileSystem: angularFileSystem });
96
125
  if (debug) {
97
126
  try {
98
127
  console.log('[ns-angular-linker][rollup] linking', cleanId);
@@ -126,76 +155,212 @@ let tsConfig = tsConfigAppPath;
126
155
  if (!fs.existsSync(tsConfigAppPath) && fs.existsSync(tsConfigPath)) {
127
156
  tsConfig = tsConfigPath;
128
157
  }
129
- const plugins = [
130
- // Allow external html template changes to trigger hot reload: Make .ts files depend on their .html templates
131
- {
132
- name: 'angular-template-deps',
133
- transform(code, id) {
134
- // For .ts files that reference templateUrl, add the .html file as a dependency
135
- if (id.endsWith('.ts') && code.includes('templateUrl')) {
136
- const templateUrlMatch = code.match(/templateUrl:\s*['"]\.\/(.*?\.html)['"]/);
137
- if (templateUrlMatch) {
138
- const htmlPath = path.resolve(path.dirname(id), templateUrlMatch[1]);
139
- // Add the HTML file as a dependency so Vite watches it
140
- this.addWatchFile(htmlPath);
141
- }
158
+ function normalizeAngularWatchPath(filePath) {
159
+ return filePath
160
+ .split('?', 1)[0]
161
+ .replace(/\\/g, '/')
162
+ .replace(/^file:\/\//, '');
163
+ }
164
+ function normalizeAngularWatchKey(filePath) {
165
+ const normalizedPath = normalizeAngularWatchPath(filePath);
166
+ const fileSystemPath = normalizedPath.startsWith('/@fs/') ? normalizedPath.slice('/@fs'.length) : normalizedPath;
167
+ const normalizedProjectRoot = projectRoot.replace(/\\/g, '/').replace(/\/$/, '');
168
+ if (normalizedProjectRoot && fileSystemPath.startsWith(normalizedProjectRoot)) {
169
+ const relative = fileSystemPath.slice(normalizedProjectRoot.length);
170
+ return relative.startsWith('/') ? relative : `/${relative}`;
171
+ }
172
+ return fileSystemPath;
173
+ }
174
+ function getAngularWatchKeys(filePath) {
175
+ const normalizedPath = normalizeAngularWatchPath(filePath);
176
+ const keys = new Set();
177
+ keys.add(normalizedPath);
178
+ keys.add(normalizeAngularWatchKey(normalizedPath));
179
+ return Array.from(keys).filter(Boolean);
180
+ }
181
+ function resolveAngularWatchFilePath(filePath) {
182
+ const normalizedPath = normalizeAngularWatchPath(filePath);
183
+ const fileSystemPath = normalizedPath.startsWith('/@fs/') ? normalizedPath.slice('/@fs'.length) : normalizedPath;
184
+ if (path.isAbsolute(fileSystemPath) && fs.existsSync(fileSystemPath)) {
185
+ return fileSystemPath;
186
+ }
187
+ if (fileSystemPath.startsWith('/')) {
188
+ return path.resolve(projectRoot, `.${fileSystemPath}`);
189
+ }
190
+ return path.resolve(projectRoot, fileSystemPath);
191
+ }
192
+ function extractComponentAssetPaths(code, componentId) {
193
+ const componentPath = normalizeAngularWatchPath(componentId);
194
+ const assetPaths = new Set();
195
+ const resolveAssetPath = (assetPath) => normalizeAngularWatchPath(path.resolve(path.dirname(componentPath), assetPath));
196
+ const templateUrlMatch = code.match(/templateUrl\s*:\s*['"](.+?\.(?:html|htm))['"]/);
197
+ if (templateUrlMatch) {
198
+ assetPaths.add(resolveAssetPath(templateUrlMatch[1]));
199
+ }
200
+ const styleUrlMatch = code.match(/styleUrl\s*:\s*['"](.+?\.(?:css|less|sass|scss))['"]/);
201
+ if (styleUrlMatch) {
202
+ assetPaths.add(resolveAssetPath(styleUrlMatch[1]));
203
+ }
204
+ const styleUrlsMatch = code.match(/styleUrls\s*:\s*\[([\s\S]*?)\]/m);
205
+ if (styleUrlsMatch) {
206
+ for (const match of styleUrlsMatch[1].matchAll(/['"](.+?\.(?:css|less|sass|scss))['"]/g)) {
207
+ assetPaths.add(resolveAssetPath(match[1]));
208
+ }
209
+ }
210
+ return Array.from(assetPaths);
211
+ }
212
+ function createAngularPlugins(opts) {
213
+ const assetToComponents = new Map();
214
+ const componentToAssets = new Map();
215
+ const pendingComponentInvalidations = new Set();
216
+ const untrackComponentAssets = (componentPath) => {
217
+ const previousAssets = componentToAssets.get(componentPath);
218
+ if (!previousAssets)
219
+ return;
220
+ for (const assetPath of previousAssets) {
221
+ const components = assetToComponents.get(assetPath);
222
+ if (!components)
223
+ continue;
224
+ components.delete(componentPath);
225
+ if (components.size === 0) {
226
+ assetToComponents.delete(assetPath);
142
227
  }
143
- return null;
228
+ }
229
+ componentToAssets.delete(componentPath);
230
+ };
231
+ const trackComponentAssets = (componentPath, assetPaths) => {
232
+ untrackComponentAssets(componentPath);
233
+ if (assetPaths.length === 0)
234
+ return;
235
+ const normalizedAssets = new Set(assetPaths.flatMap((assetPath) => getAngularWatchKeys(assetPath)));
236
+ componentToAssets.set(componentPath, normalizedAssets);
237
+ for (const assetPath of normalizedAssets) {
238
+ const components = assetToComponents.get(assetPath) || new Set();
239
+ components.add(componentPath);
240
+ assetToComponents.set(assetPath, components);
241
+ }
242
+ };
243
+ return [
244
+ // Allow external html template changes to trigger hot reload: Make .ts files depend on their .html templates
245
+ {
246
+ name: 'angular-template-deps',
247
+ enforce: 'pre',
248
+ transform(code, id) {
249
+ const componentPath = normalizeAngularWatchPath(id);
250
+ const componentKey = normalizeAngularWatchKey(id);
251
+ if (!componentKey.endsWith('.ts'))
252
+ return null;
253
+ const assetPaths = extractComponentAssetPaths(code, componentPath);
254
+ trackComponentAssets(componentKey, assetPaths);
255
+ for (const assetPath of assetPaths) {
256
+ this.addWatchFile(assetPath);
257
+ }
258
+ return null;
259
+ },
260
+ watchChange(id) {
261
+ const changedPath = normalizeAngularWatchPath(id);
262
+ const components = new Set();
263
+ for (const assetKey of getAngularWatchKeys(changedPath)) {
264
+ for (const componentPath of assetToComponents.get(assetKey) || []) {
265
+ components.add(componentPath);
266
+ }
267
+ }
268
+ if (components?.size) {
269
+ for (const componentPath of components) {
270
+ pendingComponentInvalidations.add(componentPath);
271
+ }
272
+ return;
273
+ }
274
+ if (/\.(html|htm)$/i.test(changedPath)) {
275
+ const componentPath = changedPath.replace(/\.(html|htm)$/i, '.ts');
276
+ if (fs.existsSync(resolveAngularWatchFilePath(componentPath))) {
277
+ pendingComponentInvalidations.add(normalizeAngularWatchKey(componentPath));
278
+ }
279
+ }
280
+ },
281
+ shouldTransformCachedModule({ id }) {
282
+ const componentPath = normalizeAngularWatchKey(id);
283
+ if (!pendingComponentInvalidations.has(componentPath))
284
+ return null;
285
+ pendingComponentInvalidations.delete(componentPath);
286
+ return true;
287
+ },
144
288
  },
145
- },
146
- // Transform Angular partial declarations in node_modules to avoid runtime JIT
147
- // Pass the project root so linker deps resolve from the app, not the plugin package.
148
- angularLinkerVitePlugin(process.cwd()),
149
- // Simplify: rely on Vite pre plugin (load/transform) for linking; Rollup safety net disabled unless re-enabled later
150
- // angularRollupLinker(process.cwd()),
151
- angular({
152
- liveReload: false, // Disable live reload in favor of HMR
153
- tsconfig: tsConfig,
154
- }),
155
- // Post-phase linker to catch any declarations introduced after other transforms (including project code)
156
- angularLinkerVitePluginPost(process.cwd()),
157
- // Enforce: fully disable dependency optimization during serve to avoid rxjs esm5 crawling and OOM
158
- {
159
- name: 'ns-disable-optimize-deps',
160
- enforce: 'post',
161
- apply: 'serve',
162
- config(userConfig) {
163
- const od = userConfig?.optimizeDeps || {};
164
- const prevExclude = Array.isArray(od.exclude) ? od.exclude : [];
165
- const exclude = new Set(prevExclude);
166
- ['@nativescript/core', 'rxjs', '@valor/nativescript-websockets', 'set-value', 'react', 'react-reconciler', 'react-nativescript'].forEach((x) => exclude.add(x));
167
- return {
168
- optimizeDeps: {
169
- noDiscovery: true,
170
- entries: [],
171
- include: [],
172
- exclude: Array.from(exclude),
173
- rolldownOptions: {
174
- ...(od.rolldownOptions || {}),
175
- plugins: [],
289
+ // Transform Angular partial declarations in node_modules to avoid runtime JIT
290
+ // Pass the project root so linker deps resolve from the app, not the plugin package.
291
+ angularLinkerVitePlugin(process.cwd()),
292
+ // Simplify: rely on Vite pre plugin (load/transform) for linking; Rollup safety net disabled unless re-enabled later
293
+ // angularRollupLinker(process.cwd()),
294
+ ...angular({
295
+ experimental: {
296
+ useAngularCompilationAPI: opts.useAngularCompilationAPI,
297
+ },
298
+ liveReload: false, // Disable live reload in favor of HMR
299
+ tsconfig: tsConfig,
300
+ }),
301
+ // Post-phase linker to catch any declarations introduced after other transforms (including project code)
302
+ angularLinkerVitePluginPost(process.cwd()),
303
+ // Enforce: fully disable dependency optimization during serve to avoid rxjs esm5 crawling and OOM
304
+ {
305
+ name: 'ns-disable-optimize-deps',
306
+ enforce: 'post',
307
+ apply: 'serve',
308
+ config(userConfig) {
309
+ const od = userConfig?.optimizeDeps || {};
310
+ const prevExclude = Array.isArray(od.exclude) ? od.exclude : [];
311
+ const exclude = new Set(prevExclude);
312
+ ['@nativescript/core', 'rxjs', '@valor/nativescript-websockets', 'set-value', 'react', 'react-reconciler', 'react-nativescript'].forEach((x) => exclude.add(x));
313
+ return {
314
+ optimizeDeps: {
315
+ noDiscovery: true,
316
+ entries: [],
317
+ include: [],
318
+ exclude: Array.from(exclude),
319
+ rolldownOptions: {
320
+ ...(od.rolldownOptions || {}),
321
+ plugins: [],
322
+ },
176
323
  },
177
- },
178
- };
179
- },
180
- configResolved(resolved) {
181
- const deps = (resolved.optimizeDeps || (resolved.optimizeDeps = {}));
182
- deps.noDiscovery = true;
183
- deps.entries = [];
184
- deps.include = [];
185
- const exclude = new Set(Array.isArray(deps.exclude) ? deps.exclude : []);
186
- ['@nativescript/core', 'rxjs', '@valor/nativescript-websockets', 'set-value', 'react', 'react-reconciler', 'react-nativescript'].forEach((x) => exclude.add(x));
187
- deps.exclude = Array.from(exclude);
188
- const rolldownOptions = (deps.rolldownOptions || (deps.rolldownOptions = {}));
189
- rolldownOptions.plugins = [];
324
+ };
325
+ },
326
+ configResolved(resolved) {
327
+ const resolvedConfig = resolved;
328
+ const deps = (resolvedConfig.optimizeDeps || (resolvedConfig.optimizeDeps = {}));
329
+ deps.noDiscovery = true;
330
+ deps.entries = [];
331
+ deps.include = [];
332
+ const exclude = new Set(Array.isArray(deps.exclude) ? deps.exclude : []);
333
+ ['@nativescript/core', 'rxjs', '@valor/nativescript-websockets', 'set-value', 'react', 'react-reconciler', 'react-nativescript'].forEach((x) => exclude.add(x));
334
+ deps.exclude = Array.from(exclude);
335
+ const rolldownOptions = (deps.rolldownOptions || (deps.rolldownOptions = {}));
336
+ rolldownOptions.plugins = [];
337
+ },
190
338
  },
191
- },
192
- ];
339
+ ];
340
+ }
193
341
  export const angularConfig = ({ mode }) => {
342
+ const useSingleBundleDevOutput = mode === 'development' && !hmrActive;
343
+ const plugins = createAngularPlugins({
344
+ // Vite build --watch with the legacy Analog compilation path can regress
345
+ // Angular app sources from Ivy output back to decorator emit on rebuild.
346
+ // Restrict the newer compilation API to NativeScript's development no-HMR
347
+ // flow, which is where the unstable rebuilds occur today.
348
+ useAngularCompilationAPI: useSingleBundleDevOutput,
349
+ });
194
350
  const disableAnimations = true;
195
351
  //process.env.NS_DISABLE_NG_ANIMATIONS === "1" ||
196
352
  //process.env.NS_DISABLE_NG_ANIMATIONS === "true";
197
353
  // Post-link emitted chunks to catch any remaining partial declarations that slipped through
198
354
  // due to plugin order or external transforms.
355
+ const applyAngularChunkPostProcessing = (code, options = {}) => {
356
+ const codeWithInjectables = synthesizeMissingInjectableFactories(code, {
357
+ vendorInjectExport: options.vendorInjectExport,
358
+ });
359
+ const codeWithCtorParameters = synthesizeDecoratorCtorParameters(codeWithInjectables);
360
+ return inlineDecoratorComponentTemplates(codeWithCtorParameters, {
361
+ projectRoot: process.cwd(),
362
+ });
363
+ };
199
364
  const postLinker = {
200
365
  name: 'ns-angular-linker-post',
201
366
  apply: 'build',
@@ -206,13 +371,22 @@ export const angularConfig = ({ mode }) => {
206
371
  return false;
207
372
  return Object.keys(chunk.modules).some((m) => m.includes('node_modules/@nativescript/angular/fesm2022/nativescript-angular-polyfills.mjs'));
208
373
  }
209
- const { babel, linkerPlugin } = await ensureSharedAngularLinker(process.cwd());
210
- if (!babel || !linkerPlugin)
374
+ const { babel } = await ensureSharedAngularLinker(process.cwd());
375
+ if (!babel)
376
+ return;
377
+ const fileSystem = await resolveAngularFileSystem(process.cwd());
378
+ const linkerFactory = await importLinkerFactory();
379
+ if (!linkerFactory)
211
380
  return;
212
381
  const strict = process.env.NS_STRICT_NG_LINK === '1' || process.env.NS_STRICT_NG_LINK === 'true';
213
382
  const enforceStrict = process.env.NS_STRICT_NG_LINK_ENFORCE === '1' || process.env.NS_STRICT_NG_LINK_ENFORCE === 'true';
214
383
  const debug = process.env.VITE_DEBUG_LOGS === '1' || process.env.VITE_DEBUG_LOGS === 'true';
215
384
  const unlinked = [];
385
+ const vendorInjectExport = (() => {
386
+ const vendorChunk = Object.entries(bundle).find(([name, value]) => value && value.type === 'chunk' && /(^|\/)vendor\.mjs$/.test(name));
387
+ const vendorCode = vendorChunk ? vendorChunk[1].code : undefined;
388
+ return vendorCode?.match(/\binject as ([A-Za-z_$][\w$]*)/)?.[1];
389
+ })();
216
390
  for (const [fileName, chunk] of Object.entries(bundle)) {
217
391
  if (!fileName.endsWith('.mjs') && !fileName.endsWith('.js'))
218
392
  continue;
@@ -222,15 +396,19 @@ export const angularConfig = ({ mode }) => {
222
396
  continue;
223
397
  const isNsPolyfills = isNsAngularPolyfillsChunk(chunk);
224
398
  try {
399
+ // Create a FRESH linker plugin per chunk — the linker may have
400
+ // internal state that becomes stale across watch-mode rebuild cycles.
401
+ const freshPlugin = linkerFactory({ sourceMapping: false, fileSystem });
225
402
  const res = await babel.transformAsync(code, {
226
403
  filename: fileName,
227
404
  configFile: false,
228
405
  babelrc: false,
229
406
  sourceMaps: false,
230
407
  compact: false,
231
- plugins: [linkerPlugin],
408
+ plugins: [freshPlugin],
232
409
  });
233
- const finalCode = res?.code && res.code !== code ? res.code : code;
410
+ const linkedCode = res?.code && res.code !== code ? res.code : code;
411
+ const finalCode = applyAngularChunkPostProcessing(linkedCode, { vendorInjectExport });
234
412
  if (finalCode !== code) {
235
413
  chunk.code = finalCode;
236
414
  if (debug) {
@@ -244,7 +422,8 @@ export const angularConfig = ({ mode }) => {
244
422
  unlinked.push(fileName);
245
423
  }
246
424
  }
247
- catch {
425
+ catch (e) {
426
+ console.warn(`[ns-angular-linker][post] linking FAILED for ${fileName}:`, e?.message || e);
248
427
  if (strict)
249
428
  unlinked.push(fileName);
250
429
  }
@@ -290,37 +469,46 @@ export const angularConfig = ({ mode }) => {
290
469
  }
291
470
  },
292
471
  };
293
- // Safety net: transform each rendered chunk to link any remaining ɵɵngDeclare* call sites
472
+ // Safety net: transform each rendered chunk to link any remaining ɵɵngDeclare* call sites.
473
+ // IMPORTANT: create a FRESH linker plugin per invocation — the shared instance may have
474
+ // stale internal state from a prior build cycle, causing silent failures in watch-mode rebuilds.
294
475
  const renderChunkLinker = {
295
476
  name: 'ns-angular-linker-render',
296
477
  apply: 'build',
297
478
  enforce: 'post',
298
479
  async renderChunk(code, chunk) {
480
+ if (!code)
481
+ return null;
482
+ const filename = chunk.fileName || chunk.name || 'chunk.mjs';
483
+ const debug = process.env.VITE_DEBUG_LOGS === '1' || process.env.VITE_DEBUG_LOGS === 'true';
299
484
  try {
300
- if (!code)
301
- return null;
302
- if (!containsRealNgDeclare(code))
303
- return null;
304
- const { babel, linkerPlugin } = await ensureSharedAngularLinker(process.cwd());
305
- if (!babel || !linkerPlugin)
306
- return null;
307
- const filename = chunk.fileName || chunk.name || 'chunk.mjs';
308
- const debug = process.env.VITE_DEBUG_LOGS === '1' || process.env.VITE_DEBUG_LOGS === 'true';
309
- const runLink = async (input) => {
310
- const result = await babel.transformAsync(input, {
311
- filename,
312
- configFile: false,
313
- babelrc: false,
314
- sourceMaps: false,
315
- compact: false,
316
- plugins: [linkerPlugin],
317
- });
318
- return result?.code ?? input;
319
- };
320
- let transformed = await runLink(code);
321
- if (containsRealNgDeclare(transformed)) {
322
- transformed = await runLink(transformed);
485
+ let transformed = code;
486
+ if (containsRealNgDeclare(code)) {
487
+ const { babel } = await ensureSharedAngularLinker(process.cwd());
488
+ if (!babel)
489
+ return null;
490
+ const fileSystem = await resolveAngularFileSystem(process.cwd());
491
+ // Fresh plugin per chunk — avoids stale linker state across watch-mode rebuilds
492
+ const freshPlugin = (await importLinkerFactory())?.({ sourceMapping: false, fileSystem });
493
+ if (!freshPlugin)
494
+ return null;
495
+ const runLink = async (input) => {
496
+ const result = await babel.transformAsync(input, {
497
+ filename,
498
+ configFile: false,
499
+ babelrc: false,
500
+ sourceMaps: false,
501
+ compact: false,
502
+ plugins: [freshPlugin],
503
+ });
504
+ return result?.code ?? input;
505
+ };
506
+ transformed = await runLink(code);
507
+ if (containsRealNgDeclare(transformed)) {
508
+ transformed = await runLink(transformed);
509
+ }
323
510
  }
511
+ transformed = applyAngularChunkPostProcessing(transformed);
324
512
  if (transformed !== code) {
325
513
  if (debug) {
326
514
  try {
@@ -331,40 +519,42 @@ export const angularConfig = ({ mode }) => {
331
519
  return { code: transformed, map: null };
332
520
  }
333
521
  }
334
- catch { }
522
+ catch (e) {
523
+ console.warn(`[ns-angular-linker][render] linking FAILED for ${filename}:`, e?.message || e);
524
+ }
335
525
  return null;
336
526
  },
337
527
  };
338
528
  const enableRollupLinker = process.env.NS_ENABLE_ROLLUP_LINKER === '1' || process.env.NS_ENABLE_ROLLUP_LINKER === 'true' || hmrActive;
339
- return mergeConfig(baseConfig({ mode, flavor: 'angular' }), {
529
+ // Build a single merged alias array to avoid property override conflicts.
530
+ // Previously the disableAnimations spread added a second `resolve` key
531
+ // that silently clobbered the fesm2022 and RxJS aliases.
532
+ const angularAliases = [
533
+ // Map Angular deep ESM paths to bare package ids
534
+ { find: /^@angular\/([^/]+)\/fesm2022\/.*\.mjs$/, replacement: '@angular/$1' },
535
+ { find: /^@nativescript\/angular\/fesm2022\/.*\.mjs$/, replacement: '@nativescript/angular' },
536
+ // RxJS esm5 → esm redirects removed: Vite 8 enforces the rxjs `exports` field,
537
+ // blocking deep path aliases. Instead, the `es2015` resolve condition is added
538
+ // below so rxjs resolves to its modern ESM builds via the exports map.
539
+ ];
540
+ if (disableAnimations) {
541
+ angularAliases.push({
542
+ find: /^@angular\/animations(\/.+)?$/, // match subpaths too
543
+ replacement: resolveRelativeToImportMeta(import.meta.url, '../shims/angular-animations-stub.js'),
544
+ }, {
545
+ find: /^@angular\/platform-browser\/animations(\/.+)?$/,
546
+ replacement: resolveRelativeToImportMeta(import.meta.url, '../shims/angular-animations-stub.js'),
547
+ });
548
+ }
549
+ const config = mergeConfig(baseConfig({ mode, flavor: 'angular' }), {
340
550
  plugins: [...plugins, ...(enableRollupLinker ? [angularRollupLinker(process.cwd())] : []), renderChunkLinker, postLinker],
341
- // Always alias fesm2022 deep imports to package root so vendor bridge can externalize properly
342
551
  resolve: {
343
- alias: [
344
- // Map Angular deep ESM paths to bare package ids
345
- { find: /^@angular\/([^/]+)\/fesm2022\/.*\.mjs$/, replacement: '@angular/$1' },
346
- { find: /^@nativescript\/angular\/fesm2022\/.*\.mjs$/, replacement: '@nativescript/angular' },
347
- // Prefer modern RxJS builds; avoid esm5 which explodes module count and memory
348
- { find: /^rxjs\/dist\/esm5\/(.*)$/, replacement: 'rxjs/dist/esm2015/$1' },
349
- { find: /^rxjs\/operators$/, replacement: 'rxjs/dist/esm2015/operators/index.js' },
350
- { find: /^rxjs$/, replacement: 'rxjs/dist/esm2015/index.js' },
351
- // Existing optional animations shims
352
- ],
552
+ alias: angularAliases,
553
+ // Add 'es2015' condition so RxJS resolves to dist/esm (modern ESM) rather
554
+ // than dist/esm5 via the 'default' condition. This avoids the esm5 module
555
+ // explosion and OOM while respecting the package's exports field in Vite 8.
556
+ conditions: ['es2015'],
353
557
  },
354
- ...(disableAnimations && {
355
- resolve: {
356
- alias: [
357
- {
358
- find: /^@angular\/animations(\/.+)?$/, // match subpaths too
359
- replacement: new URL('../shims/angular-animations-stub.js', import.meta.url).pathname,
360
- },
361
- {
362
- find: /^@angular\/platform-browser\/animations(\/.+)?$/,
363
- replacement: new URL('../shims/angular-animations-stub.js', import.meta.url).pathname,
364
- },
365
- ],
366
- },
367
- }),
368
558
  // Disable dependency optimization entirely for NativeScript Angular HMR.
369
559
  // Vite 5.1+: use noDiscovery with an empty include list (disabled was removed).
370
560
  // The HTTP loader + vendor bridge manage dependencies; pre-bundling can OOM.
@@ -376,5 +566,19 @@ export const angularConfig = ({ mode }) => {
376
566
  rolldownOptions: { plugins: [] },
377
567
  },
378
568
  });
569
+ if (useSingleBundleDevOutput) {
570
+ const build = (config.build ?? (config.build = {}));
571
+ const rolldownOptions = (build.rolldownOptions ?? (build.rolldownOptions = {}));
572
+ const outputConfigs = Array.isArray(rolldownOptions.output) ? rolldownOptions.output : [rolldownOptions.output ?? {}];
573
+ for (const output of outputConfigs) {
574
+ // Angular non-HMR reloads are more reliable when rebuilds keep a single boot bundle.
575
+ // This avoids watch-time chunk alias/name drift that can leave the native app reloading into stale split points.
576
+ delete output.manualChunks;
577
+ delete output.chunkFileNames;
578
+ output.codeSplitting = false;
579
+ }
580
+ rolldownOptions.output = Array.isArray(rolldownOptions.output) ? outputConfigs : outputConfigs[0];
581
+ }
582
+ return config;
379
583
  };
380
584
  //# sourceMappingURL=angular.js.map