@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.
- package/configuration/angular.d.ts +1 -1
- package/configuration/angular.js +486 -140
- package/configuration/angular.js.map +1 -1
- package/configuration/base.js +159 -29
- package/configuration/base.js.map +1 -1
- package/configuration/javascript.js +3 -3
- package/configuration/javascript.js.map +1 -1
- package/configuration/solid.js +7 -0
- package/configuration/solid.js.map +1 -1
- package/configuration/typescript.js +4 -4
- package/configuration/typescript.js.map +1 -1
- package/helpers/angular/angular-linker.js +38 -42
- package/helpers/angular/angular-linker.js.map +1 -1
- package/helpers/angular/inject-component-hmr-registration.d.ts +112 -0
- package/helpers/angular/inject-component-hmr-registration.js +359 -0
- package/helpers/angular/inject-component-hmr-registration.js.map +1 -0
- package/helpers/angular/inline-decorator-component-templates.d.ts +3 -0
- package/helpers/angular/inline-decorator-component-templates.js +400 -0
- package/helpers/angular/inline-decorator-component-templates.js.map +1 -0
- package/helpers/angular/shared-linker.d.ts +7 -0
- package/helpers/angular/shared-linker.js +37 -1
- package/helpers/angular/shared-linker.js.map +1 -1
- package/helpers/angular/synthesize-decorator-ctor-parameters.d.ts +1 -0
- package/helpers/angular/synthesize-decorator-ctor-parameters.js +256 -0
- package/helpers/angular/synthesize-decorator-ctor-parameters.js.map +1 -0
- package/helpers/angular/synthesize-injectable-factories.d.ts +3 -0
- package/helpers/angular/synthesize-injectable-factories.js +414 -0
- package/helpers/angular/synthesize-injectable-factories.js.map +1 -0
- package/helpers/angular/util.d.ts +1 -0
- package/helpers/angular/util.js +88 -0
- package/helpers/angular/util.js.map +1 -1
- package/helpers/commonjs-plugins.d.ts +5 -2
- package/helpers/commonjs-plugins.js +126 -0
- package/helpers/commonjs-plugins.js.map +1 -1
- package/helpers/config-as-json.js +10 -0
- package/helpers/config-as-json.js.map +1 -1
- package/helpers/esbuild-platform-resolver.js +5 -5
- package/helpers/esbuild-platform-resolver.js.map +1 -1
- package/helpers/external-configs.d.ts +9 -1
- package/helpers/external-configs.js +31 -6
- package/helpers/external-configs.js.map +1 -1
- package/helpers/global-defines.d.ts +51 -0
- package/helpers/global-defines.js +77 -0
- package/helpers/global-defines.js.map +1 -1
- package/helpers/import-meta-path.d.ts +4 -0
- package/helpers/import-meta-path.js +5 -0
- package/helpers/import-meta-path.js.map +1 -0
- package/helpers/import-specifier.d.ts +1 -0
- package/helpers/import-specifier.js +18 -0
- package/helpers/import-specifier.js.map +1 -0
- package/helpers/logging.d.ts +1 -0
- package/helpers/logging.js +63 -3
- package/helpers/logging.js.map +1 -1
- package/helpers/main-entry.d.ts +5 -2
- package/helpers/main-entry.js +365 -116
- package/helpers/main-entry.js.map +1 -1
- package/helpers/nativeclass-transform.js +8 -127
- package/helpers/nativeclass-transform.js.map +1 -1
- package/helpers/nativeclass-transformer-plugin.d.ts +19 -1
- package/helpers/nativeclass-transformer-plugin.js +318 -36
- package/helpers/nativeclass-transformer-plugin.js.map +1 -1
- package/helpers/ns-core-url.d.ts +83 -0
- package/helpers/ns-core-url.js +167 -0
- package/helpers/ns-core-url.js.map +1 -0
- package/helpers/prelink-angular.js +1 -4
- package/helpers/prelink-angular.js.map +1 -1
- package/helpers/project.d.ts +35 -0
- package/helpers/project.js +120 -2
- package/helpers/project.js.map +1 -1
- package/helpers/ts-config-paths.js +50 -2
- package/helpers/ts-config-paths.js.map +1 -1
- package/helpers/workers.d.ts +20 -19
- package/helpers/workers.js +620 -3
- package/helpers/workers.js.map +1 -1
- package/hmr/client/css-handler.js +60 -19
- package/hmr/client/css-handler.js.map +1 -1
- package/hmr/client/hmr-pending-overlay.d.ts +27 -0
- package/hmr/client/hmr-pending-overlay.js +50 -0
- package/hmr/client/hmr-pending-overlay.js.map +1 -0
- package/hmr/client/index.js +597 -24
- package/hmr/client/index.js.map +1 -1
- package/hmr/client/utils.d.ts +5 -0
- package/hmr/client/utils.js +212 -21
- package/hmr/client/utils.js.map +1 -1
- package/hmr/entry-runtime.d.ts +10 -0
- package/hmr/entry-runtime.js +330 -42
- package/hmr/entry-runtime.js.map +1 -1
- package/hmr/frameworks/angular/client/index.d.ts +3 -1
- package/hmr/frameworks/angular/client/index.js +821 -25
- package/hmr/frameworks/angular/client/index.js.map +1 -1
- package/hmr/frameworks/angular/server/linker.js +37 -6
- package/hmr/frameworks/angular/server/linker.js.map +1 -1
- package/hmr/frameworks/angular/server/strategy.js +30 -6
- package/hmr/frameworks/angular/server/strategy.js.map +1 -1
- package/hmr/frameworks/typescript/server/strategy.js +8 -2
- package/hmr/frameworks/typescript/server/strategy.js.map +1 -1
- package/hmr/frameworks/vue/client/index.js +18 -42
- package/hmr/frameworks/vue/client/index.js.map +1 -1
- package/hmr/helpers/ast-normalizer.js +22 -10
- package/hmr/helpers/ast-normalizer.js.map +1 -1
- package/hmr/helpers/cjs-named-exports.d.ts +23 -0
- package/hmr/helpers/cjs-named-exports.js +152 -0
- package/hmr/helpers/cjs-named-exports.js.map +1 -0
- package/hmr/server/constants.d.ts +1 -0
- package/hmr/server/constants.js +14 -3
- package/hmr/server/constants.js.map +1 -1
- package/hmr/server/core-sanitize.d.ts +49 -2
- package/hmr/server/core-sanitize.js +267 -24
- package/hmr/server/core-sanitize.js.map +1 -1
- package/hmr/server/import-map.d.ts +65 -0
- package/hmr/server/import-map.js +222 -0
- package/hmr/server/import-map.js.map +1 -0
- package/hmr/server/index.d.ts +2 -1
- package/hmr/server/index.js.map +1 -1
- package/hmr/server/ns-core-cjs-shape.d.ts +204 -0
- package/hmr/server/ns-core-cjs-shape.js +271 -0
- package/hmr/server/ns-core-cjs-shape.js.map +1 -0
- package/hmr/server/perf-instrumentation.d.ts +114 -0
- package/hmr/server/perf-instrumentation.js +195 -0
- package/hmr/server/perf-instrumentation.js.map +1 -0
- package/hmr/server/runtime-graph-filter.d.ts +5 -0
- package/hmr/server/runtime-graph-filter.js +21 -0
- package/hmr/server/runtime-graph-filter.js.map +1 -0
- package/hmr/server/shared-transform-request.d.ts +12 -0
- package/hmr/server/shared-transform-request.js +144 -0
- package/hmr/server/shared-transform-request.js.map +1 -0
- package/hmr/server/vite-plugin.d.ts +21 -1
- package/hmr/server/vite-plugin.js +461 -22
- package/hmr/server/vite-plugin.js.map +1 -1
- package/hmr/server/websocket-angular-entry.d.ts +2 -0
- package/hmr/server/websocket-angular-entry.js +68 -0
- package/hmr/server/websocket-angular-entry.js.map +1 -0
- package/hmr/server/websocket-angular-hot-update.d.ts +78 -0
- package/hmr/server/websocket-angular-hot-update.js +413 -0
- package/hmr/server/websocket-angular-hot-update.js.map +1 -0
- package/hmr/server/websocket-core-bridge.d.ts +21 -0
- package/hmr/server/websocket-core-bridge.js +357 -0
- package/hmr/server/websocket-core-bridge.js.map +1 -0
- package/hmr/server/websocket-graph-upsert.d.ts +21 -0
- package/hmr/server/websocket-graph-upsert.js +33 -0
- package/hmr/server/websocket-graph-upsert.js.map +1 -0
- package/hmr/server/websocket-hmr-pending.d.ts +43 -0
- package/hmr/server/websocket-hmr-pending.js +55 -0
- package/hmr/server/websocket-hmr-pending.js.map +1 -0
- package/hmr/server/websocket-module-bindings.d.ts +6 -0
- package/hmr/server/websocket-module-bindings.js +471 -0
- package/hmr/server/websocket-module-bindings.js.map +1 -0
- package/hmr/server/websocket-module-specifiers.d.ts +101 -0
- package/hmr/server/websocket-module-specifiers.js +820 -0
- package/hmr/server/websocket-module-specifiers.js.map +1 -0
- package/hmr/server/websocket-ns-m-finalize.d.ts +22 -0
- package/hmr/server/websocket-ns-m-finalize.js +88 -0
- package/hmr/server/websocket-ns-m-finalize.js.map +1 -0
- package/hmr/server/websocket-ns-m-paths.d.ts +3 -0
- package/hmr/server/websocket-ns-m-paths.js +92 -0
- package/hmr/server/websocket-ns-m-paths.js.map +1 -0
- package/hmr/server/websocket-ns-m-request.d.ts +45 -0
- package/hmr/server/websocket-ns-m-request.js +196 -0
- package/hmr/server/websocket-ns-m-request.js.map +1 -0
- package/hmr/server/websocket-runtime-compat.d.ts +19 -0
- package/hmr/server/websocket-runtime-compat.js +287 -0
- package/hmr/server/websocket-runtime-compat.js.map +1 -0
- package/hmr/server/websocket-served-module-helpers.d.ts +36 -0
- package/hmr/server/websocket-served-module-helpers.js +631 -0
- package/hmr/server/websocket-served-module-helpers.js.map +1 -0
- package/hmr/server/websocket-txn.d.ts +6 -0
- package/hmr/server/websocket-txn.js +45 -0
- package/hmr/server/websocket-txn.js.map +1 -0
- package/hmr/server/websocket-vendor-unifier.d.ts +10 -0
- package/hmr/server/websocket-vendor-unifier.js +51 -0
- package/hmr/server/websocket-vendor-unifier.js.map +1 -0
- package/hmr/server/websocket-vue-sfc.d.ts +27 -0
- package/hmr/server/websocket-vue-sfc.js +1069 -0
- package/hmr/server/websocket-vue-sfc.js.map +1 -0
- package/hmr/server/websocket.d.ts +26 -3
- package/hmr/server/websocket.js +2233 -796
- package/hmr/server/websocket.js.map +1 -1
- package/hmr/shared/package-classifier.d.ts +9 -0
- package/hmr/shared/package-classifier.js +58 -0
- package/hmr/shared/package-classifier.js.map +1 -0
- package/hmr/shared/runtime/boot-timeline.d.ts +17 -0
- package/hmr/shared/runtime/boot-timeline.js +51 -0
- package/hmr/shared/runtime/boot-timeline.js.map +1 -0
- package/hmr/shared/runtime/browser-runtime-contract.d.ts +64 -0
- package/hmr/shared/runtime/browser-runtime-contract.js +54 -0
- package/hmr/shared/runtime/browser-runtime-contract.js.map +1 -0
- package/hmr/shared/runtime/dev-overlay.d.ts +85 -0
- package/hmr/shared/runtime/dev-overlay.js +1236 -0
- package/hmr/shared/runtime/dev-overlay.js.map +1 -0
- package/hmr/shared/runtime/http-only-boot.d.ts +1 -0
- package/hmr/shared/runtime/http-only-boot.js +53 -6
- package/hmr/shared/runtime/http-only-boot.js.map +1 -1
- package/hmr/shared/runtime/module-provenance.d.ts +1 -0
- package/hmr/shared/runtime/module-provenance.js +63 -0
- package/hmr/shared/runtime/module-provenance.js.map +1 -0
- package/hmr/shared/runtime/platform-polyfills.d.ts +26 -0
- package/hmr/shared/runtime/platform-polyfills.js +122 -0
- package/hmr/shared/runtime/platform-polyfills.js.map +1 -0
- package/hmr/shared/runtime/root-placeholder.d.ts +1 -0
- package/hmr/shared/runtime/root-placeholder.js +552 -82
- package/hmr/shared/runtime/root-placeholder.js.map +1 -1
- package/hmr/shared/runtime/session-bootstrap.d.ts +1 -0
- package/hmr/shared/runtime/session-bootstrap.js +195 -0
- package/hmr/shared/runtime/session-bootstrap.js.map +1 -0
- package/hmr/shared/runtime/vendor-bootstrap.js +52 -15
- package/hmr/shared/runtime/vendor-bootstrap.js.map +1 -1
- package/hmr/shared/vendor/manifest.d.ts +37 -0
- package/hmr/shared/vendor/manifest.js +677 -57
- package/hmr/shared/vendor/manifest.js.map +1 -1
- package/hmr/shared/vendor/registry.js +104 -7
- package/hmr/shared/vendor/registry.js.map +1 -1
- package/index.d.ts +1 -0
- package/index.js +5 -0
- package/index.js.map +1 -1
- package/package.json +14 -2
- package/runtime/core-aliases-early.js +94 -67
- package/runtime/core-aliases-early.js.map +1 -1
- package/shims/solid-jsx-runtime.d.ts +7 -0
- package/shims/solid-jsx-runtime.js +17 -0
- package/shims/solid-jsx-runtime.js.map +1 -0
package/helpers/workers.js
CHANGED
|
@@ -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
|
-
|
|
4
|
-
|
|
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
|
-
|
|
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
|