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

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 (220) hide show
  1. package/configuration/angular.d.ts +1 -1
  2. package/configuration/angular.js +486 -140
  3. package/configuration/angular.js.map +1 -1
  4. package/configuration/base.js +159 -29
  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 +4 -4
  11. package/configuration/typescript.js.map +1 -1
  12. package/helpers/angular/angular-linker.js +38 -42
  13. package/helpers/angular/angular-linker.js.map +1 -1
  14. package/helpers/angular/inject-component-hmr-registration.d.ts +112 -0
  15. package/helpers/angular/inject-component-hmr-registration.js +359 -0
  16. package/helpers/angular/inject-component-hmr-registration.js.map +1 -0
  17. package/helpers/angular/inline-decorator-component-templates.d.ts +3 -0
  18. package/helpers/angular/inline-decorator-component-templates.js +400 -0
  19. package/helpers/angular/inline-decorator-component-templates.js.map +1 -0
  20. package/helpers/angular/shared-linker.d.ts +7 -0
  21. package/helpers/angular/shared-linker.js +37 -1
  22. package/helpers/angular/shared-linker.js.map +1 -1
  23. package/helpers/angular/synthesize-decorator-ctor-parameters.d.ts +1 -0
  24. package/helpers/angular/synthesize-decorator-ctor-parameters.js +256 -0
  25. package/helpers/angular/synthesize-decorator-ctor-parameters.js.map +1 -0
  26. package/helpers/angular/synthesize-injectable-factories.d.ts +3 -0
  27. package/helpers/angular/synthesize-injectable-factories.js +414 -0
  28. package/helpers/angular/synthesize-injectable-factories.js.map +1 -0
  29. package/helpers/angular/util.d.ts +1 -0
  30. package/helpers/angular/util.js +88 -0
  31. package/helpers/angular/util.js.map +1 -1
  32. package/helpers/commonjs-plugins.d.ts +5 -2
  33. package/helpers/commonjs-plugins.js +126 -0
  34. package/helpers/commonjs-plugins.js.map +1 -1
  35. package/helpers/config-as-json.js +10 -0
  36. package/helpers/config-as-json.js.map +1 -1
  37. package/helpers/esbuild-platform-resolver.js +5 -5
  38. package/helpers/esbuild-platform-resolver.js.map +1 -1
  39. package/helpers/external-configs.d.ts +9 -1
  40. package/helpers/external-configs.js +31 -6
  41. package/helpers/external-configs.js.map +1 -1
  42. package/helpers/global-defines.d.ts +51 -0
  43. package/helpers/global-defines.js +77 -0
  44. package/helpers/global-defines.js.map +1 -1
  45. package/helpers/import-meta-path.d.ts +4 -0
  46. package/helpers/import-meta-path.js +5 -0
  47. package/helpers/import-meta-path.js.map +1 -0
  48. package/helpers/import-specifier.d.ts +1 -0
  49. package/helpers/import-specifier.js +18 -0
  50. package/helpers/import-specifier.js.map +1 -0
  51. package/helpers/logging.d.ts +1 -0
  52. package/helpers/logging.js +63 -3
  53. package/helpers/logging.js.map +1 -1
  54. package/helpers/main-entry.d.ts +5 -2
  55. package/helpers/main-entry.js +365 -116
  56. package/helpers/main-entry.js.map +1 -1
  57. package/helpers/nativeclass-transform.js +8 -127
  58. package/helpers/nativeclass-transform.js.map +1 -1
  59. package/helpers/nativeclass-transformer-plugin.d.ts +19 -1
  60. package/helpers/nativeclass-transformer-plugin.js +318 -36
  61. package/helpers/nativeclass-transformer-plugin.js.map +1 -1
  62. package/helpers/ns-core-url.d.ts +83 -0
  63. package/helpers/ns-core-url.js +167 -0
  64. package/helpers/ns-core-url.js.map +1 -0
  65. package/helpers/prelink-angular.js +1 -4
  66. package/helpers/prelink-angular.js.map +1 -1
  67. package/helpers/project.d.ts +35 -0
  68. package/helpers/project.js +120 -2
  69. package/helpers/project.js.map +1 -1
  70. package/helpers/ts-config-paths.js +50 -2
  71. package/helpers/ts-config-paths.js.map +1 -1
  72. package/helpers/workers.d.ts +20 -19
  73. package/helpers/workers.js +620 -3
  74. package/helpers/workers.js.map +1 -1
  75. package/hmr/client/css-handler.js +60 -19
  76. package/hmr/client/css-handler.js.map +1 -1
  77. package/hmr/client/hmr-pending-overlay.d.ts +27 -0
  78. package/hmr/client/hmr-pending-overlay.js +50 -0
  79. package/hmr/client/hmr-pending-overlay.js.map +1 -0
  80. package/hmr/client/index.js +597 -24
  81. package/hmr/client/index.js.map +1 -1
  82. package/hmr/client/utils.d.ts +5 -0
  83. package/hmr/client/utils.js +212 -21
  84. package/hmr/client/utils.js.map +1 -1
  85. package/hmr/entry-runtime.d.ts +10 -0
  86. package/hmr/entry-runtime.js +330 -42
  87. package/hmr/entry-runtime.js.map +1 -1
  88. package/hmr/frameworks/angular/client/index.d.ts +3 -1
  89. package/hmr/frameworks/angular/client/index.js +821 -25
  90. package/hmr/frameworks/angular/client/index.js.map +1 -1
  91. package/hmr/frameworks/angular/server/linker.js +37 -6
  92. package/hmr/frameworks/angular/server/linker.js.map +1 -1
  93. package/hmr/frameworks/angular/server/strategy.js +30 -6
  94. package/hmr/frameworks/angular/server/strategy.js.map +1 -1
  95. package/hmr/frameworks/typescript/server/strategy.js +8 -2
  96. package/hmr/frameworks/typescript/server/strategy.js.map +1 -1
  97. package/hmr/frameworks/vue/client/index.js +18 -42
  98. package/hmr/frameworks/vue/client/index.js.map +1 -1
  99. package/hmr/helpers/ast-normalizer.js +22 -10
  100. package/hmr/helpers/ast-normalizer.js.map +1 -1
  101. package/hmr/helpers/cjs-named-exports.d.ts +23 -0
  102. package/hmr/helpers/cjs-named-exports.js +152 -0
  103. package/hmr/helpers/cjs-named-exports.js.map +1 -0
  104. package/hmr/server/constants.d.ts +1 -0
  105. package/hmr/server/constants.js +14 -3
  106. package/hmr/server/constants.js.map +1 -1
  107. package/hmr/server/core-sanitize.d.ts +49 -2
  108. package/hmr/server/core-sanitize.js +267 -24
  109. package/hmr/server/core-sanitize.js.map +1 -1
  110. package/hmr/server/import-map.d.ts +65 -0
  111. package/hmr/server/import-map.js +222 -0
  112. package/hmr/server/import-map.js.map +1 -0
  113. package/hmr/server/index.d.ts +2 -1
  114. package/hmr/server/index.js.map +1 -1
  115. package/hmr/server/ns-core-cjs-shape.d.ts +204 -0
  116. package/hmr/server/ns-core-cjs-shape.js +271 -0
  117. package/hmr/server/ns-core-cjs-shape.js.map +1 -0
  118. package/hmr/server/perf-instrumentation.d.ts +114 -0
  119. package/hmr/server/perf-instrumentation.js +195 -0
  120. package/hmr/server/perf-instrumentation.js.map +1 -0
  121. package/hmr/server/runtime-graph-filter.d.ts +5 -0
  122. package/hmr/server/runtime-graph-filter.js +21 -0
  123. package/hmr/server/runtime-graph-filter.js.map +1 -0
  124. package/hmr/server/shared-transform-request.d.ts +12 -0
  125. package/hmr/server/shared-transform-request.js +144 -0
  126. package/hmr/server/shared-transform-request.js.map +1 -0
  127. package/hmr/server/vite-plugin.d.ts +21 -1
  128. package/hmr/server/vite-plugin.js +461 -22
  129. package/hmr/server/vite-plugin.js.map +1 -1
  130. package/hmr/server/websocket-angular-entry.d.ts +2 -0
  131. package/hmr/server/websocket-angular-entry.js +68 -0
  132. package/hmr/server/websocket-angular-entry.js.map +1 -0
  133. package/hmr/server/websocket-angular-hot-update.d.ts +78 -0
  134. package/hmr/server/websocket-angular-hot-update.js +413 -0
  135. package/hmr/server/websocket-angular-hot-update.js.map +1 -0
  136. package/hmr/server/websocket-core-bridge.d.ts +21 -0
  137. package/hmr/server/websocket-core-bridge.js +357 -0
  138. package/hmr/server/websocket-core-bridge.js.map +1 -0
  139. package/hmr/server/websocket-graph-upsert.d.ts +21 -0
  140. package/hmr/server/websocket-graph-upsert.js +33 -0
  141. package/hmr/server/websocket-graph-upsert.js.map +1 -0
  142. package/hmr/server/websocket-hmr-pending.d.ts +43 -0
  143. package/hmr/server/websocket-hmr-pending.js +55 -0
  144. package/hmr/server/websocket-hmr-pending.js.map +1 -0
  145. package/hmr/server/websocket-module-bindings.d.ts +6 -0
  146. package/hmr/server/websocket-module-bindings.js +471 -0
  147. package/hmr/server/websocket-module-bindings.js.map +1 -0
  148. package/hmr/server/websocket-module-specifiers.d.ts +101 -0
  149. package/hmr/server/websocket-module-specifiers.js +820 -0
  150. package/hmr/server/websocket-module-specifiers.js.map +1 -0
  151. package/hmr/server/websocket-ns-m-finalize.d.ts +22 -0
  152. package/hmr/server/websocket-ns-m-finalize.js +88 -0
  153. package/hmr/server/websocket-ns-m-finalize.js.map +1 -0
  154. package/hmr/server/websocket-ns-m-paths.d.ts +3 -0
  155. package/hmr/server/websocket-ns-m-paths.js +92 -0
  156. package/hmr/server/websocket-ns-m-paths.js.map +1 -0
  157. package/hmr/server/websocket-ns-m-request.d.ts +45 -0
  158. package/hmr/server/websocket-ns-m-request.js +196 -0
  159. package/hmr/server/websocket-ns-m-request.js.map +1 -0
  160. package/hmr/server/websocket-runtime-compat.d.ts +19 -0
  161. package/hmr/server/websocket-runtime-compat.js +287 -0
  162. package/hmr/server/websocket-runtime-compat.js.map +1 -0
  163. package/hmr/server/websocket-served-module-helpers.d.ts +36 -0
  164. package/hmr/server/websocket-served-module-helpers.js +631 -0
  165. package/hmr/server/websocket-served-module-helpers.js.map +1 -0
  166. package/hmr/server/websocket-txn.d.ts +6 -0
  167. package/hmr/server/websocket-txn.js +45 -0
  168. package/hmr/server/websocket-txn.js.map +1 -0
  169. package/hmr/server/websocket-vendor-unifier.d.ts +10 -0
  170. package/hmr/server/websocket-vendor-unifier.js +51 -0
  171. package/hmr/server/websocket-vendor-unifier.js.map +1 -0
  172. package/hmr/server/websocket-vue-sfc.d.ts +27 -0
  173. package/hmr/server/websocket-vue-sfc.js +1069 -0
  174. package/hmr/server/websocket-vue-sfc.js.map +1 -0
  175. package/hmr/server/websocket.d.ts +26 -3
  176. package/hmr/server/websocket.js +2233 -796
  177. package/hmr/server/websocket.js.map +1 -1
  178. package/hmr/shared/package-classifier.d.ts +9 -0
  179. package/hmr/shared/package-classifier.js +58 -0
  180. package/hmr/shared/package-classifier.js.map +1 -0
  181. package/hmr/shared/runtime/boot-timeline.d.ts +17 -0
  182. package/hmr/shared/runtime/boot-timeline.js +51 -0
  183. package/hmr/shared/runtime/boot-timeline.js.map +1 -0
  184. package/hmr/shared/runtime/browser-runtime-contract.d.ts +64 -0
  185. package/hmr/shared/runtime/browser-runtime-contract.js +54 -0
  186. package/hmr/shared/runtime/browser-runtime-contract.js.map +1 -0
  187. package/hmr/shared/runtime/dev-overlay.d.ts +85 -0
  188. package/hmr/shared/runtime/dev-overlay.js +1236 -0
  189. package/hmr/shared/runtime/dev-overlay.js.map +1 -0
  190. package/hmr/shared/runtime/http-only-boot.d.ts +1 -0
  191. package/hmr/shared/runtime/http-only-boot.js +53 -6
  192. package/hmr/shared/runtime/http-only-boot.js.map +1 -1
  193. package/hmr/shared/runtime/module-provenance.d.ts +1 -0
  194. package/hmr/shared/runtime/module-provenance.js +63 -0
  195. package/hmr/shared/runtime/module-provenance.js.map +1 -0
  196. package/hmr/shared/runtime/platform-polyfills.d.ts +26 -0
  197. package/hmr/shared/runtime/platform-polyfills.js +122 -0
  198. package/hmr/shared/runtime/platform-polyfills.js.map +1 -0
  199. package/hmr/shared/runtime/root-placeholder.d.ts +1 -0
  200. package/hmr/shared/runtime/root-placeholder.js +552 -82
  201. package/hmr/shared/runtime/root-placeholder.js.map +1 -1
  202. package/hmr/shared/runtime/session-bootstrap.d.ts +1 -0
  203. package/hmr/shared/runtime/session-bootstrap.js +195 -0
  204. package/hmr/shared/runtime/session-bootstrap.js.map +1 -0
  205. package/hmr/shared/runtime/vendor-bootstrap.js +52 -15
  206. package/hmr/shared/runtime/vendor-bootstrap.js.map +1 -1
  207. package/hmr/shared/vendor/manifest.d.ts +37 -0
  208. package/hmr/shared/vendor/manifest.js +677 -57
  209. package/hmr/shared/vendor/manifest.js.map +1 -1
  210. package/hmr/shared/vendor/registry.js +104 -7
  211. package/hmr/shared/vendor/registry.js.map +1 -1
  212. package/index.d.ts +1 -0
  213. package/index.js +5 -0
  214. package/index.js.map +1 -1
  215. package/package.json +14 -2
  216. package/runtime/core-aliases-early.js +94 -67
  217. package/runtime/core-aliases-early.js.map +1 -1
  218. package/shims/solid-jsx-runtime.d.ts +7 -0
  219. package/shims/solid-jsx-runtime.js +17 -0
  220. package/shims/solid-jsx-runtime.js.map +1 -0
@@ -1,7 +1,60 @@
1
1
  import path from 'path';
2
+ import { createRequire } from 'node:module';
2
3
  import { nsConfigToJson, resolveNativeScriptPlatformFile } from './utils.js';
3
- export function getWorkerPlugins(platform) {
4
- return [
4
+ import { createTsConfigPathsResolver, getTsConfigData } from './ts-config-paths.js';
5
+ import { packagePlatformResolverPlugin } from './package-platform-aliases.js';
6
+ import { nativescriptPackageResolver } from './nativescript-package-resolver.js';
7
+ import { findMonorepoWorkspaceRoot, getProjectRootPath } from './project.js';
8
+ const nodeRequire = createRequire(import.meta.url);
9
+ // Stub out webpack-style `nativescript-worker-loader!./worker.js` imports.
10
+ // Some packages (e.g. `nativescript-sqlite-commercial`) still ship a webpack 4
11
+ // branch like:
12
+ // if (global.TNS_WEBPACK >= 5) { worker = new Worker("./worker.js"); }
13
+ // else { require("nativescript-worker-loader!./worker.js"); }
14
+ // At runtime under @nativescript/vite, `global.TNS_WEBPACK` is undefined so the
15
+ // loader-prefix branch is never executed — but Rolldown still statically scans
16
+ // it and fails to resolve the webpack-only specifier. Returning a virtual stub
17
+ // module satisfies the static graph without touching runtime semantics.
18
+ const NS_WORKER_LOADER_STUB_ID = '\0ns-worker-loader-stub';
19
+ export function nativescriptWorkerLoaderStubPlugin() {
20
+ return {
21
+ name: 'nativescript-worker-loader-stub',
22
+ enforce: 'pre',
23
+ resolveId(id) {
24
+ if (typeof id === 'string' && id.startsWith('nativescript-worker-loader!')) {
25
+ return NS_WORKER_LOADER_STUB_ID;
26
+ }
27
+ return null;
28
+ },
29
+ load(id) {
30
+ if (id === NS_WORKER_LOADER_STUB_ID) {
31
+ // The default export is a constructor — emulate `new SqliteWorker()`
32
+ // so the legacy code path doesn't crash if it ever runs accidentally.
33
+ return ['const message = "nativescript-worker-loader! is a webpack-only loader prefix and is not supported under Vite. Update the calling package to use `new Worker(new URL(...))` for worker entry points.";', 'function NSWorkerLoaderStub() { throw new Error(message); }', 'export default NSWorkerLoaderStub;'].join('\n');
34
+ }
35
+ return null;
36
+ },
37
+ };
38
+ }
39
+ // Worker bundles run as separate Rolldown builds and do NOT inherit `config.plugins`
40
+ // at build time (see https://vite.dev/config/worker-options#worker-plugins). To match
41
+ // the main bundle's module resolution behavior, mirror the bare-specifier resolvers
42
+ // that the main config registers — most importantly the tsconfig `paths` resolver,
43
+ // without which workspace path aliases (e.g. `@scope/lib/util`) fail to resolve in
44
+ // any code reachable from a `new Worker(new URL(...))` entry point.
45
+ export function getWorkerPlugins(platformOrOpts) {
46
+ const opts = typeof platformOrOpts === 'string' ? { platform: platformOrOpts } : platformOrOpts;
47
+ const { platform, verbose } = opts;
48
+ // Reuse the same tsconfig data the main config does. `getTsConfigData` is internally
49
+ // memoized by config path, so this is essentially free on subsequent calls.
50
+ const tsConfig = getTsConfigData({ platform, verbose });
51
+ const tsConfigResolver = createTsConfigPathsResolver({
52
+ paths: tsConfig.paths,
53
+ baseUrl: tsConfig.baseUrl,
54
+ platform,
55
+ verbose,
56
+ });
57
+ const plugins = [
5
58
  // Handle ~/package.json virtual module for workers
6
59
  {
7
60
  name: 'worker-virtual-package-json',
@@ -61,6 +114,558 @@ export function getWorkerPlugins(platform) {
61
114
  },
62
115
  },
63
116
  ];
117
+ // Mirror the main-config bare-specifier resolvers for workers. Without these,
118
+ // workspace tsconfig paths and platform-specific package mains fail to resolve
119
+ // when code is pulled into a worker bundle.
120
+ if (tsConfigResolver) {
121
+ plugins.push(tsConfigResolver);
122
+ }
123
+ plugins.push(packagePlatformResolverPlugin({ tsConfig, platform, verbose }));
124
+ plugins.push(nativescriptPackageResolver(platform));
125
+ plugins.push(nativescriptWorkerLoaderStubPlugin());
126
+ return plugins;
127
+ }
128
+ // In Vite dev/HMR mode, Vite's built-in `workerImportMetaUrlPlugin` rewrites
129
+ // `new Worker(new URL('./foo.worker', import.meta.url))` into
130
+ // `new Worker(new URL(/* @vite-ignore */"/src/.../foo.worker.ts?worker_file&type=classic", '' + import.meta.url))`.
131
+ // That output breaks under NativeScript for two independent reasons:
132
+ //
133
+ // 1. TypeError on `new URL(spec, '' + import.meta.url)`. The iOS V8 runtime's
134
+ // `InitializeImportMetaObject` callback (in NativeScript/runtime/Runtime.mm)
135
+ // blindly prefixes the module's registry key with `file://`. For HTTP-served
136
+ // HMR modules the key is already `http://localhost:5173/ns/m/...`, so the
137
+ // callback emits `import.meta.url = "file://http://localhost:5173/ns/m/..."`
138
+ // — a malformed URL that fails the WHATWG URL parser's base check. Other
139
+ // `new URL(spec, import.meta.url)` sites in the served pipeline are wrapped
140
+ // in `try/catch` and silently fall through; the worker creation site is not.
141
+ //
142
+ // 2. Pipeline routing mismatch (Class E in HMR_TRANSFORM_PIPELINE_REVIEW.md).
143
+ // Even with a valid `import.meta.url`, the resolved URL points at Vite's
144
+ // `?worker_file&type=classic` middleware, which serves a self-contained
145
+ // worker bundle whose internal imports use `/src/...` and `/@fs/...` URLs
146
+ // that bypass our `/ns/m/` wrapping pipeline. The worker would crash on
147
+ // its first transitive import.
148
+ //
149
+ // We use `__NS_HTTP_ORIGIN__` (set by the entry runtime in
150
+ // `hmr/entry-runtime.ts`) so the URL stays correct when the device connects
151
+ // via a non-localhost origin (e.g. `http://192.168.x.x:5173`).
152
+ //
153
+ // Counterpart for production builds: `workerUrlPlugin()` below, which runs in
154
+ // `generateBundle` and rewrites a similar pattern to `new Worker('~/' + ...)`.
155
+ // Matches Vite-emitted dev shape:
156
+ // new Worker(new URL(/* @vite-ignore */ "/src/.../foo.worker.ts?worker_file&type=classic", '' + import.meta.url))
157
+ // The `/* @vite-ignore */` and `'' +` coercion are constants Vite always emits
158
+ // (see `workerImportMetaUrlPlugin` in vite/dist/node/chunks/node.js), so we
159
+ // match them as fixed structure rather than as optional fragments. The asset
160
+ // path can use single, double, or template-literal quotes.
161
+ const WORKER_VITE_DEV_RE = /new\s+Worker\s*\(\s*new\s+URL\s*\(\s*\/\*\s*@vite-ignore\s*\*\/\s*(['"`])([^'"`]+)\1\s*,\s*(?:'\s*'|"\s*"|`\s*`)\s*\+\s*import\.meta\.url\s*\)\s*(,\s*\{[^}]*\})?\s*\)/g;
162
+ const SKIP_TRANSFORM_ID_RE = /(?:^|\/)(?:node_modules|\.vite)\//;
163
+ // Strip Vite's `?worker_file&type=classic` query suffix (and any extension) so
164
+ // the resulting URL matches the canonical `/ns/m/<rel-without-ext>` shape that
165
+ // the NS HMR pipeline serves. Exported for unit testing.
166
+ export function viteWorkerAssetPathToNsMUrl(assetPath, projectRoot, workspaceRoot) {
167
+ if (typeof assetPath !== 'string' || !assetPath) {
168
+ return null;
169
+ }
170
+ // Vite emits asset paths in two shapes during dev/HMR:
171
+ // 1. Project-relative: "/src/.../foo.worker.ts?worker_file&type=classic"
172
+ // 2. Absolute fs: "/@fs/Users/.../src/.../foo.worker.ts?worker_file&type=classic"
173
+ // We only need to match #1 here — the project-relative form Vite uses for
174
+ // project-local files. Absolute-fs paths come from outside the project root
175
+ // (e.g. workspace libs in a monorepo), and we hand those off to Vite's
176
+ // default behavior rather than try to map them into `/ns/m/`.
177
+ const queryIdx = assetPath.indexOf('?');
178
+ const cleanPath = queryIdx === -1 ? assetPath : assetPath.slice(0, queryIdx);
179
+ const query = queryIdx === -1 ? '' : assetPath.slice(queryIdx);
180
+ // Confirm this is the worker_file query Vite emits — leaves non-worker URLs
181
+ // (e.g. asset URLs from `assetImportMetaUrlPlugin`) alone.
182
+ if (!/[?&]worker_file(?:&|=|$)/.test(query)) {
183
+ return null;
184
+ }
185
+ // Project-relative: "/src/..." → "/ns/m/src/..."
186
+ if (cleanPath.startsWith('/') && !cleanPath.startsWith('/@fs/')) {
187
+ // Strip the rewritable extension so the URL matches the canonical
188
+ // `/ns/m/<rel-without-ext>` shape served by the HMR middleware.
189
+ const noExt = cleanPath.replace(/\.(?:ts|tsx|mjs|cjs|js|jsx)$/, '');
190
+ return `/ns/m${noExt}`;
191
+ }
192
+ // Absolute-fs: "/@fs/abs/path/..." — try to map into project or workspace roots.
193
+ if (cleanPath.startsWith('/@fs/')) {
194
+ const absPath = cleanPath.slice('/@fs'.length); // keep leading '/'
195
+ const toPosix = (value) => value.replace(/\\/g, '/');
196
+ const stripTrailing = (value) => value.replace(/\/+$/, '');
197
+ const target = toPosix(absPath);
198
+ const projectPosix = stripTrailing(toPosix(path.resolve(projectRoot)));
199
+ const workspacePosix = workspaceRoot ? stripTrailing(toPosix(path.resolve(workspaceRoot))) : null;
200
+ const tryRoot = (root) => {
201
+ if (!root)
202
+ return null;
203
+ if (target === root)
204
+ return '/ns/m';
205
+ if (target.startsWith(`${root}/`)) {
206
+ const rel = target.slice(root.length); // includes leading '/'
207
+ const noExt = rel.replace(/\.(?:ts|tsx|mjs|cjs|js|jsx)$/, '');
208
+ return `/ns/m${noExt}`;
209
+ }
210
+ return null;
211
+ };
212
+ return tryRoot(projectPosix) ?? tryRoot(workspacePosix);
213
+ }
214
+ return null;
215
+ }
216
+ // Runtime helper injected at the top of every HMR-transformed module that
217
+ // instantiates a Worker. Wraps each `new Worker(...)` call in
218
+ // `__nsHmrTrackWorker(...)`, which registers the worker for cleanup via
219
+ // TWO complementary mechanisms:
220
+ //
221
+ // 1. STANDARDS-COMPLIANT — `import.meta.hot.dispose(cb)` per Vite spec.
222
+ // The NS iOS runtime's `HMRSupport.mm` registers the callback in
223
+ // `g_hotDispose` (per-module). The Angular HMR client drains it
224
+ // via `globalThis.__nsRunHmrDispose()` before reboot. This is the
225
+ // same primitive every Vite plugin author already knows; users
226
+ // can register their own dispose callbacks the same way.
227
+ //
228
+ // 2. RUNTIME-AUTHORITATIVE — `globalThis.__NS_HMR_WORKERS__` Set
229
+ // drained by the HMR client (or by the runtime's
230
+ // `__nsTerminateAllWorkers()`). This catches workers spawned in
231
+ // modules that aren't being individually re-evaluated (e.g. the
232
+ // `app.component.ts` constructor that re-runs on every Angular
233
+ // reboot, even though `app.component.ts` itself isn't being
234
+ // replaced — its `dispose` callbacks don't fire per Vite spec).
235
+ //
236
+ // ## Why both?
237
+ //
238
+ // `import.meta.hot.dispose()` is correct for modules being replaced.
239
+ // But Angular HMR's `__reboot_ng_modules__` re-creates the component
240
+ // tree without re-evaluating modules — `app.component.ts`'s top-level
241
+ // dispose callback wouldn't fire on a `login.component.html` save,
242
+ // even though Angular re-runs `AppComponent`'s constructor and spawns
243
+ // a fresh worker. The runtime-authoritative path catches this:
244
+ // `__nsTerminateAllWorkers()` walks `Caches::Workers` (the iOS
245
+ // runtime's authoritative worker registry) and kills every live
246
+ // worker regardless of which module spawned it.
247
+ //
248
+ // ## Design notes
249
+ //
250
+ // * Helper injected ONLY in modules that have at least one
251
+ // `new Worker(new URL(...))` call we rewrote. Modules without
252
+ // workers pay no prelude cost.
253
+ // * `terminate()` is the only cleanup primitive. Apps needing
254
+ // graceful shutdown should send a custom message before HMR via
255
+ // their own pre-update hook (e.g.
256
+ // `import.meta.hot.on('vite:beforeUpdate', ...)`).
257
+ // * `try/catch` around `terminate()` so an already-dead worker
258
+ // doesn't break the HMR cycle (e.g. user code already terminated
259
+ // it).
260
+ // * Both mechanisms are best-effort and idempotent: terminating an
261
+ // already-dead worker is a no-op, and clearing an already-empty
262
+ // Set is a no-op. Belt-and-suspenders is the right policy here.
263
+ // * `addEventListener('terminated', ...)` would be nicer than a Set
264
+ // of references, but iOS Worker doesn't fire that event reliably,
265
+ // so we use the Set + opportunistic cleanup approach.
266
+ const HMR_WORKER_DISPOSE_HELPER = [
267
+ '/* Injected by @nativescript/vite workerHmrUrlPlugin (HMR worker auto-dispose) */',
268
+ 'const __nsHmrTrackWorker = /* @__PURE__ */ (function () {',
269
+ // Per-module Set so `import.meta.hot.dispose` only terminates
270
+ // workers SPAWNED BY THIS MODULE — matches Vite spec semantics.
271
+ // The shared `globalThis.__NS_HMR_WORKERS__` Set below is the
272
+ // belt-and-suspenders fallback the runtime can also drain
273
+ // universally on Angular reboot.
274
+ '\tconst __nsModuleWorkers = new Set();',
275
+ '\tlet __nsDisposeRegistered = false;',
276
+ '\treturn function __nsHmrTrackWorker(w) {',
277
+ '\t\tif (!w) return w;',
278
+ // Path 1: register in the legacy global Set. Kept for backward
279
+ // compatibility with older NS runtimes that don't yet ship
280
+ // `__nsTerminateAllWorkers()` or `__nsRunHmrDispose()`. Once those
281
+ // runtime APIs are universally adopted this can be removed —
282
+ // everything else here is standards-compliant.
283
+ '\t\ttry {',
284
+ '\t\t\tconst __nsG = typeof globalThis !== "undefined" ? globalThis : (typeof self !== "undefined" ? self : {});',
285
+ '\t\t\tif (!__nsG.__NS_HMR_WORKERS__) __nsG.__NS_HMR_WORKERS__ = new Set();',
286
+ '\t\t\t__nsG.__NS_HMR_WORKERS__.add(w);',
287
+ '\t\t} catch (_e) {}',
288
+ // Path 2: standards-compliant `import.meta.hot.dispose` registration.
289
+ // We re-register the disposer on EVERY worker spawn rather than
290
+ // just the first, because per Vite spec dispose callbacks are
291
+ // consumed when they fire — the runtime drains them out of its
292
+ // registry on each HMR cycle. The closure-level
293
+ // `__nsDisposeRegistered` flag is reset by the disposer itself
294
+ // after firing, so we register exactly once per HMR cycle (not
295
+ // once per worker spawn within a cycle): the second `add()` in
296
+ // the same cycle sees `__nsDisposeRegistered === true` and skips
297
+ // re-registration. After the cycle completes the flag flips back
298
+ // to false and the next worker spawn registers a fresh disposer.
299
+ // Modules that never instantiate a worker never register a
300
+ // disposer at all.
301
+ '\t\t__nsModuleWorkers.add(w);',
302
+ '\t\tif (!__nsDisposeRegistered && typeof import.meta !== "undefined" && import.meta && import.meta.hot && typeof import.meta.hot.dispose === "function") {',
303
+ '\t\t\t__nsDisposeRegistered = true;',
304
+ '\t\t\timport.meta.hot.dispose(function () {',
305
+ '\t\t\t\tfor (const __nsW of __nsModuleWorkers) {',
306
+ '\t\t\t\t\ttry { typeof __nsW.terminate === "function" && __nsW.terminate(); } catch (_e) {}',
307
+ '\t\t\t\t}',
308
+ '\t\t\t\t__nsModuleWorkers.clear();',
309
+ // Re-arm so the next worker spawn (in the new module instance
310
+ // after the HMR reboot) registers a fresh disposer for the next
311
+ // cycle. Without this re-arm, only cycle #1 uses the dispose
312
+ // path and cycles #2+ fall through to the worker terminator
313
+ // fallback — observable but suboptimal (uses two log lines
314
+ // instead of one and pays the worker terminator's iteration
315
+ // cost unnecessarily).
316
+ '\t\t\t\t__nsDisposeRegistered = false;',
317
+ '\t\t\t});',
318
+ '\t\t}',
319
+ '\t\treturn w;',
320
+ '\t};',
321
+ '})();',
322
+ '',
323
+ ].join('\n');
324
+ export function workerHmrUrlPlugin(opts) {
325
+ const { verbose } = opts || {};
326
+ let projectRoot = '';
327
+ let workspaceRoot = null;
328
+ return {
329
+ name: 'nativescript-worker-hmr-url-transform',
330
+ // Run AFTER Vite's built-in `workerImportMetaUrlPlugin` (and AFTER
331
+ // the Angular plugin, which discards upstream `code` by re-compiling
332
+ // from disk). At this point Vite has already rewritten the user's
333
+ // `new Worker(new URL('./foo', import.meta.url))` into its dev shape
334
+ // `new Worker(new URL(/* @vite-ignore */"/src/.../foo.worker.ts?worker_file&type=classic", '' + import.meta.url))`.
335
+ // We match that shape and replace it with a plain string URL that
336
+ // routes through `/ns/m/` so the worker's internal imports get the
337
+ // same HMR treatment as the main thread.
338
+ enforce: 'post',
339
+ // Dev/HMR only — `workerUrlPlugin()` below handles the production build.
340
+ apply: 'serve',
341
+ configResolved(config) {
342
+ projectRoot = path.resolve(config.root || getProjectRootPath());
343
+ workspaceRoot = findMonorepoWorkspaceRoot(projectRoot);
344
+ },
345
+ transform(code, id) {
346
+ if (!code || code.indexOf('new Worker') === -1 || code.indexOf('import.meta.url') === -1) {
347
+ return null;
348
+ }
349
+ // `id` may carry a Vite query suffix (`?vue&type=script`, `?used`, …);
350
+ // strip it so path matching works against real fs paths.
351
+ const cleanId = id.split('?', 1)[0];
352
+ if (!cleanId || SKIP_TRANSFORM_ID_RE.test(cleanId)) {
353
+ return null;
354
+ }
355
+ let modified = false;
356
+ let workerWraps = 0;
357
+ let newCode = code.replace(WORKER_VITE_DEV_RE, (match, _quote, assetPath, options) => {
358
+ const nsmUrl = viteWorkerAssetPathToNsMUrl(assetPath, projectRoot, workspaceRoot);
359
+ if (!nsmUrl) {
360
+ if (verbose) {
361
+ // eslint-disable-next-line no-console
362
+ console.warn(`[ns-worker-hmr] worker asset path ${JSON.stringify(assetPath)} in ${cleanId} can't be mapped to /ns/m/; leaving Vite's default behavior in place`);
363
+ }
364
+ return match;
365
+ }
366
+ modified = true;
367
+ workerWraps++;
368
+ const optionsTail = options ? options : '';
369
+ // Wrap each `new Worker(...)` in `__nsHmrTrackWorker(...)`
370
+ // so it auto-registers for cleanup on the next HMR
371
+ // dispose. The wrap is transparent — `__nsHmrTrackWorker`
372
+ // returns the worker instance unchanged so callers that
373
+ // assign the result to a variable still get a real
374
+ // Worker.
375
+ return `__nsHmrTrackWorker(new Worker((typeof globalThis !== "undefined" && typeof globalThis.__NS_HTTP_ORIGIN__ === "string" ? globalThis.__NS_HTTP_ORIGIN__ : "") + ${JSON.stringify(nsmUrl)}${optionsTail}))`;
376
+ });
377
+ if (!modified) {
378
+ return null;
379
+ }
380
+ // Inject the helper prelude exactly once at the top of the
381
+ // module. The helper closure self-tracks workers and lazily
382
+ // registers the `import.meta.hot.dispose()` callback on the
383
+ // first wrap, so injecting it unconditionally (whether or not
384
+ // HMR is wired up at module-eval time) is safe.
385
+ newCode = HMR_WORKER_DISPOSE_HELPER + newCode;
386
+ if (verbose) {
387
+ // eslint-disable-next-line no-console
388
+ console.log(`[ns-worker-hmr] rewrote ${workerWraps} Vite worker URL${workerWraps === 1 ? '' : 's'} → /ns/m/ in ${cleanId} (with HMR auto-terminate via globalThis.__NS_HMR_WORKERS__)`);
389
+ }
390
+ // Returning null for the source map keeps Vite's downstream sourcemap
391
+ // composition simple; the per-Worker line shift is small and the
392
+ // frame is rarely the one a developer is debugging.
393
+ return { code: newCode, map: null };
394
+ },
395
+ };
396
+ }
397
+ // Safety-net TypeScript fallback transform.
398
+ //
399
+ // Problem: In HMR mode (where `useAngularCompilationAPI = false`), the
400
+ // `@analogjs/vite-plugin-angular` `config` hook forcibly sets `oxc: false` on
401
+ // the Vite config (see `angular-vite-plugin.js`:
402
+ // `const oxc = pluginOptions.useAngularCompilationAPI ? undefined : (config.oxc ?? false);`).
403
+ // That disables Vite's built-in oxc TypeScript transformer for the whole dev
404
+ // session. The Analog plugin then expects its own `fileEmitter` to strip types
405
+ // from every `.ts` file in the project — but `fileEmitter` only knows about
406
+ // files that are part of the Angular TypeScript program (anything imported
407
+ // directly, or referenced via `templateUrl` / `styleUrls` from a decorated
408
+ // class).
409
+ //
410
+ // Worker entry files fall outside the program. They are only loaded via
411
+ // `new Worker(new URL('./foo.worker', import.meta.url))`, which is NOT an
412
+ // import — it's a URL constructor expression the device resolves at runtime.
413
+ // `fileEmitter(id)` returns nothing for those files, the Analog plugin's
414
+ // transform returns `undefined`, oxc doesn't run (because Analog disabled it),
415
+ // and the raw `.ts` source reaches the device with type annotations intact.
416
+ // V8's parser then chokes on the first `(x: Type)` parameter annotation with
417
+ // `SyntaxError: Unexpected token ':'`.
418
+ //
419
+ // The fix is a small post-enforce transform that re-runs Vite's own
420
+ // `transformWithOxc` on any `.ts`/`.tsx` file that still looks like raw
421
+ // TypeScript after the rest of the pipeline is done. For already-compiled
422
+ // Angular output (pure JS), the detection heuristic short-circuits and we
423
+ // never invoke oxc, so the fast path stays fast.
424
+ //
425
+ // Scope intentionally narrow:
426
+ // * `enforce: 'post'` — only sees final code after every other plugin had a
427
+ // chance to transform.
428
+ // * `apply: 'serve'` — dev/HMR only. Production builds use Rolldown which
429
+ // handles TS natively without needing this net.
430
+ // * Skips `node_modules` / `.vite` — third-party code has its own pipeline,
431
+ // and hitting every transitive dep would be wasteful.
432
+ // * Skips files containing Angular decorators (`@Component`, `@Injectable`,
433
+ // `@NgModule`, `@Directive`, `@Pipe`). Those files belong to the Angular
434
+ // program; if they fell through the Angular plugin we surface Angular's
435
+ // own `"contains Angular decorators but is not in the TypeScript program"`
436
+ // warning rather than silently transforming them with oxc (which would
437
+ // emit a `@oxc-project/runtime/helpers/decorate` import that the app does
438
+ // not depend on, breaking Vite's import-analysis pass).
439
+ // * Regex-based detection — catches the tokens V8 would actually reject.
440
+ // False positives (running oxc on valid JS) are harmless because oxc with
441
+ // `lang: 'ts'` is a no-op on JS; false negatives would only surface as the
442
+ // same error the fix is designed to prevent, so the detector errs toward
443
+ // running the transform when in doubt.
444
+ const TS_ONLY_SYNTAX_RE = new RegExp([
445
+ // `import type { … } from '…'` / `export type { … } from '…'`
446
+ String.raw `\b(?:import|export)\s+type\s`,
447
+ // `interface Foo { … }`
448
+ String.raw `\binterface\s+[A-Z_$][\w$]*\s*[<{]`,
449
+ // `type Foo = …`
450
+ String.raw `\btype\s+[A-Z_$][\w$]*\s*[<=]`,
451
+ // `as Type` assertions — restrict right-hand side to common primitives
452
+ // or PascalCase identifiers to avoid catching unrelated tokens.
453
+ String.raw `\bas\s+(?:string|number|boolean|any|unknown|never|void|[A-Z][\w$]*)\b`,
454
+ // Parameter / destructured type annotations: `(msg: any)`, `(x: T, y: U)`.
455
+ // Anchored to `(` or `,` so we don't match object literal keys like `{ a: 1 }`.
456
+ String.raw `[(,]\s*[\w$]+\s*\??\s*:\s*(?:string|number|boolean|any|unknown|never|void|null|undefined|object|[A-Z][\w$]*(?:<[^>]*>)?(?:\[\])?)\b`,
457
+ // Variable type annotations: `let x: T = …` / `const y: T`
458
+ String.raw `\b(?:const|let|var)\s+[\w$]+\s*:\s*[\w$<>[\]|&., ]+\s*[;=]`,
459
+ // Return type annotations on arrow functions: `): T =>`
460
+ String.raw `\)\s*:\s*(?:string|number|boolean|any|unknown|never|void|[A-Z][\w$]*(?:<[^>]*>)?)\s*(?:=>|\{)`,
461
+ ].join('|'));
462
+ // Decorator shapes that mean "the Angular plugin owns this file, stay out of
463
+ // its way." We do NOT try to compile these ourselves even if the Angular
464
+ // plugin's `fileEmitter` didn't produce output for them — oxc would rewrite
465
+ // the decorators into `import _decorate from "@oxc-project/runtime/helpers/decorate"`
466
+ // calls, Vite's import-analysis would fail to resolve that helper package,
467
+ // and we'd turn a harmless "not in TypeScript program" warning into a fatal
468
+ // import error. Better to let Angular's own warning surface and leave the
469
+ // code untouched.
470
+ const ANGULAR_DECORATOR_RE = /@(?:Component|Directive|Injectable|NgModule|Pipe)\s*\(/;
471
+ const TS_FALLBACK_SKIP_ID_RE = /(?:^|\/)(?:node_modules|\.vite)\//;
472
+ export function tsFallbackTransformPlugin(opts) {
473
+ const { verbose } = opts || {};
474
+ // Cached after the first successful import so repeated transforms don't
475
+ // pay the dynamic-import cost. `null` = not loaded yet; `false` = load
476
+ // attempted and failed (older Vite with no oxc export — we'll skip).
477
+ let cachedTransformWithOxc = null;
478
+ return {
479
+ name: 'nativescript-ts-fallback-transform',
480
+ enforce: 'post',
481
+ apply: 'serve',
482
+ async transform(code, id) {
483
+ if (cachedTransformWithOxc === false)
484
+ return null;
485
+ const cleanId = id.split('?', 1)[0];
486
+ if (!cleanId || !/\.(m?ts|[jt]sx)$/.test(cleanId))
487
+ return null;
488
+ if (TS_FALLBACK_SKIP_ID_RE.test(cleanId))
489
+ return null;
490
+ if (ANGULAR_DECORATOR_RE.test(code))
491
+ return null;
492
+ if (!TS_ONLY_SYNTAX_RE.test(code))
493
+ return null;
494
+ if (cachedTransformWithOxc === null) {
495
+ try {
496
+ // Dynamic import keeps this plugin cross-version-safe: older
497
+ // Vite installs without `transformWithOxc` (pre-Rolldown
498
+ // builds) cleanly disable this fallback instead of crashing.
499
+ const vite = await import('vite');
500
+ if (typeof vite.transformWithOxc === 'function') {
501
+ cachedTransformWithOxc = vite.transformWithOxc;
502
+ }
503
+ else {
504
+ cachedTransformWithOxc = false;
505
+ return null;
506
+ }
507
+ }
508
+ catch {
509
+ cachedTransformWithOxc = false;
510
+ return null;
511
+ }
512
+ }
513
+ try {
514
+ const lang = cleanId.endsWith('tsx') ? 'tsx' : cleanId.endsWith('jsx') ? 'jsx' : 'ts';
515
+ const result = await cachedTransformWithOxc(code, cleanId, { lang });
516
+ if (!result || typeof result.code !== 'string')
517
+ return null;
518
+ if (verbose) {
519
+ // eslint-disable-next-line no-console
520
+ console.log(`[ns-ts-fallback] type-stripped ${cleanId}`);
521
+ }
522
+ return { code: result.code, map: result.map ?? null };
523
+ }
524
+ catch (err) {
525
+ if (verbose) {
526
+ // eslint-disable-next-line no-console
527
+ console.warn(`[ns-ts-fallback] transformWithOxc failed for ${cleanId}:`, err);
528
+ }
529
+ return null;
530
+ }
531
+ },
532
+ };
533
+ }
534
+ export function angularWorkerUrlPreservePlugin(opts) {
535
+ const { verbose } = opts || {};
536
+ let patched = false;
537
+ const applyPatch = () => {
538
+ if (patched)
539
+ return;
540
+ patched = true;
541
+ patchAngularCompilationInitializers({ verbose });
542
+ };
543
+ return {
544
+ name: 'nativescript-angular-worker-url-preserve',
545
+ // `enforce: 'pre'` + eager `config` hook ensures the patch lands
546
+ // before any `buildStart`/`transform` hook runs (i.e. before Angular
547
+ // ever instantiates a compilation class and calls `initialize`).
548
+ enforce: 'pre',
549
+ config() {
550
+ applyPatch();
551
+ return null;
552
+ },
553
+ // Belt-and-suspenders: Vite sometimes skips `config` for inner
554
+ // environments (e.g. `build --environment=<name>`). `configResolved`
555
+ // always runs once per environment, so re-applying here is safe
556
+ // (idempotent) and guarantees the patch lands before compilation.
557
+ configResolved() {
558
+ applyPatch();
559
+ },
560
+ };
561
+ }
562
+ // The three concrete `AngularCompilation` subclasses in `@angular/build`.
563
+ // All three expose an `initialize(tsconfig, hostOptions, compilerOptionsTransformer)`
564
+ // method that forwards `hostOptions.processWebWorker` into either the TS
565
+ // transformer (Aot/Jit) or a worker-thread MessageChannel (Parallel). We
566
+ // wrap `initialize` on each so `hostOptions.processWebWorker` is coerced to
567
+ // identity before any of that happens.
568
+ const ANGULAR_COMPILATION_TARGETS = [
569
+ {
570
+ specifier: 'src/tools/angular/compilation/aot-compilation.js',
571
+ className: 'AotCompilation',
572
+ },
573
+ {
574
+ specifier: 'src/tools/angular/compilation/jit-compilation.js',
575
+ className: 'JitCompilation',
576
+ },
577
+ {
578
+ specifier: 'src/tools/angular/compilation/parallel-compilation.js',
579
+ className: 'ParallelCompilation',
580
+ },
581
+ ];
582
+ function patchAngularCompilationInitializers(opts) {
583
+ const { verbose } = opts;
584
+ // `@angular/build` locks its public `exports` map to `.`, `./private`,
585
+ // and `./package.json`. Deep subpath requires like
586
+ // `@angular/build/src/tools/angular/compilation/aot-compilation.js`
587
+ // fail with `ERR_PACKAGE_PATH_NOT_EXPORTED`. Resolve the package root
588
+ // via the always-allowed `./package.json` export and require the
589
+ // absolute on-disk paths instead — `exports` doesn't gate absolute fs
590
+ // paths.
591
+ let pkgRoot;
592
+ try {
593
+ const pkgJsonPath = nodeRequire.resolve('@angular/build/package.json');
594
+ pkgRoot = path.dirname(pkgJsonPath);
595
+ }
596
+ catch {
597
+ if (verbose) {
598
+ // eslint-disable-next-line no-console
599
+ console.log('[ns-angular-worker-preserve] @angular/build not installed; skipping patch (non-Angular project)');
600
+ }
601
+ return;
602
+ }
603
+ let patchedCount = 0;
604
+ let attemptedCount = 0;
605
+ for (const target of ANGULAR_COMPILATION_TARGETS) {
606
+ attemptedCount++;
607
+ const filePath = path.join(pkgRoot, target.specifier);
608
+ let mod;
609
+ try {
610
+ mod = nodeRequire(filePath);
611
+ }
612
+ catch (err) {
613
+ if (verbose) {
614
+ // eslint-disable-next-line no-console
615
+ console.log(`[ns-angular-worker-preserve] ${target.className} not loadable at ${filePath} (older @angular/build or reorganized layout); skipping:`, err.message);
616
+ }
617
+ continue;
618
+ }
619
+ const klass = mod ? mod[target.className] : null;
620
+ if (typeof klass !== 'function') {
621
+ if (verbose) {
622
+ // eslint-disable-next-line no-console
623
+ console.log(`[ns-angular-worker-preserve] ${target.className} export missing from ${filePath}; skipping`);
624
+ }
625
+ continue;
626
+ }
627
+ if (klass.__nativescriptPatchedProcessWebWorker) {
628
+ patchedCount++;
629
+ continue;
630
+ }
631
+ const originalInitialize = klass.prototype && klass.prototype.initialize;
632
+ if (typeof originalInitialize !== 'function') {
633
+ if (verbose) {
634
+ // eslint-disable-next-line no-console
635
+ console.log(`[ns-angular-worker-preserve] ${target.className}.prototype.initialize missing; skipping`);
636
+ }
637
+ continue;
638
+ }
639
+ klass.prototype.initialize = function nativescriptPatchedInitialize(tsconfig, hostOptions, ...rest) {
640
+ // Wrap `processWebWorker` in place so Angular sees an identity
641
+ // function. When Angular's transformer sees `replacementPath ===
642
+ // filePath` it leaves `new Worker(new URL(...))` nodes unchanged,
643
+ // and Vite's own `workerImportMetaUrlPlugin` handles bundling
644
+ // downstream. Mutating the incoming object is safe: Analog
645
+ // constructs a fresh `hostOptions` on every `performAngularCompilation`
646
+ // call, and the only consumer (this `initialize` call) runs
647
+ // synchronously after our override.
648
+ if (hostOptions && typeof hostOptions.processWebWorker === 'function' && !hostOptions.__nativescriptPatchedProcessWebWorker) {
649
+ hostOptions.processWebWorker = function identityProcessWebWorker(workerFile, _containingFile) {
650
+ return workerFile;
651
+ };
652
+ hostOptions.__nativescriptPatchedProcessWebWorker = true;
653
+ }
654
+ return originalInitialize.call(this, tsconfig, hostOptions, ...rest);
655
+ };
656
+ klass.__nativescriptPatchedProcessWebWorker = true;
657
+ patchedCount++;
658
+ }
659
+ if (verbose) {
660
+ if (patchedCount === 0) {
661
+ // eslint-disable-next-line no-console
662
+ console.warn(`[ns-angular-worker-preserve] no AngularCompilation subclasses patched (tried ${attemptedCount}); worker URLs may be blanked out in the build`);
663
+ }
664
+ else {
665
+ // eslint-disable-next-line no-console
666
+ console.log(`[ns-angular-worker-preserve] patched ${patchedCount}/${attemptedCount} AngularCompilation subclass initializers (${ANGULAR_COMPILATION_TARGETS.map((t) => t.className).join(', ')})`);
667
+ }
668
+ }
64
669
  }
65
670
  export function workerUrlPlugin() {
66
671
  return {
@@ -72,7 +677,19 @@ export function workerUrlPlugin() {
72
677
  // Transform Vite's worker URL pattern to NativeScript's expected format
73
678
  // From: new Worker(new URL(/* @vite-ignore */ "/assets/sample.worker-C6wW8q2-.js", import.meta.url))
74
679
  // To: new Worker('~/' + 'assets/sample.worker-C6wW8q2-.js')
75
- const workerUrlRegex = /new\s+Worker\s*\(\s*new\s+URL\s*\(\s*(?:\/\*[^*]*\*\/\s*)?["']([^"']+)["']\s*,\s*import\.meta\.url\s*\)\s*\)/g;
680
+ //
681
+ // Rolldown (Vite's underlying bundler) emits the asset path as a
682
+ // template-literal (backticks) and prefixes the second URL arg
683
+ // with `\`\` +` to coerce it to a string, e.g.:
684
+ // new Worker(new URL(`/assets/foo.js`, `` + import.meta.url))
685
+ // The regex below accepts either single quotes, double quotes,
686
+ // or backticks for the asset path, and an optional
687
+ // `<emptyString> +` coercion prefix before `import.meta.url`. At
688
+ // NS runtime there's no `import.meta.url` in the main bundle and
689
+ // `new URL("/assets/...", ...)` would resolve to a `file:///...`
690
+ // URL that NS Worker can't load, so this rewrite is the last
691
+ // step that makes worker chunks actually loadable.
692
+ const workerUrlRegex = /new\s+Worker\s*\(\s*new\s+URL\s*\(\s*(?:\/\*[^*]*\*\/\s*)?[`"']([^`"']+)[`"']\s*,\s*(?:[`"'][^`"']*[`"']\s*\+\s*)?import\.meta\.url\s*\)\s*\)/g;
76
693
  if (workerUrlRegex.test(chunk.code)) {
77
694
  chunk.code = chunk.code.replace(workerUrlRegex, (match, assetPath) => {
78
695
  // Use the full asset path including assets/ folder