@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
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import * as esbuild from 'esbuild';
|
|
2
2
|
import { readFile } from 'fs/promises';
|
|
3
3
|
import path from 'path';
|
|
4
|
-
import { readFileSync } from 'fs';
|
|
4
|
+
import fs, { readFileSync } from 'fs';
|
|
5
5
|
import { createHash } from 'crypto';
|
|
6
6
|
import { createRequire } from 'node:module';
|
|
7
7
|
import { registerVendorManifest, clearVendorManifest, getVendorManifest } from './registry.js';
|
|
8
|
+
import { generatePlatformPolyfills } from '../runtime/platform-polyfills.js';
|
|
8
9
|
import { createNativeClassEsbuildPlugin } from '../../../helpers/nativeclass-esbuild-plugin.js';
|
|
10
|
+
import { getGlobalDefines } from '../../../helpers/global-defines.js';
|
|
9
11
|
export const VENDOR_MANIFEST_ID = '@nativescript/vendor-manifest';
|
|
10
12
|
export const VENDOR_MANIFEST_VIRTUAL_ID = '\0' + VENDOR_MANIFEST_ID;
|
|
11
13
|
export const VENDOR_BUNDLE_ID = '@nativescript/vendor';
|
|
@@ -17,10 +19,10 @@ export const DEFAULT_MANIFEST_FILENAME = 'ns-vendor-manifest.json';
|
|
|
17
19
|
// Do not force-include @nativescript/core in the dev vendor bundle.
|
|
18
20
|
// Keeping core out of vendor avoids duplicate side-effect registrations (e.g.,
|
|
19
21
|
// com.tns.FragmentClass, com.tns.NativeScriptActivity) across bundle.mjs and vendor.
|
|
20
|
-
//
|
|
21
|
-
//
|
|
22
|
-
//
|
|
23
|
-
const ALWAYS_INCLUDE = new Set([]);
|
|
22
|
+
// Force runtime-sensitive packages onto the vendor path so they do not drift
|
|
23
|
+
// between startup bundle, HTTP-wrapped CommonJS, and base-require semantics
|
|
24
|
+
// during HMR sessions.
|
|
25
|
+
const ALWAYS_INCLUDE = new Set(['stacktrace-js']);
|
|
24
26
|
const ALWAYS_EXCLUDE = new Set([
|
|
25
27
|
'@nativescript/android',
|
|
26
28
|
'@nativescript/ios',
|
|
@@ -39,6 +41,9 @@ const ALWAYS_EXCLUDE = new Set([
|
|
|
39
41
|
'bufferutil',
|
|
40
42
|
'utf-8-validate',
|
|
41
43
|
'node-gyp-build',
|
|
44
|
+
// All @babel/* and babel-* packages are build-time tools, never runtime deps.
|
|
45
|
+
// They get pulled in as peer deps of packages like @nativescript-community/solid-js
|
|
46
|
+
// but should never be in the vendor bundle (they require 'fs', 'path', etc.).
|
|
42
47
|
'@babel/core',
|
|
43
48
|
'@babel/helper-plugin-utils',
|
|
44
49
|
'@babel/generator',
|
|
@@ -47,7 +52,11 @@ const ALWAYS_EXCLUDE = new Set([
|
|
|
47
52
|
'@babel/parser',
|
|
48
53
|
'@babel/plugin-syntax-typescript',
|
|
49
54
|
'@babel/plugin-transform-typescript',
|
|
55
|
+
'@babel/preset-typescript',
|
|
56
|
+
'@babel/preset-env',
|
|
50
57
|
'@babel/types',
|
|
58
|
+
'babel-preset-solid',
|
|
59
|
+
'babel-plugin-jsx-dom-expressions',
|
|
51
60
|
// Heavy dependency not needed in vendor dev bundle; fetch via HTTP loader instead
|
|
52
61
|
'rxjs',
|
|
53
62
|
'nativescript',
|
|
@@ -57,6 +66,54 @@ const ALWAYS_EXCLUDE = new Set([
|
|
|
57
66
|
'ws',
|
|
58
67
|
'@types/node',
|
|
59
68
|
'nativescript-theme-core',
|
|
69
|
+
// Build-time tools that get pulled in as transitive dependencies but should
|
|
70
|
+
// never be in the device vendor bundle (they require Node built-ins like fs,
|
|
71
|
+
// path, child_process, etc.). Now that we collect transitive runtime deps,
|
|
72
|
+
// these need explicit exclusion.
|
|
73
|
+
'esbuild',
|
|
74
|
+
'prettier',
|
|
75
|
+
'acorn',
|
|
76
|
+
'recast',
|
|
77
|
+
'source-map',
|
|
78
|
+
'source-map-js',
|
|
79
|
+
'tsx',
|
|
80
|
+
'diff',
|
|
81
|
+
'esprima',
|
|
82
|
+
// TanStack build-time router tooling (code generation, file-based routing)
|
|
83
|
+
'@tanstack/router-plugin',
|
|
84
|
+
'@tanstack/router-generator',
|
|
85
|
+
'@tanstack/router-utils',
|
|
86
|
+
'@tanstack/virtual-file-routes',
|
|
87
|
+
// File system / glob utilities — build-time only, require Node fs
|
|
88
|
+
'fdir',
|
|
89
|
+
'picomatch',
|
|
90
|
+
'tinyglobby',
|
|
91
|
+
// SSR-only library (bot detection) — not needed on device
|
|
92
|
+
'isbot',
|
|
93
|
+
// Type-only packages with no runtime JavaScript
|
|
94
|
+
'csstype',
|
|
95
|
+
// NativeScript CLI hook system — build-time only, requires Node os/path
|
|
96
|
+
'@nativescript/hook',
|
|
97
|
+
// Test runner uses webpack's require.context API which doesn't exist in Vite.
|
|
98
|
+
// Including it in the vendor bundle causes __require.context crashes at runtime.
|
|
99
|
+
'@nativescript/unit-test-runner',
|
|
100
|
+
'nativescript-unit-test-runner',
|
|
101
|
+
// CSS build tools — postcss, tailwindcss, and related tooling are exclusively
|
|
102
|
+
// build-time processors. They require Node APIs (process, fs, path) and must
|
|
103
|
+
// never run on device. esbuild bundles their transitive deps (picocolors,
|
|
104
|
+
// nanoid, etc.) which reference `process` and crash at runtime.
|
|
105
|
+
'tailwindcss',
|
|
106
|
+
'@nativescript/tailwind',
|
|
107
|
+
'postcss',
|
|
108
|
+
'autoprefixer',
|
|
109
|
+
'postcss-import',
|
|
110
|
+
'postcss-url',
|
|
111
|
+
'postcss-nested',
|
|
112
|
+
'picocolors',
|
|
113
|
+
'nanoid',
|
|
114
|
+
// Server-side SDKs that require Node networking APIs (net, tls, dns, crypto).
|
|
115
|
+
// These are backend tools, not device-side.
|
|
116
|
+
'mongodb',
|
|
60
117
|
]);
|
|
61
118
|
const INDEX_ALIAS_SUFFIXES = ['/index', '/index.js', '/index.android.js', '/index.ios.js', '/index.visionos.js'];
|
|
62
119
|
export function vendorManifestPlugin(options) {
|
|
@@ -106,7 +163,7 @@ export function vendorManifestPlugin(options) {
|
|
|
106
163
|
const result = await ensureResult('server');
|
|
107
164
|
if (req.url === SERVER_VENDOR_PATH) {
|
|
108
165
|
res.setHeader('Content-Type', 'application/javascript');
|
|
109
|
-
res.end(result
|
|
166
|
+
res.end(createVendorBundleRuntimeModule(result));
|
|
110
167
|
return true;
|
|
111
168
|
}
|
|
112
169
|
if (req.url === SERVER_MANIFEST_PATH) {
|
|
@@ -173,15 +230,8 @@ export function vendorManifestPlugin(options) {
|
|
|
173
230
|
}
|
|
174
231
|
if (id === VENDOR_BUNDLE_VIRTUAL_ID) {
|
|
175
232
|
const result = await ensureResult('load-bundle');
|
|
176
|
-
// Return a single self-contained module that includes both the vendor module map
|
|
177
|
-
// and the vendor manifest to avoid extra imports that can influence chunking.
|
|
178
|
-
// - result.code exports `__nsVendorModuleMap`
|
|
179
|
-
// - we append an inline manifest export
|
|
180
233
|
return {
|
|
181
|
-
code:
|
|
182
|
-
export const vendorManifest = ${JSON.stringify(result.manifest)};
|
|
183
|
-
export default vendorManifest;
|
|
184
|
-
`,
|
|
234
|
+
code: createVendorBundleRuntimeModule(result),
|
|
185
235
|
moduleType: 'js',
|
|
186
236
|
};
|
|
187
237
|
}
|
|
@@ -219,7 +269,31 @@ async function generateVendorBundle(options) {
|
|
|
219
269
|
const { projectRoot, platform, mode, flavor } = options;
|
|
220
270
|
const collected = collectVendorModules(projectRoot, platform, flavor);
|
|
221
271
|
const entryCode = createVendorEntry(collected.entries);
|
|
272
|
+
// Externalize @nativescript/core and its subpaths in the vendor bundle so
|
|
273
|
+
// vendored packages (e.g. @nativescript-community/ui-material-bottomsheet)
|
|
274
|
+
// do NOT bring their own copy of core with them. The iOS import map maps
|
|
275
|
+
// `@nativescript/core` → `/ns/core` (the core bridge) at runtime, and the
|
|
276
|
+
// bridge delegates to the canonical Application/View/etc. already set up
|
|
277
|
+
// by bundle.mjs via installCoreAliasesEarly + the globalThis.Application
|
|
278
|
+
// seed. Without this externalization, vendor.mjs bundles a second copy of
|
|
279
|
+
// iOSApplication/View/LayoutBase — the second iosApp never receives the
|
|
280
|
+
// iOS launch event (bundle.mjs's iosApp registered first as
|
|
281
|
+
// UIApplication.delegate), so Application.getRootView() on it returns
|
|
282
|
+
// undefined, and any vendor-internal code that reads .getRootView() or
|
|
283
|
+
// checks `instanceof View` against bundle's classes fails under HMR.
|
|
284
|
+
const nsCoreExternalPlugin = {
|
|
285
|
+
name: 'ns-core-external',
|
|
286
|
+
setup(build) {
|
|
287
|
+
build.onResolve({ filter: /^@nativescript\/core(?:\/.*)?$/ }, (args) => ({
|
|
288
|
+
path: args.path,
|
|
289
|
+
external: true,
|
|
290
|
+
}));
|
|
291
|
+
},
|
|
292
|
+
};
|
|
222
293
|
const plugins = [
|
|
294
|
+
// Mark @nativescript/core external BEFORE other plugins so esbuild never
|
|
295
|
+
// tries to read/transform core's source files. See comment above.
|
|
296
|
+
nsCoreExternalPlugin,
|
|
223
297
|
// Apply NativeClass transformer to convert @NativeClass decorated classes to ES5 IIFE pattern.
|
|
224
298
|
// This MUST run before other plugins to ensure proper transformation.
|
|
225
299
|
createNativeClassEsbuildPlugin(platform),
|
|
@@ -233,6 +307,14 @@ async function generateVendorBundle(options) {
|
|
|
233
307
|
if (flavor === 'angular') {
|
|
234
308
|
plugins.push(angularLinkerEsbuildPlugin(projectRoot));
|
|
235
309
|
}
|
|
310
|
+
// Solid packages (e.g. solid-navigation) may ship raw .jsx/.tsx source
|
|
311
|
+
// files instead of pre-compiled .js. esbuild's default JSX transform
|
|
312
|
+
// targets React (React.createElement), which crashes at runtime with
|
|
313
|
+
// "React is not defined". Add a plugin that compiles .jsx/.tsx through
|
|
314
|
+
// babel-preset-solid so the vendor bundle gets proper Solid output.
|
|
315
|
+
if (flavor === 'solid') {
|
|
316
|
+
plugins.push(createSolidJsxEsbuildPlugin(projectRoot));
|
|
317
|
+
}
|
|
236
318
|
const buildResult = await esbuild.build({
|
|
237
319
|
stdin: {
|
|
238
320
|
contents: entryCode,
|
|
@@ -252,23 +334,164 @@ async function generateVendorBundle(options) {
|
|
|
252
334
|
// that Rollup warns it "cannot interpret due to the position of the comment".
|
|
253
335
|
// This preserves license text while preventing noisy warnings.
|
|
254
336
|
legalComments: 'eof',
|
|
255
|
-
|
|
337
|
+
// NativeScript is always a client environment — never server-side. The conditions
|
|
338
|
+
// must include 'browser' so packages with conditional exports (e.g.,
|
|
339
|
+
// @tanstack/router-core/isServer) resolve to client-side variants.
|
|
340
|
+
//
|
|
341
|
+
// 'development'/'production' (mode) is intentionally excluded: esbuild resolves
|
|
342
|
+
// conditions in the order they appear in the package.json exports object, and
|
|
343
|
+
// many packages list 'development' before 'browser'. Including it would cause
|
|
344
|
+
// environment-ambiguous stubs (e.g., isServer = undefined) to win over the
|
|
345
|
+
// correct client-side value (isServer = false). The 'import' condition already
|
|
346
|
+
// provides the correct ESM entry points, and process.env.NODE_ENV (set via
|
|
347
|
+
// define below) handles dev/prod branching at runtime.
|
|
348
|
+
//
|
|
349
|
+
// This aligns with the non-HMR Vite build: ['module', 'react-native', 'import', 'browser', 'default'].
|
|
350
|
+
conditions: ['module', 'react-native', 'import', 'browser', 'default'],
|
|
256
351
|
mainFields: ['module', 'browser', 'main'],
|
|
257
352
|
resolveExtensions: resolveExtensionsForPlatform(platform),
|
|
258
353
|
loader: {
|
|
259
354
|
'.css': 'text',
|
|
260
355
|
'.json': 'json',
|
|
261
356
|
},
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
357
|
+
// Mirror Vite's main-bundle DefinePlugin in the vendor esbuild build.
|
|
358
|
+
//
|
|
359
|
+
// esbuild's `define` requires every value to be a JS expression
|
|
360
|
+
// expressed as a string (the same constraint Vite normalises away).
|
|
361
|
+
// `getGlobalDefines()` returns a few raw `boolean` values for
|
|
362
|
+
// historical reasons (e.g. `__COMMONJS__: false`,
|
|
363
|
+
// `__UI_USE_XML_PARSER__: true`), so coerce any non-string entries
|
|
364
|
+
// through `JSON.stringify` before handing the table to esbuild.
|
|
365
|
+
define: (() => {
|
|
366
|
+
const raw = getGlobalDefines({
|
|
367
|
+
platform,
|
|
368
|
+
targetMode: mode,
|
|
369
|
+
verbose: !!options.verbose,
|
|
370
|
+
flavor: flavor ?? '',
|
|
371
|
+
isCI: !!process.env.CI,
|
|
372
|
+
});
|
|
373
|
+
const out = {};
|
|
374
|
+
for (const [key, value] of Object.entries(raw)) {
|
|
375
|
+
out[key] = typeof value === 'string' ? value : JSON.stringify(value);
|
|
376
|
+
}
|
|
377
|
+
// Belt-and-suspenders: keep the original NODE_ENV define explicit so
|
|
378
|
+
// future changes to `getGlobalDefines()` can't silently drop it.
|
|
379
|
+
out['process.env.NODE_ENV'] = JSON.stringify(mode);
|
|
380
|
+
return out;
|
|
381
|
+
})(),
|
|
265
382
|
plugins,
|
|
266
|
-
|
|
383
|
+
// Externalize ALL Node built-in modules. The vendor bundle runs on the
|
|
384
|
+
// NativeScript device runtime, not Node, so any Node API reference must
|
|
385
|
+
// be external. Using both bare and 'node:' prefixed forms.
|
|
386
|
+
external: [
|
|
387
|
+
'assert',
|
|
388
|
+
'async_hooks',
|
|
389
|
+
'buffer',
|
|
390
|
+
'child_process',
|
|
391
|
+
'cluster',
|
|
392
|
+
'console',
|
|
393
|
+
'constants',
|
|
394
|
+
'crypto',
|
|
395
|
+
'dgram',
|
|
396
|
+
'diagnostics_channel',
|
|
397
|
+
'dns',
|
|
398
|
+
'domain',
|
|
399
|
+
'events',
|
|
400
|
+
'fs',
|
|
401
|
+
'fs/promises',
|
|
402
|
+
'http',
|
|
403
|
+
'http2',
|
|
404
|
+
'https',
|
|
405
|
+
'inspector',
|
|
406
|
+
'module',
|
|
407
|
+
'net',
|
|
408
|
+
'os',
|
|
409
|
+
'path',
|
|
410
|
+
'path/posix',
|
|
411
|
+
'path/win32',
|
|
412
|
+
'perf_hooks',
|
|
413
|
+
'process',
|
|
414
|
+
'punycode',
|
|
415
|
+
'querystring',
|
|
416
|
+
'readline',
|
|
417
|
+
'repl',
|
|
418
|
+
'stream',
|
|
419
|
+
'stream/web',
|
|
420
|
+
'stream/promises',
|
|
421
|
+
'string_decoder',
|
|
422
|
+
'sys',
|
|
423
|
+
'timers',
|
|
424
|
+
'timers/promises',
|
|
425
|
+
'tls',
|
|
426
|
+
'trace_events',
|
|
427
|
+
'tty',
|
|
428
|
+
'url',
|
|
429
|
+
'util',
|
|
430
|
+
'v8',
|
|
431
|
+
'vm',
|
|
432
|
+
'wasi',
|
|
433
|
+
'worker_threads',
|
|
434
|
+
'zlib',
|
|
435
|
+
// node: prefixed variants
|
|
436
|
+
'node:assert',
|
|
437
|
+
'node:async_hooks',
|
|
438
|
+
'node:buffer',
|
|
439
|
+
'node:child_process',
|
|
440
|
+
'node:cluster',
|
|
441
|
+
'node:console',
|
|
442
|
+
'node:constants',
|
|
443
|
+
'node:crypto',
|
|
444
|
+
'node:dgram',
|
|
445
|
+
'node:diagnostics_channel',
|
|
446
|
+
'node:dns',
|
|
447
|
+
'node:domain',
|
|
448
|
+
'node:events',
|
|
449
|
+
'node:fs',
|
|
450
|
+
'node:fs/promises',
|
|
451
|
+
'node:http',
|
|
452
|
+
'node:http2',
|
|
453
|
+
'node:https',
|
|
454
|
+
'node:inspector',
|
|
455
|
+
'node:module',
|
|
456
|
+
'node:net',
|
|
457
|
+
'node:os',
|
|
458
|
+
'node:path',
|
|
459
|
+
'node:path/posix',
|
|
460
|
+
'node:path/win32',
|
|
461
|
+
'node:perf_hooks',
|
|
462
|
+
'node:process',
|
|
463
|
+
'node:punycode',
|
|
464
|
+
'node:querystring',
|
|
465
|
+
'node:readline',
|
|
466
|
+
'node:repl',
|
|
467
|
+
'node:stream',
|
|
468
|
+
'node:stream/web',
|
|
469
|
+
'node:stream/promises',
|
|
470
|
+
'node:string_decoder',
|
|
471
|
+
'node:sys',
|
|
472
|
+
'node:timers',
|
|
473
|
+
'node:timers/promises',
|
|
474
|
+
'node:tls',
|
|
475
|
+
'node:trace_events',
|
|
476
|
+
'node:tty',
|
|
477
|
+
'node:url',
|
|
478
|
+
'node:util',
|
|
479
|
+
'node:v8',
|
|
480
|
+
'node:vm',
|
|
481
|
+
'node:wasi',
|
|
482
|
+
'node:worker_threads',
|
|
483
|
+
'node:zlib',
|
|
484
|
+
],
|
|
267
485
|
});
|
|
268
486
|
if (!buildResult.outputFiles?.length) {
|
|
269
487
|
throw new Error('Vendor bundle generation produced no output');
|
|
270
488
|
}
|
|
271
|
-
const
|
|
489
|
+
const rawVendorCode = buildResult.outputFiles[0].text;
|
|
490
|
+
// Prepend platform polyfills so they run BEFORE any vendor module code.
|
|
491
|
+
// This ensures globals like AbortController and self are available when
|
|
492
|
+
// frameworks (TanStack Router, etc.) first execute inside the bundle.
|
|
493
|
+
const polyfillPrelude = generatePlatformPolyfills();
|
|
494
|
+
const vendorCode = polyfillPrelude + rawVendorCode;
|
|
272
495
|
const hash = createHash('sha1').update(vendorCode).digest('hex');
|
|
273
496
|
const manifest = buildManifest(collected.entries, hash);
|
|
274
497
|
return {
|
|
@@ -281,9 +504,17 @@ function collectVendorModules(projectRoot, platform, flavor) {
|
|
|
281
504
|
const packageJsonPath = path.resolve(projectRoot, 'package.json');
|
|
282
505
|
const pkg = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
|
|
283
506
|
const projectRequire = createRequire(packageJsonPath);
|
|
507
|
+
const debug = process.env.VITE_DEBUG_LOGS === 'true' || process.env.VITE_DEBUG_LOGS === '1';
|
|
284
508
|
const vendor = new Set();
|
|
285
509
|
const visited = new Set();
|
|
286
510
|
const queue = [];
|
|
511
|
+
// Local-source deps (file: pointing to a directory, link:, workspace:) are
|
|
512
|
+
// app code, not pre-packaged libraries. esbuild's vendor pipeline has none
|
|
513
|
+
// of the user's tsconfig path aliases or other Vite plugin resolvers, so
|
|
514
|
+
// any aliased import inside their source will fail with "Could not
|
|
515
|
+
// resolve". We collect their names here so that peer-dep traversal can
|
|
516
|
+
// also skip them.
|
|
517
|
+
const localSourceNames = new Set();
|
|
287
518
|
const isPackageRootSpecifier = (name) => {
|
|
288
519
|
if (!name)
|
|
289
520
|
return false;
|
|
@@ -307,12 +538,14 @@ function collectVendorModules(projectRoot, platform, flavor) {
|
|
|
307
538
|
if (!isAngularFlavor && (name === '@angular/compiler' || name.startsWith('@angular/'))) {
|
|
308
539
|
return;
|
|
309
540
|
}
|
|
310
|
-
|
|
311
|
-
if (
|
|
312
|
-
|
|
541
|
+
// Skip already-visited packages to avoid redundant queue processing
|
|
542
|
+
if (visited.has(name)) {
|
|
543
|
+
return;
|
|
313
544
|
}
|
|
545
|
+
visited.add(name);
|
|
314
546
|
vendor.add(name);
|
|
315
|
-
|
|
547
|
+
const isRoot = isPackageRootSpecifier(name);
|
|
548
|
+
// Only traverse deps for package roots; subpaths should not attempt package.json resolution
|
|
316
549
|
if (isRoot) {
|
|
317
550
|
queue.push(name);
|
|
318
551
|
}
|
|
@@ -321,14 +554,35 @@ function collectVendorModules(projectRoot, platform, flavor) {
|
|
|
321
554
|
if (!deps) {
|
|
322
555
|
return;
|
|
323
556
|
}
|
|
324
|
-
for (const name of Object.
|
|
557
|
+
for (const [name, spec] of Object.entries(deps)) {
|
|
558
|
+
if (isUnvendorableLocalSource(name, spec, projectRequire, platform)) {
|
|
559
|
+
// Defer to the regular Vite/Rolldown pipeline (HTTP-served in
|
|
560
|
+
// dev, bundled in production) where the
|
|
561
|
+
// ns-tsconfig-paths-resolver and the rest of the plugin chain
|
|
562
|
+
// can handle aliased imports. Local .tgz file: refs ARE proper
|
|
563
|
+
// packaged libraries and DO stay in vendor; so do file:
|
|
564
|
+
// directory refs that point at packages with compiled JS
|
|
565
|
+
// entry points (a common NativeScript monorepo pattern that
|
|
566
|
+
// hoists installs and re-exposes them from the app's
|
|
567
|
+
// package.json via `file:../../node_modules/<name>`).
|
|
568
|
+
localSourceNames.add(name);
|
|
569
|
+
if (debug) {
|
|
570
|
+
console.log(`[vendor] skipping local source dependency ${name} (spec: ${String(spec)})`);
|
|
571
|
+
}
|
|
572
|
+
continue;
|
|
573
|
+
}
|
|
325
574
|
addCandidate(name);
|
|
326
575
|
}
|
|
327
576
|
};
|
|
328
577
|
addDeps(pkg.dependencies);
|
|
329
578
|
addDeps(pkg.optionalDependencies);
|
|
330
579
|
for (const name of ALWAYS_INCLUDE) {
|
|
331
|
-
|
|
580
|
+
// Some force-included packages are only present transitively in apps that
|
|
581
|
+
// actually use them. Skip missing packages quietly so unrelated projects do
|
|
582
|
+
// not fail vendor collection just because the policy list names them.
|
|
583
|
+
if (canResolveDependencyPackageJson(name, projectRequire)) {
|
|
584
|
+
addCandidate(name);
|
|
585
|
+
}
|
|
332
586
|
}
|
|
333
587
|
// Ensure Android Activity proxy is present for SBG scanning in dev/HMR
|
|
334
588
|
// and non-HMR builds alike: explicitly include the side-effect module
|
|
@@ -339,16 +593,10 @@ function collectVendorModules(projectRoot, platform, flavor) {
|
|
|
339
593
|
if (pkg.dependencies?.['nativescript-vue'] && pkg.devDependencies?.vue) {
|
|
340
594
|
addCandidate('vue');
|
|
341
595
|
}
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
if (pkg.dependencies?.['@angular/common']) {
|
|
347
|
-
addCandidate('@angular/common');
|
|
348
|
-
}
|
|
349
|
-
// RxJS is large and not required inside the vendor bundle for dev HMR.
|
|
350
|
-
// Avoid bundling to reduce memory pressure; let app import via HTTP loader.
|
|
351
|
-
}
|
|
596
|
+
// Angular framework packages are intentionally NOT added to vendor. They are
|
|
597
|
+
// served via HTTP only so every importer resolves to a single module realm.
|
|
598
|
+
// See shouldSkipDependency() for the full rationale. RxJS is also left out of
|
|
599
|
+
// vendor (large, and not required in the vendor bundle for dev HMR).
|
|
352
600
|
if (pkg.dependencies?.['react-nativescript']) {
|
|
353
601
|
if (pkg.dependencies?.react) {
|
|
354
602
|
addCandidate('react');
|
|
@@ -357,6 +605,21 @@ function collectVendorModules(projectRoot, platform, flavor) {
|
|
|
357
605
|
addCandidate('react-dom');
|
|
358
606
|
}
|
|
359
607
|
}
|
|
608
|
+
// SolidJS / TanStack Router: when @nativescript/tanstack-router is a dependency,
|
|
609
|
+
// its runtime deps (@tanstack/solid-router, @tanstack/router-core, @tanstack/history)
|
|
610
|
+
// MUST be in the vendor bundle. These packages:
|
|
611
|
+
// 1. Use browser APIs (window.dispatchEvent) that don't exist in NativeScript — they
|
|
612
|
+
// must be bundled where the NativeScript wrapper intercepts those calls
|
|
613
|
+
// 2. Contain JSX source that needs Solid compilation (dist/source/*.jsx) — the HTTP
|
|
614
|
+
// fallback can't compile node_modules JSX since vite-plugin-solid skips it
|
|
615
|
+
// 3. Import solid-js internally — loading via HTTP creates a separate solid-js instance
|
|
616
|
+
// esbuild uses the 'import' condition (not 'solid'), resolving to pre-compiled
|
|
617
|
+
// dist/esm/*.js which avoids all three issues.
|
|
618
|
+
if (pkg.dependencies?.['@nativescript/tanstack-router']) {
|
|
619
|
+
addCandidate('@tanstack/solid-router');
|
|
620
|
+
addCandidate('@tanstack/router-core');
|
|
621
|
+
addCandidate('@tanstack/history');
|
|
622
|
+
}
|
|
360
623
|
parseEnvList(process.env.NS_VENDOR_INCLUDE).forEach(addCandidate);
|
|
361
624
|
const projectDeps = {
|
|
362
625
|
dependencies: new Set(Object.keys(pkg.dependencies ?? {})),
|
|
@@ -371,13 +634,19 @@ function collectVendorModules(projectRoot, platform, flavor) {
|
|
|
371
634
|
}
|
|
372
635
|
const peerDependencies = Object.keys(dependencyPkg.peerDependencies ?? {});
|
|
373
636
|
for (const peer of peerDependencies) {
|
|
374
|
-
if (shouldSkipDependency(peer)) {
|
|
637
|
+
if (shouldSkipDependency(peer) || localSourceNames.has(peer)) {
|
|
375
638
|
continue;
|
|
376
639
|
}
|
|
377
640
|
if (projectDeps.dependencies.has(peer) || projectDeps.optional.has(peer) || projectDeps.dev.has(peer)) {
|
|
378
641
|
addCandidate(peer);
|
|
379
642
|
}
|
|
380
643
|
}
|
|
644
|
+
// NOTE: We intentionally do NOT collect transitive runtime dependencies
|
|
645
|
+
// here. The import map + runtime specifier normalization handles non-vendor
|
|
646
|
+
// packages by routing them through HTTP to the Vite dev server. This avoids
|
|
647
|
+
// the fragility of trying to esbuild-bundle every transitive dep (which can
|
|
648
|
+
// fail due to Node built-ins, type-only packages, duplicate module instances,
|
|
649
|
+
// etc.). Only direct project dependencies go into the vendor bundle.
|
|
381
650
|
}
|
|
382
651
|
parseEnvList(process.env.NS_VENDOR_EXCLUDE).forEach((name) => {
|
|
383
652
|
vendor.delete(name);
|
|
@@ -393,6 +662,44 @@ function shouldSkipDependency(name) {
|
|
|
393
662
|
if (ALWAYS_EXCLUDE.has(name)) {
|
|
394
663
|
return true;
|
|
395
664
|
}
|
|
665
|
+
// Angular framework packages must only be served via the HTTP path so every
|
|
666
|
+
// importer resolves to a single module realm. When these packages are present
|
|
667
|
+
// in the vendor bundle AND imported by app modules via HTTP subpath, every
|
|
668
|
+
// @Component/@Injectable gets defined twice (once per realm), producing NG0912
|
|
669
|
+
// selector collisions, cross-realm `instanceof` failures, and dual class
|
|
670
|
+
// identities throughout Angular's DI container. HTTP-only is the single-realm
|
|
671
|
+
// invariant for user-level framework code.
|
|
672
|
+
if (name === '@nativescript/angular' || name === 'nativescript-angular' || name.startsWith('@angular/')) {
|
|
673
|
+
return true;
|
|
674
|
+
}
|
|
675
|
+
// All Babel packages are build tools — never bundle into device runtime.
|
|
676
|
+
// They require Node built-ins (fs, path, url) that don't exist on device.
|
|
677
|
+
if (name.startsWith('@babel/') || name.startsWith('babel-')) {
|
|
678
|
+
return true;
|
|
679
|
+
}
|
|
680
|
+
// Dev tools and type-only packages — not needed on device
|
|
681
|
+
if (name.startsWith('@solid-devtools/')) {
|
|
682
|
+
return true;
|
|
683
|
+
}
|
|
684
|
+
if (name.startsWith('@types/')) {
|
|
685
|
+
return true;
|
|
686
|
+
}
|
|
687
|
+
// PostCSS ecosystem — all build-time CSS processing
|
|
688
|
+
if (name === 'postcss' || name.startsWith('postcss-')) {
|
|
689
|
+
return true;
|
|
690
|
+
}
|
|
691
|
+
// Tailwind ecosystem — build-time only CSS framework
|
|
692
|
+
if (name.includes('tailwind')) {
|
|
693
|
+
return true;
|
|
694
|
+
}
|
|
695
|
+
// Test runners and frameworks — never needed on device
|
|
696
|
+
if (name.includes('test-runner') || name.includes('unit-test')) {
|
|
697
|
+
return true;
|
|
698
|
+
}
|
|
699
|
+
// Linters and formatters — build-time tools
|
|
700
|
+
if (name.includes('eslint') || name.includes('stylelint')) {
|
|
701
|
+
return true;
|
|
702
|
+
}
|
|
396
703
|
if (name.startsWith('.')) {
|
|
397
704
|
return true;
|
|
398
705
|
}
|
|
@@ -407,6 +714,160 @@ function shouldSkipDependency(name) {
|
|
|
407
714
|
}
|
|
408
715
|
return false;
|
|
409
716
|
}
|
|
717
|
+
const COMPILED_JS_ENTRY_EXTENSIONS = ['.js', '.mjs', '.cjs'];
|
|
718
|
+
const COMPILED_JS_ENTRY_REGEX = /\.(?:c|m)?jsx?$/;
|
|
719
|
+
function compiledJsExtensionsForPlatform(platform) {
|
|
720
|
+
const exts = [...COMPILED_JS_ENTRY_EXTENSIONS];
|
|
721
|
+
switch (platform) {
|
|
722
|
+
case 'android':
|
|
723
|
+
exts.push('.android.js');
|
|
724
|
+
break;
|
|
725
|
+
case 'ios':
|
|
726
|
+
exts.push('.ios.js', '.visionos.js');
|
|
727
|
+
break;
|
|
728
|
+
case 'visionos':
|
|
729
|
+
exts.push('.visionos.js', '.ios.js');
|
|
730
|
+
break;
|
|
731
|
+
}
|
|
732
|
+
return exts;
|
|
733
|
+
}
|
|
734
|
+
/**
|
|
735
|
+
* Determine whether a `package.json` dependency must be excluded from the
|
|
736
|
+
* HMR vendor bundle because esbuild's standalone vendor pipeline can't
|
|
737
|
+
* resolve its source.
|
|
738
|
+
*
|
|
739
|
+
* The HMR vendor bundle is generated by a standalone esbuild build that
|
|
740
|
+
* has none of the Vite plugin chain (most notably
|
|
741
|
+
* `ns-tsconfig-paths-resolver`), so any aliased import inside the
|
|
742
|
+
* package's **source** files will fail with "Could not resolve" and abort
|
|
743
|
+
* the whole bundle.
|
|
744
|
+
*
|
|
745
|
+
* Skip:
|
|
746
|
+
* - `link:` and `workspace:` refs (always app-side source).
|
|
747
|
+
* - `file:` refs to a directory whose installed package only ships
|
|
748
|
+
* TypeScript/JSX source (no compiled `.js`/`.mjs`/`.cjs` entry).
|
|
749
|
+
*
|
|
750
|
+
* Keep (return false):
|
|
751
|
+
* - Regular semver / git / url specs (normal third-party libraries).
|
|
752
|
+
* - Local `.tgz` file refs (pre-packaged libraries extracted at install).
|
|
753
|
+
* - `file:` directory refs that resolve to a package with a compiled JS
|
|
754
|
+
* entry — a common NativeScript monorepo convention where the app's
|
|
755
|
+
* `package.json` redirects to `../../node_modules/<name>` to avoid
|
|
756
|
+
* duplicate installs while letting the NativeScript CLI discover
|
|
757
|
+
* plugins from the app directory.
|
|
758
|
+
*/
|
|
759
|
+
export function isUnvendorableLocalSource(name, spec, projectRequire, platform) {
|
|
760
|
+
if (typeof spec !== 'string')
|
|
761
|
+
return false;
|
|
762
|
+
if (spec.startsWith('link:') || spec.startsWith('workspace:'))
|
|
763
|
+
return true;
|
|
764
|
+
if (!spec.startsWith('file:'))
|
|
765
|
+
return false;
|
|
766
|
+
// Tarballs are already pre-packaged libraries — install extracts them
|
|
767
|
+
// into a normal node_modules entry.
|
|
768
|
+
if (/\.t(?:ar\.)?gz(?:[?#].*)?$/.test(spec))
|
|
769
|
+
return false;
|
|
770
|
+
// Directory file: refs need a deeper check: peek at the installed
|
|
771
|
+
// package.json and ask "does this ship compiled JS?". If yes, vendor
|
|
772
|
+
// it. If no (TS source only), defer to the regular Vite pipeline.
|
|
773
|
+
return !packageHasCompiledJsEntry(name, projectRequire, platform);
|
|
774
|
+
}
|
|
775
|
+
function packageHasCompiledJsEntry(name, projectRequire, platform) {
|
|
776
|
+
let pkgJsonPath;
|
|
777
|
+
try {
|
|
778
|
+
pkgJsonPath = projectRequire.resolve(`${name}/package.json`);
|
|
779
|
+
}
|
|
780
|
+
catch {
|
|
781
|
+
return false;
|
|
782
|
+
}
|
|
783
|
+
let pkg;
|
|
784
|
+
try {
|
|
785
|
+
pkg = JSON.parse(readFileSync(pkgJsonPath, 'utf-8'));
|
|
786
|
+
}
|
|
787
|
+
catch {
|
|
788
|
+
return false;
|
|
789
|
+
}
|
|
790
|
+
const pkgDir = path.dirname(pkgJsonPath);
|
|
791
|
+
const candidates = [];
|
|
792
|
+
const pushCandidate = (value) => {
|
|
793
|
+
if (typeof value === 'string' && value)
|
|
794
|
+
candidates.push(value);
|
|
795
|
+
};
|
|
796
|
+
pushCandidate(pkg.module);
|
|
797
|
+
pushCandidate(pkg.main);
|
|
798
|
+
// Recursively flatten conditional `exports` maps to surface concrete
|
|
799
|
+
// file paths. We only need `string` leaves; anything else (function-
|
|
800
|
+
// based exports, etc.) doesn't apply to esbuild's resolution.
|
|
801
|
+
const visitExports = (node) => {
|
|
802
|
+
if (!node)
|
|
803
|
+
return;
|
|
804
|
+
if (typeof node === 'string') {
|
|
805
|
+
pushCandidate(node);
|
|
806
|
+
return;
|
|
807
|
+
}
|
|
808
|
+
if (Array.isArray(node)) {
|
|
809
|
+
for (const item of node)
|
|
810
|
+
visitExports(item);
|
|
811
|
+
return;
|
|
812
|
+
}
|
|
813
|
+
if (typeof node === 'object') {
|
|
814
|
+
for (const value of Object.values(node))
|
|
815
|
+
visitExports(value);
|
|
816
|
+
}
|
|
817
|
+
};
|
|
818
|
+
visitExports(pkg.exports);
|
|
819
|
+
if (candidates.length === 0) {
|
|
820
|
+
// node's default lookup falls back to `index.js`.
|
|
821
|
+
candidates.push('index');
|
|
822
|
+
}
|
|
823
|
+
const extensionsToTry = compiledJsExtensionsForPlatform(platform);
|
|
824
|
+
for (const cand of candidates) {
|
|
825
|
+
const abs = path.resolve(pkgDir, cand);
|
|
826
|
+
const ext = path.extname(cand);
|
|
827
|
+
if (COMPILED_JS_ENTRY_REGEX.test(cand)) {
|
|
828
|
+
// Explicit JS extension. If the file exists, vendor it. If not
|
|
829
|
+
// (a NativeScript plugin commonly declares `main: "index.js"`
|
|
830
|
+
// but ships only platform variants like `index.ios.js`), try
|
|
831
|
+
// the platform-specific variants which esbuild's
|
|
832
|
+
// `resolveExtensions` will pick up at bundle time.
|
|
833
|
+
if (fs.existsSync(abs))
|
|
834
|
+
return true;
|
|
835
|
+
const baseAbs = abs.slice(0, -ext.length);
|
|
836
|
+
for (const e of extensionsToTry) {
|
|
837
|
+
if (fs.existsSync(baseAbs + e))
|
|
838
|
+
return true;
|
|
839
|
+
}
|
|
840
|
+
continue;
|
|
841
|
+
}
|
|
842
|
+
if (!ext) {
|
|
843
|
+
// Extensionless main — try plain JS variants AND the
|
|
844
|
+
// platform-specific variants NativeScript plugins commonly use
|
|
845
|
+
// (`index.ios.js`, `index.android.js`, `index.visionos.js`).
|
|
846
|
+
for (const e of extensionsToTry) {
|
|
847
|
+
if (fs.existsSync(abs + e))
|
|
848
|
+
return true;
|
|
849
|
+
}
|
|
850
|
+
continue;
|
|
851
|
+
}
|
|
852
|
+
// A non-JS extension (typically `.ts`/`.tsx`) means the package
|
|
853
|
+
// only ships TS source — esbuild's vendor pipeline can't resolve
|
|
854
|
+
// any tsconfig-aliased imports inside it.
|
|
855
|
+
}
|
|
856
|
+
return false;
|
|
857
|
+
}
|
|
858
|
+
export const __test_collectVendorModules = collectVendorModules;
|
|
859
|
+
export const __test_createVendorBundleRuntimeModule = createVendorBundleRuntimeModule;
|
|
860
|
+
export const __test_isUnvendorableLocalSource = isUnvendorableLocalSource;
|
|
861
|
+
export const __test_packageHasCompiledJsEntry = packageHasCompiledJsEntry;
|
|
862
|
+
function canResolveDependencyPackageJson(specifier, projectRequire) {
|
|
863
|
+
try {
|
|
864
|
+
projectRequire.resolve(`${specifier}/package.json`);
|
|
865
|
+
return true;
|
|
866
|
+
}
|
|
867
|
+
catch {
|
|
868
|
+
return false;
|
|
869
|
+
}
|
|
870
|
+
}
|
|
410
871
|
function readDependencyPackageJson(specifier, projectRequire) {
|
|
411
872
|
try {
|
|
412
873
|
const packageJsonPath = projectRequire.resolve(`${specifier}/package.json`);
|
|
@@ -437,6 +898,12 @@ function createVendorEntry(entries) {
|
|
|
437
898
|
const modules = entries.map((specifier, index) => `${JSON.stringify(specifier)}: __nsVendor_${index}`).join(',\n ');
|
|
438
899
|
return `${imports}\n\nexport const __nsVendorModuleMap = {\n ${modules}\n};\n`;
|
|
439
900
|
}
|
|
901
|
+
function createVendorBundleRuntimeModule(result) {
|
|
902
|
+
return `${result.code}
|
|
903
|
+
export const vendorManifest = ${JSON.stringify(result.manifest)};
|
|
904
|
+
export default vendorManifest;
|
|
905
|
+
`;
|
|
906
|
+
}
|
|
440
907
|
function resolveExtensionsForPlatform(platform) {
|
|
441
908
|
const base = ['.tsx', '.jsx', '.ts', '.js', '.mjs', '.cjs', '.json'];
|
|
442
909
|
const extensions = new Set(base);
|
|
@@ -518,10 +985,7 @@ function createVendorEsbuildPlugin(projectRoot) {
|
|
|
518
985
|
// @angular/platform-browser/animations -> provide concrete named stubs
|
|
519
986
|
build.onResolve({ filter: /^@angular\/platform-browser\/animations(?:\/.*)?$/ }, (args) => {
|
|
520
987
|
if (debug) {
|
|
521
|
-
|
|
522
|
-
console.log('[vendor] map', args.path, '->', PB_ANIMATIONS_ID);
|
|
523
|
-
}
|
|
524
|
-
catch { }
|
|
988
|
+
console.log('[vendor] map', args.path, '->', PB_ANIMATIONS_ID);
|
|
525
989
|
}
|
|
526
990
|
return { path: PB_ANIMATIONS_ID, namespace: 'ns-vendor' };
|
|
527
991
|
});
|
|
@@ -547,10 +1011,7 @@ function createVendorEsbuildPlugin(projectRoot) {
|
|
|
547
1011
|
// @angular/animations/browser -> provide ɵ* engine/renderer/style normalizer stubs
|
|
548
1012
|
build.onResolve({ filter: /^@angular\/animations\/browser(?:\/.*)?$/ }, (args) => {
|
|
549
1013
|
if (debug) {
|
|
550
|
-
|
|
551
|
-
console.log('[vendor] map', args.path, '->', ANIMATIONS_BROWSER_ID);
|
|
552
|
-
}
|
|
553
|
-
catch { }
|
|
1014
|
+
console.log('[vendor] map', args.path, '->', ANIMATIONS_BROWSER_ID);
|
|
554
1015
|
}
|
|
555
1016
|
return { path: ANIMATIONS_BROWSER_ID, namespace: 'ns-vendor' };
|
|
556
1017
|
});
|
|
@@ -572,10 +1033,7 @@ function createVendorEsbuildPlugin(projectRoot) {
|
|
|
572
1033
|
// Keep generic mapping for @angular/animations base; /browser is handled above
|
|
573
1034
|
{ filter: /^@angular\/animations(?:$|\/)$/ }, (args) => {
|
|
574
1035
|
if (debug) {
|
|
575
|
-
|
|
576
|
-
console.log('[vendor] map', args.path, '->', ANIMATIONS_ID);
|
|
577
|
-
}
|
|
578
|
-
catch { }
|
|
1036
|
+
console.log('[vendor] map', args.path, '->', ANIMATIONS_ID);
|
|
579
1037
|
}
|
|
580
1038
|
return { path: ANIMATIONS_ID, namespace: 'ns-vendor' };
|
|
581
1039
|
});
|
|
@@ -606,6 +1064,63 @@ function createVendorEsbuildPlugin(projectRoot) {
|
|
|
606
1064
|
},
|
|
607
1065
|
};
|
|
608
1066
|
}
|
|
1067
|
+
/**
|
|
1068
|
+
* esbuild plugin to compile .jsx/.tsx files from Solid packages through
|
|
1069
|
+
* babel-preset-solid. Without this, esbuild uses its default React JSX
|
|
1070
|
+
* transform, producing React.createElement calls that crash at runtime.
|
|
1071
|
+
*
|
|
1072
|
+
* Only applied to files inside node_modules that have .jsx or .tsx extension.
|
|
1073
|
+
*/
|
|
1074
|
+
function createSolidJsxEsbuildPlugin(projectRoot) {
|
|
1075
|
+
// Lazy-load Babel and the Solid preset so they're only required when
|
|
1076
|
+
// the Solid flavor is active.
|
|
1077
|
+
let babel;
|
|
1078
|
+
let solidPreset;
|
|
1079
|
+
return {
|
|
1080
|
+
name: 'ns-vendor-solid-jsx',
|
|
1081
|
+
setup(build) {
|
|
1082
|
+
// Intercept .jsx and .tsx files from node_modules
|
|
1083
|
+
build.onLoad({ filter: /node_modules\/.*\.[jt]sx$/ }, async (args) => {
|
|
1084
|
+
try {
|
|
1085
|
+
if (!babel) {
|
|
1086
|
+
babel = await import('@babel/core');
|
|
1087
|
+
// babel-preset-solid is the standard Solid JSX transform
|
|
1088
|
+
solidPreset = (await import('babel-preset-solid')).default;
|
|
1089
|
+
}
|
|
1090
|
+
const source = await readFile(args.path, 'utf-8');
|
|
1091
|
+
const result = await babel.transformAsync(source, {
|
|
1092
|
+
filename: args.path,
|
|
1093
|
+
presets: [
|
|
1094
|
+
[
|
|
1095
|
+
solidPreset,
|
|
1096
|
+
{
|
|
1097
|
+
generate: 'universal',
|
|
1098
|
+
hydratable: false,
|
|
1099
|
+
moduleName: '@nativescript-community/solid-js',
|
|
1100
|
+
},
|
|
1101
|
+
],
|
|
1102
|
+
],
|
|
1103
|
+
parserOpts: {
|
|
1104
|
+
plugins: ['jsx', ...(args.path.endsWith('.tsx') ? ['typescript'] : [])],
|
|
1105
|
+
},
|
|
1106
|
+
ast: false,
|
|
1107
|
+
sourceMaps: false,
|
|
1108
|
+
configFile: false,
|
|
1109
|
+
babelrc: false,
|
|
1110
|
+
});
|
|
1111
|
+
if (result?.code) {
|
|
1112
|
+
return { contents: result.code, loader: 'js' };
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
catch (e) {
|
|
1116
|
+
console.warn(`[ns-vendor-solid-jsx] failed to transform ${args.path}:`, e?.message || e);
|
|
1117
|
+
}
|
|
1118
|
+
// Fall through to esbuild's default handling
|
|
1119
|
+
return undefined;
|
|
1120
|
+
});
|
|
1121
|
+
},
|
|
1122
|
+
};
|
|
1123
|
+
}
|
|
609
1124
|
/**
|
|
610
1125
|
* Minimal esbuild plugin to run Angular linker (Babel) over partial-compiled
|
|
611
1126
|
* Angular packages in node_modules. This converts ɵɵngDeclare* calls into
|
|
@@ -615,6 +1130,7 @@ function angularLinkerEsbuildPlugin(projectRoot) {
|
|
|
615
1130
|
// Lazily resolve Babel and Angular linker from the project to avoid hard deps
|
|
616
1131
|
let babel = null;
|
|
617
1132
|
let createLinker = null;
|
|
1133
|
+
let angularFileSystem = null;
|
|
618
1134
|
async function ensureDeps() {
|
|
619
1135
|
if (babel && createLinker)
|
|
620
1136
|
return;
|
|
@@ -639,6 +1155,40 @@ function angularLinkerEsbuildPlugin(projectRoot) {
|
|
|
639
1155
|
}
|
|
640
1156
|
catch { }
|
|
641
1157
|
}
|
|
1158
|
+
// Angular 21+ requires a fileSystem for the linker plugin
|
|
1159
|
+
if (!angularFileSystem) {
|
|
1160
|
+
try {
|
|
1161
|
+
const req = createRequire(projectRoot + '/package.json');
|
|
1162
|
+
const cliPath = req.resolve('@angular/compiler-cli');
|
|
1163
|
+
const cliMod = await import(cliPath);
|
|
1164
|
+
if (cliMod.NodeJSFileSystem) {
|
|
1165
|
+
angularFileSystem = new cliMod.NodeJSFileSystem();
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
catch { }
|
|
1169
|
+
if (!angularFileSystem) {
|
|
1170
|
+
try {
|
|
1171
|
+
const cliMod = await import('@angular/compiler-cli');
|
|
1172
|
+
if (cliMod.NodeJSFileSystem) {
|
|
1173
|
+
angularFileSystem = new cliMod.NodeJSFileSystem();
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
1176
|
+
catch { }
|
|
1177
|
+
}
|
|
1178
|
+
if (!angularFileSystem) {
|
|
1179
|
+
// Minimal fallback
|
|
1180
|
+
const nodePath = await import('node:path');
|
|
1181
|
+
const nodeFs = await import('node:fs');
|
|
1182
|
+
angularFileSystem = {
|
|
1183
|
+
resolve: (...paths) => nodePath.resolve(...paths),
|
|
1184
|
+
dirname: (p) => nodePath.dirname(p),
|
|
1185
|
+
join: (...paths) => nodePath.join(...paths),
|
|
1186
|
+
isRooted: (p) => nodePath.isAbsolute(p),
|
|
1187
|
+
exists: (p) => nodeFs.existsSync(p),
|
|
1188
|
+
readFile: (p) => nodeFs.readFileSync(p, 'utf8'),
|
|
1189
|
+
};
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
642
1192
|
}
|
|
643
1193
|
// Restrict to Angular framework packages to minimize esbuild memory usage.
|
|
644
1194
|
const FILTER = /node_modules\/(?:@angular|@nativescript\/angular)\/.*\.[mc]?js$/;
|
|
@@ -659,15 +1209,11 @@ function angularLinkerEsbuildPlugin(projectRoot) {
|
|
|
659
1209
|
return { contents: source, loader: 'js' };
|
|
660
1210
|
}
|
|
661
1211
|
const plugin = createLinker({
|
|
662
|
-
// Link everything the filter captures; plugin will no-op otherwise
|
|
663
|
-
// shouldLink is inferred by plugin when left unset for Babel version
|
|
664
1212
|
sourceMapping: false,
|
|
1213
|
+
fileSystem: angularFileSystem,
|
|
665
1214
|
});
|
|
666
1215
|
if (debug) {
|
|
667
|
-
|
|
668
|
-
console.log('[ns-angular-linker][vendor] linking', args.path);
|
|
669
|
-
}
|
|
670
|
-
catch { }
|
|
1216
|
+
console.log('[ns-angular-linker][vendor] linking', args.path);
|
|
671
1217
|
}
|
|
672
1218
|
const result = await babel.transformAsync(source, {
|
|
673
1219
|
filename: args.path,
|
|
@@ -773,15 +1319,84 @@ function normalizeSpecifier(spec) {
|
|
|
773
1319
|
return value;
|
|
774
1320
|
}
|
|
775
1321
|
|
|
1322
|
+
function normalizeCoreSubLocal(s) {
|
|
1323
|
+
if (!s) return "";
|
|
1324
|
+
let t = String(s).split("?")[0].split("#")[0].trim();
|
|
1325
|
+
t = t.replace(/^\\/+/, "").replace(/\\/+$/, "");
|
|
1326
|
+
t = t.replace(/\\.(?:mjs|cjs|js)$/, "");
|
|
1327
|
+
if (t.length >= 6 && t.substring(t.length - 6) === "/index") {
|
|
1328
|
+
t = t.substring(0, t.length - 6);
|
|
1329
|
+
}
|
|
1330
|
+
if (!t || t === "index") return "";
|
|
1331
|
+
return t;
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1334
|
+
// Invariant D: shape ESM namespaces before returning to CJS callers.
|
|
1335
|
+
//
|
|
1336
|
+
// The /ns/core handler's registration footer (see websocket.ts) and the
|
|
1337
|
+
// main-entry require shim (see helpers/main-entry.ts) both install the
|
|
1338
|
+
// shape function on globalThis. In practice, entries stored in
|
|
1339
|
+
// __NS_CORE_MODULES__ are ALREADY shaped, so this pass-through is a
|
|
1340
|
+
// fast no-op (the shape function's fast path returns obj as-is when it
|
|
1341
|
+
// already has Object.prototype). We call it anyway as defense-in-depth
|
|
1342
|
+
// against future callers that might populate the registry without
|
|
1343
|
+
// shaping.
|
|
1344
|
+
function shapeForCjs(value) {
|
|
1345
|
+
if (!value || typeof value !== "object") return value;
|
|
1346
|
+
const shape = g.__NS_CJS_SHAPE__;
|
|
1347
|
+
if (typeof shape === "function") {
|
|
1348
|
+
try { return shape(value); } catch (e) {}
|
|
1349
|
+
}
|
|
1350
|
+
return value;
|
|
1351
|
+
}
|
|
1352
|
+
|
|
1353
|
+
function resolveCoreFromRegistry(normalizedId) {
|
|
1354
|
+
if (
|
|
1355
|
+
normalizedId !== "@nativescript/core" &&
|
|
1356
|
+
normalizedId.indexOf("@nativescript/core/") !== 0
|
|
1357
|
+
) {
|
|
1358
|
+
return null;
|
|
1359
|
+
}
|
|
1360
|
+
const table = g.__NS_CORE_MODULES__;
|
|
1361
|
+
if (!table) return null;
|
|
1362
|
+
if (table[normalizedId]) return shapeForCjs(table[normalizedId]);
|
|
1363
|
+
const rawSub =
|
|
1364
|
+
normalizedId === "@nativescript/core"
|
|
1365
|
+
? ""
|
|
1366
|
+
: normalizedId.slice("@nativescript/core/".length);
|
|
1367
|
+
const normSub = normalizeCoreSubLocal(rawSub);
|
|
1368
|
+
const bareKey = normSub ? "@nativescript/core/" + normSub : "@nativescript/core";
|
|
1369
|
+
if (table[bareKey]) return shapeForCjs(table[bareKey]);
|
|
1370
|
+
if (normSub && table[normSub]) return shapeForCjs(table[normSub]);
|
|
1371
|
+
if (!normSub && table[""]) return shapeForCjs(table[""]);
|
|
1372
|
+
return null;
|
|
1373
|
+
}
|
|
1374
|
+
|
|
776
1375
|
export function createRequire(_url) {
|
|
777
1376
|
const nsRequire = getNativeScriptRequire();
|
|
778
1377
|
if (!nsRequire) {
|
|
779
|
-
return function () {
|
|
1378
|
+
return function (id) {
|
|
1379
|
+
// Even without nsRequire, the @nativescript/core registry populated by
|
|
1380
|
+
// the /ns/core bridge may already have the module — return it so
|
|
1381
|
+
// vendor install() hooks that run against the HMR-served core don't
|
|
1382
|
+
// crash at module-instantiation time.
|
|
1383
|
+
const fromRegistry = resolveCoreFromRegistry(normalizeSpecifier(id));
|
|
1384
|
+
if (fromRegistry) return fromRegistry;
|
|
780
1385
|
throw new Error("NativeScript require() is not available in this context");
|
|
781
1386
|
};
|
|
782
1387
|
}
|
|
783
1388
|
const req = function (id) {
|
|
784
1389
|
const normalizedId = normalizeSpecifier(id);
|
|
1390
|
+
// Invariant C: @nativescript/core and its subpaths are served ONCE via
|
|
1391
|
+
// the /ns/core HTTP bridge, which self-registers each module's ESM
|
|
1392
|
+
// namespace on globalThis.__NS_CORE_MODULES__. CommonJS require() from
|
|
1393
|
+
// vendor packages (e.g. \`require('@nativescript/core/ui/core/view').View\`
|
|
1394
|
+
// in @nativescript-community/gesturehandler, or \`require('@nativescript/core').View\`
|
|
1395
|
+
// in @nativescript-community/ui-material-core) MUST resolve to that
|
|
1396
|
+
// same namespace; otherwise we re-trigger class identity splits and
|
|
1397
|
+
// applyMixins() crashes with "Cannot read properties of undefined".
|
|
1398
|
+
const fromRegistry = resolveCoreFromRegistry(normalizedId);
|
|
1399
|
+
if (fromRegistry) return fromRegistry;
|
|
785
1400
|
if (
|
|
786
1401
|
normalizedId.includes("../data/patch.json") ||
|
|
787
1402
|
normalizedId.includes("css-tree/lib/data/patch.json")
|
|
@@ -804,7 +1419,12 @@ export function createRequire(_url) {
|
|
|
804
1419
|
if (normalizedId.endsWith(".json")) {
|
|
805
1420
|
return {};
|
|
806
1421
|
}
|
|
807
|
-
|
|
1422
|
+
// Shape the native require result too. The NativeScript CJS loader
|
|
1423
|
+
// may serve an @nativescript/core subpath over HTTP before the
|
|
1424
|
+
// /ns/core footer has run (e.g., during initial boot). In that
|
|
1425
|
+
// window, the result is a raw ESM namespace with null [[Prototype]]
|
|
1426
|
+
// and zone.js/vendor install() hooks crash on hasOwnProperty.
|
|
1427
|
+
return shapeForCjs(nsRequire(normalizedId));
|
|
808
1428
|
};
|
|
809
1429
|
req.resolve = nsRequire.resolve
|
|
810
1430
|
? function (id) {
|