@nativescript/vite 8.0.0-alpha.28 → 8.0.0-alpha.29
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.js +26 -128
- package/configuration/angular.js.map +1 -1
- package/configuration/base.js.map +1 -1
- package/configuration/javascript.js +5 -72
- package/configuration/javascript.js.map +1 -1
- package/configuration/typescript.js +4 -74
- package/configuration/typescript.js.map +1 -1
- package/helpers/angular/angular-linker.d.ts +5 -6
- package/helpers/angular/angular-linker.js +31 -110
- package/helpers/angular/angular-linker.js.map +1 -1
- package/helpers/angular/inject-component-hmr-registration.js +2 -70
- package/helpers/angular/inject-component-hmr-registration.js.map +1 -1
- package/helpers/angular/inject-hmr-vite-ignore.js +2 -69
- package/helpers/angular/inject-hmr-vite-ignore.js.map +1 -1
- package/helpers/angular/inline-decorator-component-templates.js +1 -170
- package/helpers/angular/inline-decorator-component-templates.js.map +1 -1
- package/helpers/angular/js-lexer.d.ts +4 -0
- package/helpers/angular/js-lexer.js +182 -0
- package/helpers/angular/js-lexer.js.map +1 -0
- package/helpers/angular/shared-linker.d.ts +31 -3
- package/helpers/angular/shared-linker.js +67 -14
- package/helpers/angular/shared-linker.js.map +1 -1
- package/helpers/angular/synthesize-decorator-ctor-parameters.js +2 -170
- package/helpers/angular/synthesize-decorator-ctor-parameters.js.map +1 -1
- package/helpers/angular/synthesize-injectable-factories.js +1 -174
- package/helpers/angular/synthesize-injectable-factories.js.map +1 -1
- package/helpers/app-components.d.ts +2 -1
- package/helpers/app-components.js.map +1 -1
- package/helpers/app-css-state.d.ts +8 -0
- package/helpers/app-css-state.js +8 -0
- package/helpers/app-css-state.js.map +1 -0
- package/helpers/bundler-context.d.ts +11 -0
- package/helpers/bundler-context.js +71 -0
- package/helpers/bundler-context.js.map +1 -0
- package/helpers/dev-host.d.ts +2 -1
- package/helpers/dev-host.js.map +1 -1
- package/helpers/main-entry.js +2 -3
- package/helpers/main-entry.js.map +1 -1
- package/helpers/nativeclass-esbuild-plugin.d.ts +2 -1
- package/helpers/nativeclass-esbuild-plugin.js.map +1 -1
- package/helpers/nativeclass-transform.js.map +1 -1
- package/helpers/platform-types.d.ts +2 -0
- package/helpers/platform-types.js +2 -0
- package/helpers/platform-types.js.map +1 -0
- package/helpers/prelink-angular.js +11 -29
- package/helpers/prelink-angular.js.map +1 -1
- package/helpers/typescript-check.d.ts +2 -1
- package/helpers/typescript-check.js.map +1 -1
- package/helpers/workers.js +1 -1
- package/helpers/workers.js.map +1 -1
- package/hmr/client/css-handler.js +1 -17
- package/hmr/client/css-handler.js.map +1 -1
- package/hmr/client/utils.d.ts +1 -1
- package/hmr/client/utils.js +15 -59
- package/hmr/client/utils.js.map +1 -1
- package/hmr/frameworks/angular/server/strategy.js +3 -14
- package/hmr/frameworks/angular/server/strategy.js.map +1 -1
- package/hmr/frameworks/solid/server/strategy.js +3 -18
- package/hmr/frameworks/solid/server/strategy.js.map +1 -1
- package/hmr/frameworks/typescript/server/strategy.js +2 -15
- package/hmr/frameworks/typescript/server/strategy.js.map +1 -1
- package/hmr/frameworks/vue/client/index.js +0 -154
- package/hmr/frameworks/vue/client/index.js.map +1 -1
- package/hmr/server/core-sanitize.d.ts +3 -4
- package/hmr/server/core-sanitize.js +3 -4
- package/hmr/server/core-sanitize.js.map +1 -1
- package/hmr/server/framework-strategy.d.ts +9 -19
- package/hmr/server/vendor-bare-module-shims.d.ts +4 -0
- package/hmr/server/vendor-bare-module-shims.js +80 -0
- package/hmr/server/vendor-bare-module-shims.js.map +1 -0
- package/hmr/server/websocket-angular-entry.js +1 -1
- package/hmr/server/websocket-angular-entry.js.map +1 -1
- package/hmr/server/websocket-module-bindings.js +1 -1
- package/hmr/server/websocket-module-bindings.js.map +1 -1
- package/hmr/server/websocket-served-module-helpers.d.ts +4 -1
- package/hmr/server/websocket-served-module-helpers.js +19 -9
- package/hmr/server/websocket-served-module-helpers.js.map +1 -1
- package/hmr/server/websocket-vue-sfc.js +3 -3
- package/hmr/server/websocket-vue-sfc.js.map +1 -1
- package/hmr/server/websocket.d.ts +10 -33
- package/hmr/server/websocket.js +31 -755
- package/hmr/server/websocket.js.map +1 -1
- package/hmr/shared/runtime/dev-overlay-snapshots.d.ts +31 -0
- package/hmr/shared/runtime/dev-overlay-snapshots.js +324 -0
- package/hmr/shared/runtime/dev-overlay-snapshots.js.map +1 -0
- package/hmr/shared/runtime/dev-overlay.d.ts +3 -29
- package/hmr/shared/runtime/dev-overlay.js +3 -330
- package/hmr/shared/runtime/dev-overlay.js.map +1 -1
- package/hmr/shared/runtime/root-placeholder.js +9 -33
- package/hmr/shared/runtime/root-placeholder.js.map +1 -1
- package/hmr/shared/vendor/manifest.js +5 -82
- package/hmr/shared/vendor/manifest.js.map +1 -1
- package/package.json +53 -11
- package/hmr/server/websocket-ns-m-finalize.d.ts +0 -22
- package/hmr/server/websocket-ns-m-finalize.js +0 -88
- package/hmr/server/websocket-ns-m-finalize.js.map +0 -1
package/hmr/server/websocket.js
CHANGED
|
@@ -32,6 +32,8 @@ import { typescriptServerStrategy } from '../frameworks/typescript/server/strate
|
|
|
32
32
|
import { buildInlineTemplateBlock, createProcessSfcCode, extractTemplateRender, processTemplateVariantMinimal } from '../frameworks/vue/server/sfc-transforms.js';
|
|
33
33
|
import { astExtractImportsAndStripTypes } from '../helpers/ast-extract.js';
|
|
34
34
|
import { getProjectAppPath, getProjectAppRelativePath, getProjectAppVirtualPath } from '../../helpers/utils.js';
|
|
35
|
+
import { getAppCssState } from '../../helpers/app-css-state.js';
|
|
36
|
+
import { buildVueVendorShim, buildPiniaVendorShim } from './vendor-bare-module-shims.js';
|
|
35
37
|
import { buildRuntimeConfig, generateImportMap } from './import-map.js';
|
|
36
38
|
import { getCliFlags } from '../../helpers/cli-flags.js';
|
|
37
39
|
import { buildCoreUrl, buildCoreUrlPath, normalizeCoreSub as normalizeCoreSubCanonical } from '../../helpers/ns-core-url.js';
|
|
@@ -47,10 +49,11 @@ import { classifyBootRoute, classifyHmrUpdateKind, createColdBootRequestCounter,
|
|
|
47
49
|
import { createHmrPendingMessage } from './websocket-hmr-pending.js';
|
|
48
50
|
import { extractVitePrebundleId, filterExistingNodeModulesTransformCandidates, getBlockedDeviceNodeModulesReason, getFlattenedManifestMap, isCoreGlobalsReference, isEsmFrameworkPackageSpecifier, isLikelyNativeScriptPluginSpecifier, isLikelyNativeScriptRuntimePluginSpecifier, isNativeScriptCoreModule, isNativeScriptPluginModule, normalizeNativeScriptCoreSpecifier, normalizeNodeModulesSpecifier, resolveCandidateFilePath, resolveInternalRuntimePluginBareSpecifier, resolveNodeModulesPackageBoundary, resolveVendorFromCandidate, resolveVendorRouting, rewriteFsAbsoluteToNsM, shouldPreserveBareRuntimePluginSubpathImport, stripDecoratedServePrefixes, tryReadRawExplicitJavaScriptModule, viteDepsPathToBareSpecifier, } from './websocket-module-specifiers.js';
|
|
49
51
|
import { ensureNativeScriptModuleBindings, getProcessCodeResolvedSpecifierOverrides } from './websocket-module-bindings.js';
|
|
50
|
-
import { collectStaticExportNamesFromFile, collectStaticExportOriginsFromFile,
|
|
52
|
+
import { collectStaticExportNamesFromFile, collectStaticExportOriginsFromFile, normalizeCoreExportOriginsForRuntime, parseCoreBridgeRequest, resolveRuntimeCoreModulePath } from './websocket-core-bridge.js';
|
|
51
53
|
import { createSharedTransformRequestRunner } from './shared-transform-request.js';
|
|
52
54
|
import { formatNsMHmrServeTag, getNumericServeVersionTag, rewriteNsMImportPathForHmr } from './websocket-ns-m-paths.js';
|
|
53
|
-
import { ensureDynamicHmrImportHelper } from './websocket-served-module-helpers.js';
|
|
55
|
+
import { assertNoOptimizedArtifacts, buildBootProgressSnippet, collectTopLevelImportRecords, deduplicateLinkerImports, dedupeRtNamedImportsAgainstDestructures, ensureDestructureCoreImports, ensureDestructureRtImports, ensureDynamicHmrImportHelper, ensureGuardPlainDynamicImports, ensureVariableDynamicImportHelper, ensureVersionedRtImports, expandStarExports, extractExportMetadata, hoistTopLevelStaticImports, MODULE_IMPORT_ANALYSIS_PLUGINS, repairImportEqualsAssignments, stripCoreGlobalsImports, stripViteDynamicImportVirtual, wrapCommonJsModuleForDevice, } from './websocket-served-module-helpers.js';
|
|
56
|
+
export { buildBootProgressSnippet, wrapCommonJsModuleForDevice };
|
|
54
57
|
export { ensureNativeScriptModuleBindings, getProcessCodeResolvedSpecifierOverrides } from './websocket-module-bindings.js';
|
|
55
58
|
export { stripDecoratedServePrefixes, tryReadRawExplicitJavaScriptModule } from './websocket-module-specifiers.js';
|
|
56
59
|
export { collectStaticExportNamesFromFile, collectStaticExportOriginsFromFile, normalizeCoreExportOriginsForRuntime, parseCoreBridgeRequest } from './websocket-core-bridge.js';
|
|
@@ -166,9 +169,6 @@ function getHmrSocketRole(client) {
|
|
|
166
169
|
}
|
|
167
170
|
return typeof client.__nsHmrClientRole === 'string' && client.__nsHmrClientRole ? client.__nsHmrClientRole : 'unknown';
|
|
168
171
|
}
|
|
169
|
-
function shouldAllowLocalCoreSanitizerPaths(contextLabel) {
|
|
170
|
-
return /\bnode_modules\/@nativescript\/vite\/hmr\/(?:client|frameworks)\//.test(contextLabel);
|
|
171
|
-
}
|
|
172
172
|
export function prepareAngularEntryForDevice(code, importerPath, sfcFileMap, depFileMap, projectRoot, verbose = false, outputDirOverrideRel, httpOrigin, resolveVendorAsHttp = false) {
|
|
173
173
|
const rewrittenCode = rewriteImports(code, importerPath, sfcFileMap, depFileMap, projectRoot, verbose, outputDirOverrideRel, httpOrigin, resolveVendorAsHttp);
|
|
174
174
|
return rewriteAngularEntryRegisterOnly(rewrittenCode, resolveAngularCoreHmrImportSource(rewrittenCode, httpOrigin));
|
|
@@ -177,74 +177,6 @@ const processSfcCode = createProcessSfcCode(processCodeForDevice);
|
|
|
177
177
|
// Bare specifiers and special skip patterns (virtual, data:, etc.)
|
|
178
178
|
const VENDOR_PACKAGES = /^[A-Za-z@][^:\/\s]*$/;
|
|
179
179
|
const SKIP_PATTERNS = /^(?:data:|blob:|node:|virtual:|vite:|\0|\/@@?id|\/__vite|__vite|__x00__)/;
|
|
180
|
-
const MODULE_IMPORT_ANALYSIS_PLUGINS = ['typescript', 'jsx', 'importMeta', 'topLevelAwait', 'classProperties', 'classPrivateProperties', 'classPrivateMethods', 'decorators-legacy'];
|
|
181
|
-
function collectTopLevelImportRecords(code) {
|
|
182
|
-
if (!code || typeof code !== 'string' || !/\bimport\b/.test(code)) {
|
|
183
|
-
return [];
|
|
184
|
-
}
|
|
185
|
-
try {
|
|
186
|
-
const ast = babelParse(code, {
|
|
187
|
-
sourceType: 'module',
|
|
188
|
-
plugins: MODULE_IMPORT_ANALYSIS_PLUGINS,
|
|
189
|
-
});
|
|
190
|
-
const body = ast?.program?.body;
|
|
191
|
-
if (!Array.isArray(body)) {
|
|
192
|
-
return [];
|
|
193
|
-
}
|
|
194
|
-
return body
|
|
195
|
-
.filter((node) => t.isImportDeclaration(node) && typeof node.start === 'number' && typeof node.end === 'number' && typeof node.source?.value === 'string')
|
|
196
|
-
.map((node) => ({
|
|
197
|
-
start: node.start,
|
|
198
|
-
end: node.end,
|
|
199
|
-
text: code.slice(node.start, node.end),
|
|
200
|
-
source: node.source.value,
|
|
201
|
-
hasOnlyNamedSpecifiers: Array.isArray(node.specifiers) && node.specifiers.length > 0 && node.specifiers.every((spec) => t.isImportSpecifier(spec)),
|
|
202
|
-
namedBindings: Array.isArray(node.specifiers)
|
|
203
|
-
? node.specifiers
|
|
204
|
-
.filter((spec) => t.isImportSpecifier(spec) && typeof spec.start === 'number' && typeof spec.end === 'number')
|
|
205
|
-
.map((spec) => ({
|
|
206
|
-
importedName: t.isIdentifier(spec.imported) ? spec.imported.name : String(spec.imported?.value || ''),
|
|
207
|
-
text: code.slice(spec.start, spec.end),
|
|
208
|
-
}))
|
|
209
|
-
: [],
|
|
210
|
-
}));
|
|
211
|
-
}
|
|
212
|
-
catch {
|
|
213
|
-
return [];
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
function hoistTopLevelStaticImports(code) {
|
|
217
|
-
const imports = collectTopLevelImportRecords(code);
|
|
218
|
-
if (!imports.length) {
|
|
219
|
-
return code;
|
|
220
|
-
}
|
|
221
|
-
let stripped = code;
|
|
222
|
-
for (const imp of [...imports].sort((left, right) => right.start - left.start)) {
|
|
223
|
-
stripped = stripped.slice(0, imp.start) + stripped.slice(imp.end);
|
|
224
|
-
}
|
|
225
|
-
const hoisted = [];
|
|
226
|
-
const seen = new Set();
|
|
227
|
-
for (const imp of imports) {
|
|
228
|
-
const text = imp.text.trim();
|
|
229
|
-
if (!text || seen.has(text)) {
|
|
230
|
-
continue;
|
|
231
|
-
}
|
|
232
|
-
seen.add(text);
|
|
233
|
-
hoisted.push(text);
|
|
234
|
-
}
|
|
235
|
-
if (!hoisted.length) {
|
|
236
|
-
return stripped;
|
|
237
|
-
}
|
|
238
|
-
return `${hoisted.join('\n')}\n${stripped.replace(/^\s*\n+/, '')}`;
|
|
239
|
-
}
|
|
240
|
-
// Duplicate of `websocket-served-module-helpers.ts::buildBootProgressSnippet`
|
|
241
|
-
// — both copies must stay in lock-step. See the canonical doc there for
|
|
242
|
-
// why the snippet must remain fully synchronous (top-level await on a
|
|
243
|
-
// boot-tagged module trips the iOS 10 s async-module deadline).
|
|
244
|
-
export function buildBootProgressSnippet(bootModuleLabel) {
|
|
245
|
-
const normalizedLabel = JSON.stringify(String(bootModuleLabel || '').replace(/\\/g, '/'));
|
|
246
|
-
return [`const __nsBootGlobal=globalThis;`, `try{if(!__nsBootGlobal.__NS_HMR_BOOT_COMPLETE__){__nsBootGlobal.__NS_HMR_BOOT_MODULE_COUNT__=Number(__nsBootGlobal.__NS_HMR_BOOT_MODULE_COUNT__||0)+1;__nsBootGlobal.__NS_HMR_BOOT_LAST_MODULE__=${normalizedLabel};}}catch(__nsBootErr){}`, ''].join('\n');
|
|
247
|
-
}
|
|
248
180
|
function rewriteVitePrebundleImportsForDevice(code, preserveVendorImports) {
|
|
249
181
|
const imports = collectTopLevelImportRecords(code);
|
|
250
182
|
if (!imports.length) {
|
|
@@ -333,145 +265,6 @@ function guardBareDynamicImports(code) {
|
|
|
333
265
|
return code;
|
|
334
266
|
}
|
|
335
267
|
}
|
|
336
|
-
function stripCoreGlobalsImports(code) {
|
|
337
|
-
const pattern = /^\s*(?:import\s+(?:[^'"\n]*from\s+)?|export\s+\*\s+from\s+)["'][^"']*(?:@nativescript(?:[/_-])core(?:[\/_-])globals|@nativescript_core_globals)[^"']*["'];?\s*$/gm;
|
|
338
|
-
return code.replace(pattern, '');
|
|
339
|
-
}
|
|
340
|
-
function ensureVariableDynamicImportHelper(code) {
|
|
341
|
-
if (!code.includes('__variableDynamicImportRuntimeHelper')) {
|
|
342
|
-
return code;
|
|
343
|
-
}
|
|
344
|
-
if (PAT.VARIABLE_DYNAMIC_IMPORT_HELPER_PATTERN.test(code)) {
|
|
345
|
-
return code;
|
|
346
|
-
}
|
|
347
|
-
const helper = `const __variableDynamicImportRuntimeHelper = (map, request, importMode) => {\n` +
|
|
348
|
-
` try { if (request === '@') { return import(new URL('/ns/m/__invalid_at__.mjs', import.meta.url).href); } } catch {}\n` +
|
|
349
|
-
` const loader = map && (map[request] || map[request?.replace(/\\\\/g, "/")]);\n` +
|
|
350
|
-
` if (!loader) {\n` +
|
|
351
|
-
` const error = new Error(\"Cannot dynamically import: \" + request);\n` +
|
|
352
|
-
` error.code = 'ERR_MODULE_NOT_FOUND';\n` +
|
|
353
|
-
` return Promise.reject(error);\n` +
|
|
354
|
-
` }\n` +
|
|
355
|
-
` try {\n` +
|
|
356
|
-
` return loader(importMode);\n` +
|
|
357
|
-
` } catch (err) {\n` +
|
|
358
|
-
` return Promise.reject(err);\n` +
|
|
359
|
-
` }\n` +
|
|
360
|
-
`};\n`;
|
|
361
|
-
return `${helper}${code}`;
|
|
362
|
-
}
|
|
363
|
-
function ensureGuardPlainDynamicImports(code, origin) {
|
|
364
|
-
try {
|
|
365
|
-
if (!code || !/\bimport\s*\(/.test(code))
|
|
366
|
-
return code;
|
|
367
|
-
const wrapper = `const __ns_import = (s) => { try { if (s === '@') { return import(new URL('/ns/m/__invalid_at__.mjs', import.meta.url).href); } } catch {} return import(s); }\n`;
|
|
368
|
-
const replaced = code.replace(/(^|[^\.\w$])import\s*\(/g, (_m, p1) => `${p1}__ns_import(`);
|
|
369
|
-
if (replaced !== code) {
|
|
370
|
-
return wrapper + replaced;
|
|
371
|
-
}
|
|
372
|
-
return code;
|
|
373
|
-
}
|
|
374
|
-
catch {
|
|
375
|
-
return code;
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
// `ensureDynamicHmrImportHelper` lives in
|
|
379
|
-
// `./websocket-served-module-helpers.js`. See that file for the
|
|
380
|
-
// architectural rationale and the current helper implementation.
|
|
381
|
-
async function expandStarExports(code, server, projectRoot, verbose, sharedTransformer) {
|
|
382
|
-
const STAR_RE = /^[ \t]*(export\s+\*\s+from\s+["'])([^"']+)(["'];?)[ \t]*$/gm;
|
|
383
|
-
let match;
|
|
384
|
-
const replacements = [];
|
|
385
|
-
while ((match = STAR_RE.exec(code)) !== null) {
|
|
386
|
-
const url = match[2];
|
|
387
|
-
if (!url.includes('/node_modules/'))
|
|
388
|
-
continue;
|
|
389
|
-
replacements.push({ full: match[0], url, prefix: match[1], suffix: match[3] });
|
|
390
|
-
}
|
|
391
|
-
if (!replacements.length)
|
|
392
|
-
return code;
|
|
393
|
-
// Pull target URLs through the shared runner when it's available so each
|
|
394
|
-
// node_modules path shares the 60s TTL cache with the main /ns/m pipeline
|
|
395
|
-
// and respects the global concurrency gate. Fan them out in parallel —
|
|
396
|
-
// this block used to be a serial `for await` loop, which dominated cold
|
|
397
|
-
// boot on apps with dozens of star-re-exports.
|
|
398
|
-
const transformer = sharedTransformer ?? ((url) => server.transformRequest(url));
|
|
399
|
-
const resolved = await Promise.all(replacements.map(async (rep) => {
|
|
400
|
-
try {
|
|
401
|
-
let vitePath = rep.url.replace(/^https?:\/\/[^/]+/, '');
|
|
402
|
-
vitePath = vitePath.replace(/^\/ns\/m\//, '/');
|
|
403
|
-
vitePath = vitePath.replace(/^\/__ns_boot__\/[^/]+/, '');
|
|
404
|
-
vitePath = vitePath.replace(/\/__ns_hmr__\/[^/]+/, '');
|
|
405
|
-
const result = await transformer(vitePath);
|
|
406
|
-
if (!result?.code)
|
|
407
|
-
return null;
|
|
408
|
-
const names = extractExportedNames(result.code);
|
|
409
|
-
if (!names.length)
|
|
410
|
-
return null;
|
|
411
|
-
if (verbose) {
|
|
412
|
-
console.log(`[ns/m] expanded export* -> ${names.length} names from ${vitePath}`);
|
|
413
|
-
}
|
|
414
|
-
return { rep, names };
|
|
415
|
-
}
|
|
416
|
-
catch {
|
|
417
|
-
return null;
|
|
418
|
-
}
|
|
419
|
-
}));
|
|
420
|
-
for (const entry of resolved) {
|
|
421
|
-
if (!entry)
|
|
422
|
-
continue;
|
|
423
|
-
const explicit = `export { ${entry.names.join(', ')} } from ${JSON.stringify(entry.rep.url)};`;
|
|
424
|
-
code = code.replace(entry.rep.full, explicit);
|
|
425
|
-
}
|
|
426
|
-
return code;
|
|
427
|
-
}
|
|
428
|
-
function extractExportedNames(code) {
|
|
429
|
-
return extractDirectExportedNames(code);
|
|
430
|
-
}
|
|
431
|
-
function repairImportEqualsAssignments(code) {
|
|
432
|
-
try {
|
|
433
|
-
if (!code || typeof code !== 'string')
|
|
434
|
-
return code;
|
|
435
|
-
code = code.replace(/(^|\n)\s*import\s*\{([^}]+)\}\s*=\s*([^;]+);?/g, (_m, p1, specList, rhs) => {
|
|
436
|
-
const cleaned = String(specList)
|
|
437
|
-
.split(',')
|
|
438
|
-
.map((s) => s.trim())
|
|
439
|
-
.filter(Boolean)
|
|
440
|
-
.map((seg) => seg.replace(/\s+as\s+/i, ': '))
|
|
441
|
-
.join(', ');
|
|
442
|
-
return `${p1}const { ${cleaned} } = ${rhs};`;
|
|
443
|
-
});
|
|
444
|
-
code = code.replace(/(^|\n)\s*import\s*\*\s*as\s*([A-Za-z_$][\w$]*)\s*=\s*([^;]+);?/g, (_m, p1, ns, rhs) => `${p1}const ${ns} = (${rhs});`);
|
|
445
|
-
code = code.replace(/(^|\n)\s*import\s+([A-Za-z_$][\w$]*)\s*=\s*([^;]+);?/g, (_m, p1, id, rhs) => `${p1}const ${id} = ${rhs};`);
|
|
446
|
-
}
|
|
447
|
-
catch { }
|
|
448
|
-
return code;
|
|
449
|
-
}
|
|
450
|
-
function ensureVersionedRtImports(code, origin, ver) {
|
|
451
|
-
if (!code || !origin || !Number.isFinite(ver))
|
|
452
|
-
return code;
|
|
453
|
-
code = code.replace(/(from\s+["'])(?:https?:\/\/[^"']+)?\/(?:\ns|ns)\/rt(?:\/[\d]+)?(["'])/g, (_m, p1, p3) => `${p1}/ns/rt/${ver}${p3}`);
|
|
454
|
-
code = code.replace(/(import\(\s*["'])(?:https?:\/\/[^"']+)?\/(?:\@ns|ns)\/rt(?:\/[\d]+)?(["']\s*\))/g, (_m, p1, p3) => `${p1}/ns/rt/${ver}${p3}`);
|
|
455
|
-
return code;
|
|
456
|
-
}
|
|
457
|
-
function stripViteDynamicImportVirtual(code) {
|
|
458
|
-
if (!/\/@id\/__x00__vite\/dynamic-import-helper/.test(code)) {
|
|
459
|
-
return code;
|
|
460
|
-
}
|
|
461
|
-
const original = code;
|
|
462
|
-
code = code.replace(/^[\t ]*import[^\n]*\/@id\/__x00__vite\/dynamic-import-helper[^\n]*$/gm, '');
|
|
463
|
-
if (/\/@id\/__x00__vite\/dynamic-import-helper/.test(code)) {
|
|
464
|
-
code = code.replace(/\/@id\/__x00__vite\/dynamic-import-helper[^"'`)]*/g, '/__NS_UNUSED_DYNAMIC_IMPORT_HELPER__');
|
|
465
|
-
}
|
|
466
|
-
if (!/__variableDynamicImportRuntimeHelper/.test(code)) {
|
|
467
|
-
const inline = `const __variableDynamicImportRuntimeHelper = (map, request, importMode) => {\n try { if (request === '@') { return import('/ns/m/__invalid_at__.mjs'); } } catch {}\n const loader = map && (map[request] || map[request?.replace(/\\\\/g, '/')]);\n if (!loader) { const e = new Error('Cannot dynamically import: ' + request); /*@ts-ignore*/ e.code = 'ERR_MODULE_NOT_FOUND'; return Promise.reject(e); }\n try { return loader(importMode); } catch (e) { return Promise.reject(e); }\n};\n`;
|
|
468
|
-
code = inline + code;
|
|
469
|
-
}
|
|
470
|
-
if (code !== original) {
|
|
471
|
-
code = `// [hmr-sanitize] removed virtual dynamic-import-helper\n${code}`;
|
|
472
|
-
}
|
|
473
|
-
return code;
|
|
474
|
-
}
|
|
475
268
|
// Detect (and log) `require('http(s)://...')` calls made from CJS shims.
|
|
476
269
|
// Pattern: HTTP-served ESM modules end up in NS-vite's `__nsRequire`
|
|
477
270
|
// shim with HTTP URLs as their relative resolution targets. The guard
|
|
@@ -557,43 +350,6 @@ function stripImportMetaHotBlocks(code) {
|
|
|
557
350
|
}
|
|
558
351
|
return result;
|
|
559
352
|
}
|
|
560
|
-
// Extract a quick set of export names and whether a default export exists from ESM code.
|
|
561
|
-
// This uses conservative regex scanning for metadata only (no code rewriting).
|
|
562
|
-
function extractExportMetadata(code) {
|
|
563
|
-
const named = new Set();
|
|
564
|
-
let hasDefault = /\bexport\s+default\b/.test(code);
|
|
565
|
-
try {
|
|
566
|
-
// export const foo, export let foo, export function bar, export class Baz
|
|
567
|
-
for (const m of code.matchAll(/\bexport\s+(?:const|let|var|function|class)\s+([A-Za-z_$][A-Za-z0-9_$]*)/g)) {
|
|
568
|
-
if (m[1])
|
|
569
|
-
named.add(m[1]);
|
|
570
|
-
}
|
|
571
|
-
// export { a, b as c }
|
|
572
|
-
for (const m of code.matchAll(/\bexport\s*\{([^}]+)\}/g)) {
|
|
573
|
-
const inner = (m[1] || '')
|
|
574
|
-
.split(',')
|
|
575
|
-
.map((s) => s.trim())
|
|
576
|
-
.filter(Boolean);
|
|
577
|
-
for (const seg of inner) {
|
|
578
|
-
// forms: name or name as alias or default as name
|
|
579
|
-
const dm = seg.match(/^([A-Za-z_$][A-Za-z0-9_$]*)(?:\s+as\s+([A-Za-z_$][A-Za-z0-9_$]*))?$/);
|
|
580
|
-
if (dm) {
|
|
581
|
-
const base = dm[1];
|
|
582
|
-
const alias = dm[2];
|
|
583
|
-
if (base === 'default') {
|
|
584
|
-
hasDefault = true;
|
|
585
|
-
continue;
|
|
586
|
-
}
|
|
587
|
-
named.add(alias || base);
|
|
588
|
-
}
|
|
589
|
-
}
|
|
590
|
-
}
|
|
591
|
-
}
|
|
592
|
-
catch { }
|
|
593
|
-
// Remove default if accidentally included
|
|
594
|
-
named.delete('default');
|
|
595
|
-
return { hasDefault, named: Array.from(named) };
|
|
596
|
-
}
|
|
597
353
|
function normalizeImportPath(spec, importerDir) {
|
|
598
354
|
if (!spec)
|
|
599
355
|
return null;
|
|
@@ -793,8 +549,8 @@ function cleanCode(code) {
|
|
|
793
549
|
result = result.replace(PAT.VITE_CLIENT_IMPORT, '');
|
|
794
550
|
result = result.replace(PAT.IMPORT_META_HOT_ASSIGNMENT, '');
|
|
795
551
|
// Keep import.meta.hot call sites; runtime now provides a stable import.meta.hot.
|
|
796
|
-
result = ACTIVE_STRATEGY.preClean(result);
|
|
797
|
-
result = ACTIVE_STRATEGY.rewriteFrameworkImports(result);
|
|
552
|
+
result = ACTIVE_STRATEGY.preClean?.(result) ?? result;
|
|
553
|
+
result = ACTIVE_STRATEGY.rewriteFrameworkImports?.(result) ?? result;
|
|
798
554
|
// Vendor manifest-driven import rewrites
|
|
799
555
|
// NOTE: Static and side-effect vendor imports are intentionally NOT rewritten here.
|
|
800
556
|
// They are left as import statements so that ensureNativeScriptModuleBindings()
|
|
@@ -822,13 +578,11 @@ function cleanCode(code) {
|
|
|
822
578
|
}
|
|
823
579
|
result = result.replace(PAT.VITE_CLIENT_IMPORT, '').replace(PAT.IMPORT_META_HOT_ASSIGNMENT, '');
|
|
824
580
|
// Clean up HMR noise
|
|
825
|
-
result = ACTIVE_STRATEGY.postClean(result);
|
|
581
|
+
result = ACTIVE_STRATEGY.postClean?.(result) ?? result;
|
|
826
582
|
result = stripCoreGlobalsImports(result);
|
|
827
583
|
return result;
|
|
828
584
|
}
|
|
829
|
-
//
|
|
830
|
-
// APPLICATION IMPORT HELPERS
|
|
831
|
-
// ============================================================================
|
|
585
|
+
// Application import helpers
|
|
832
586
|
/**
|
|
833
587
|
* Check if a path is an application module (not node_modules, not vendor, not relative)
|
|
834
588
|
* This is generic and works for ANY project structure.
|
|
@@ -973,197 +727,6 @@ function normalizeAbsoluteFilesystemImport(spec, importerPath, projectRoot) {
|
|
|
973
727
|
}
|
|
974
728
|
return absolute;
|
|
975
729
|
}
|
|
976
|
-
/**
|
|
977
|
-
* After the Angular linker runs on code that Vite has already resolved (bare
|
|
978
|
-
* specifiers → full URLs), the linker injects NEW import statements with bare
|
|
979
|
-
* specifiers (e.g. `import {Component} from '@angular/core'`). These cause:
|
|
980
|
-
* 1. Duplicate-identifier SyntaxErrors (the name was already imported via URL)
|
|
981
|
-
* 2. Unresolvable bare specifiers at runtime on device
|
|
982
|
-
*
|
|
983
|
-
* This function:
|
|
984
|
-
* • builds a map packageName → resolvedURL from existing resolved imports
|
|
985
|
-
* • collects all binding names already imported per package
|
|
986
|
-
* • for each bare-specifier import, removes duplicate bindings
|
|
987
|
-
* • rewrites any genuinely-new bindings to use the resolved URL
|
|
988
|
-
*/
|
|
989
|
-
function deduplicateLinkerImports(code) {
|
|
990
|
-
if (!code)
|
|
991
|
-
return code;
|
|
992
|
-
try {
|
|
993
|
-
const imports = collectTopLevelImportRecords(code);
|
|
994
|
-
if (!imports.length) {
|
|
995
|
-
return code;
|
|
996
|
-
}
|
|
997
|
-
// ── Step 1: collect resolved imports already in the file ──────────
|
|
998
|
-
const pkgUrlMap = new Map();
|
|
999
|
-
const pkgBindings = new Map();
|
|
1000
|
-
for (const imp of imports) {
|
|
1001
|
-
const url = imp.source;
|
|
1002
|
-
if (!/^https?:\/\//.test(url) && !url.startsWith('/')) {
|
|
1003
|
-
continue;
|
|
1004
|
-
}
|
|
1005
|
-
const nmIdx = url.lastIndexOf('/node_modules/');
|
|
1006
|
-
if (nmIdx === -1)
|
|
1007
|
-
continue;
|
|
1008
|
-
const afterNm = url.substring(nmIdx + '/node_modules/'.length);
|
|
1009
|
-
const parts = afterNm.split('/');
|
|
1010
|
-
const pkg = parts[0].startsWith('@') ? parts.slice(0, 2).join('/') : parts[0];
|
|
1011
|
-
if (!pkgUrlMap.has(pkg))
|
|
1012
|
-
pkgUrlMap.set(pkg, url);
|
|
1013
|
-
if (imp.namedBindings.length) {
|
|
1014
|
-
if (!pkgBindings.has(pkg))
|
|
1015
|
-
pkgBindings.set(pkg, new Set());
|
|
1016
|
-
for (const binding of imp.namedBindings) {
|
|
1017
|
-
if (binding.importedName)
|
|
1018
|
-
pkgBindings.get(pkg).add(binding.importedName);
|
|
1019
|
-
}
|
|
1020
|
-
}
|
|
1021
|
-
}
|
|
1022
|
-
if (pkgUrlMap.size === 0)
|
|
1023
|
-
return code;
|
|
1024
|
-
// ── Step 2: rewrite bare-specifier imports ───────────────────────
|
|
1025
|
-
const edits = [];
|
|
1026
|
-
for (const imp of imports) {
|
|
1027
|
-
if (!imp.hasOnlyNamedSpecifiers) {
|
|
1028
|
-
continue;
|
|
1029
|
-
}
|
|
1030
|
-
const specifier = imp.source;
|
|
1031
|
-
if (specifier.startsWith('/') || specifier.startsWith('.') || specifier.startsWith('http')) {
|
|
1032
|
-
continue;
|
|
1033
|
-
}
|
|
1034
|
-
const parts = specifier.split('/');
|
|
1035
|
-
const pkg = specifier.startsWith('@') ? parts.slice(0, 2).join('/') : parts[0];
|
|
1036
|
-
const url = pkgUrlMap.get(pkg);
|
|
1037
|
-
if (!url) {
|
|
1038
|
-
continue;
|
|
1039
|
-
}
|
|
1040
|
-
const existing = pkgBindings.get(pkg) || new Set();
|
|
1041
|
-
const newBindings = imp.namedBindings.filter((binding) => !existing.has(binding.importedName));
|
|
1042
|
-
if (newBindings.length === 0) {
|
|
1043
|
-
edits.push({ start: imp.start, end: imp.end, text: '' });
|
|
1044
|
-
continue;
|
|
1045
|
-
}
|
|
1046
|
-
if (newBindings.length === imp.namedBindings.length) {
|
|
1047
|
-
continue;
|
|
1048
|
-
}
|
|
1049
|
-
for (const binding of newBindings) {
|
|
1050
|
-
existing.add(binding.importedName);
|
|
1051
|
-
}
|
|
1052
|
-
edits.push({
|
|
1053
|
-
start: imp.start,
|
|
1054
|
-
end: imp.end,
|
|
1055
|
-
text: `import { ${newBindings.map((binding) => binding.text).join(', ')} } from ${JSON.stringify(url)};`,
|
|
1056
|
-
});
|
|
1057
|
-
}
|
|
1058
|
-
if (!edits.length) {
|
|
1059
|
-
return code;
|
|
1060
|
-
}
|
|
1061
|
-
let next = code;
|
|
1062
|
-
for (const edit of edits.sort((left, right) => right.start - left.start)) {
|
|
1063
|
-
next = next.slice(0, edit.start) + edit.text + next.slice(edit.end);
|
|
1064
|
-
}
|
|
1065
|
-
return next;
|
|
1066
|
-
}
|
|
1067
|
-
catch {
|
|
1068
|
-
return code;
|
|
1069
|
-
}
|
|
1070
|
-
}
|
|
1071
|
-
export function wrapCommonJsModuleForDevice(code, absolutePath) {
|
|
1072
|
-
if (!code)
|
|
1073
|
-
return code;
|
|
1074
|
-
try {
|
|
1075
|
-
const hasExportDefault = /\bexport\s+default\b/.test(code) || /export\s*\{\s*default\s*(?:as\s*default)?\s*\}/.test(code);
|
|
1076
|
-
const hasNamedExports = /\bexport\s+(?:const|let|var|function|class|async)\b/.test(code) || /\bexport\s*\{/.test(code);
|
|
1077
|
-
const hasCjsExports = /\bmodule\s*\.\s*exports\b/.test(code) || /\bexports\s*\.\s*\w/.test(code);
|
|
1078
|
-
if (hasExportDefault || hasNamedExports || !hasCjsExports) {
|
|
1079
|
-
return code;
|
|
1080
|
-
}
|
|
1081
|
-
const namedExports = new Set();
|
|
1082
|
-
const exportsRe = /\bexports\s*\.\s*([A-Za-z_$][\w$]*)\s*=/g;
|
|
1083
|
-
let em;
|
|
1084
|
-
while ((em = exportsRe.exec(code)) !== null) {
|
|
1085
|
-
const name = em[1];
|
|
1086
|
-
if (name !== '__esModule' && name !== 'default') {
|
|
1087
|
-
namedExports.add(name);
|
|
1088
|
-
}
|
|
1089
|
-
}
|
|
1090
|
-
const defPropRe = /Object\s*\.\s*defineProperty\s*\(\s*exports\s*,\s*['"]([^'"]+)['"]/g;
|
|
1091
|
-
while ((em = defPropRe.exec(code)) !== null) {
|
|
1092
|
-
const name = em[1];
|
|
1093
|
-
if (name !== '__esModule' && name !== 'default') {
|
|
1094
|
-
namedExports.add(name);
|
|
1095
|
-
}
|
|
1096
|
-
}
|
|
1097
|
-
// Static enumeration only sees `exports.foo = ...` and `Object.defineProperty(exports, 'foo', ...)`.
|
|
1098
|
-
// Real-world packages like lodash attach their entire surface to a function inside an IIFE and
|
|
1099
|
-
// then `module.exports = thatFunction`. Static analysis returns zero in that case. To handle
|
|
1100
|
-
// these modules we ALSO load the package in the dev-server's Node context (only when we have a
|
|
1101
|
-
// node_modules path) and merge the runtime keys. See `helpers/cjs-named-exports.ts` for the
|
|
1102
|
-
// reasoning and safety boundaries.
|
|
1103
|
-
if (absolutePath) {
|
|
1104
|
-
try {
|
|
1105
|
-
for (const n of getCjsNamedExports(absolutePath)) {
|
|
1106
|
-
namedExports.add(n);
|
|
1107
|
-
}
|
|
1108
|
-
}
|
|
1109
|
-
catch {
|
|
1110
|
-
/* fall through to whatever we caught statically */
|
|
1111
|
-
}
|
|
1112
|
-
}
|
|
1113
|
-
let suffix = `\nvar __cjs_mod = module.exports;\nexport default __cjs_mod;\n`;
|
|
1114
|
-
if (namedExports.size) {
|
|
1115
|
-
const entries = Array.from(namedExports);
|
|
1116
|
-
const temps = entries.map((name, i) => `var __cjs_e${i} = __cjs_mod[${JSON.stringify(name)}];`);
|
|
1117
|
-
const reExports = entries.map((name, i) => `__cjs_e${i} as ${name}`);
|
|
1118
|
-
suffix += `${temps.join(' ')}\nexport { ${reExports.join(', ')} };\n`;
|
|
1119
|
-
}
|
|
1120
|
-
const prelude = `var module = { exports: {} }; var exports = module.exports;\n` +
|
|
1121
|
-
`var __ns_cjs_require_base = (typeof globalThis.__nsBaseRequire === 'function' ? globalThis.__nsBaseRequire : (typeof globalThis.__nsRequire === 'function' ? globalThis.__nsRequire : (typeof globalThis.require === 'function' ? globalThis.require : undefined)));\n` +
|
|
1122
|
-
`var __ns_cjs_require_kind = (typeof globalThis.__nsBaseRequire === 'function' ? 'base-require' : (typeof globalThis.__nsRequire === 'function' ? 'vendor-require' : 'global-require'));\n` +
|
|
1123
|
-
`var require = function(spec) {\n` +
|
|
1124
|
-
` if (!__ns_cjs_require_base) { throw new Error('require is not defined'); }\n` +
|
|
1125
|
-
// Resolve relative specifiers against the HTTP-served module's URL
|
|
1126
|
-
// before delegating to NS's runtime require. Without this step,
|
|
1127
|
-
// \`require('./base64-vlq')\` inside a CJS module served from
|
|
1128
|
-
// \`http://.../ns/m/node_modules/source-map-js/lib/source-map-generator.js\`
|
|
1129
|
-
// would pass a literal '"./base64-vlq"' to the native require, which
|
|
1130
|
-
// has no notion of the current HTTP-module's location and either
|
|
1131
|
-
// throws "Module not found" or fetches an arbitrary filesystem path
|
|
1132
|
-
// that happens to parse as code (producing misleading syntax errors
|
|
1133
|
-
// like "missing ) after argument list" from unrelated modules).
|
|
1134
|
-
` var __nsResolvedSpec = spec;\n` +
|
|
1135
|
-
` try {\n` +
|
|
1136
|
-
` if (typeof spec === 'string' && (spec.indexOf('./') === 0 || spec.indexOf('../') === 0)) {\n` +
|
|
1137
|
-
` var __nsParentUrl = (typeof import.meta !== 'undefined' && import.meta && typeof import.meta.url === 'string') ? import.meta.url : null;\n` +
|
|
1138
|
-
` if (__nsParentUrl) {\n` +
|
|
1139
|
-
` var __nsResolvedUrl = new URL(spec, __nsParentUrl);\n` +
|
|
1140
|
-
` // Common Node-style bare extensions: prefer .js if the resolved URL lacks an extension in its last path segment.\n` +
|
|
1141
|
-
` if (!/\\.[A-Za-z0-9]+$/.test(__nsResolvedUrl.pathname.split('/').pop() || '')) {\n` +
|
|
1142
|
-
` __nsResolvedUrl.pathname = __nsResolvedUrl.pathname.replace(/\\/+$/, '') + '.js';\n` +
|
|
1143
|
-
` }\n` +
|
|
1144
|
-
` __nsResolvedSpec = __nsResolvedUrl.href;\n` +
|
|
1145
|
-
` }\n` +
|
|
1146
|
-
` }\n` +
|
|
1147
|
-
` } catch (e) {}\n` +
|
|
1148
|
-
` try { var __nsRecord = globalThis.__NS_RECORD_MODULE_PROVENANCE__; if (typeof __nsRecord === 'function') { __nsRecord(String(__nsResolvedSpec), { kind: __ns_cjs_require_kind, specifier: String(spec), url: __nsResolvedSpec !== spec ? __nsResolvedSpec : undefined, via: 'cjs-wrapper', parent: (typeof import.meta !== 'undefined' && import.meta && import.meta.url) ? import.meta.url : undefined }); } } catch (e) {}\n` +
|
|
1149
|
-
` var mod = __ns_cjs_require_base(__nsResolvedSpec);\n` +
|
|
1150
|
-
` try {\n` +
|
|
1151
|
-
` if (mod && (typeof mod === 'object' || typeof mod === 'function') && mod.default !== undefined) {\n` +
|
|
1152
|
-
` var keys = [];\n` +
|
|
1153
|
-
` try { keys = Object.keys(mod); } catch (e) {}\n` +
|
|
1154
|
-
` var defaultOnly = keys.length === 1 && keys[0] === 'default';\n` +
|
|
1155
|
-
` var esModuleOnly = keys.length === 2 && keys.indexOf('default') !== -1 && keys.indexOf('__esModule') !== -1;\n` +
|
|
1156
|
-
` if (mod.__esModule || defaultOnly || esModuleOnly) { return mod.default; }\n` +
|
|
1157
|
-
` }\n` +
|
|
1158
|
-
` } catch (e) {}\n` +
|
|
1159
|
-
` return mod;\n` +
|
|
1160
|
-
`};\n`;
|
|
1161
|
-
return `${prelude}${code}${suffix}`;
|
|
1162
|
-
}
|
|
1163
|
-
catch {
|
|
1164
|
-
return code;
|
|
1165
|
-
}
|
|
1166
|
-
}
|
|
1167
730
|
/**
|
|
1168
731
|
* Process code for device: inject globals, remove framework imports
|
|
1169
732
|
*/
|
|
@@ -1696,198 +1259,6 @@ function processCodeForDevice(code, isVitePreBundled, preserveVendorImports = fa
|
|
|
1696
1259
|
// Assert that sanitized code no longer contains any Vite optimized deps artifacts
|
|
1697
1260
|
// or virtual ids that could break the HTTP ESM loader on device. Throws with
|
|
1698
1261
|
// a helpful diagnostics message if any are found.
|
|
1699
|
-
function assertNoOptimizedArtifacts(code, contextLabel) {
|
|
1700
|
-
try {
|
|
1701
|
-
const offenders = [];
|
|
1702
|
-
const lines = code.split('\n');
|
|
1703
|
-
const tests = [
|
|
1704
|
-
// Allow Vite dev indirections like /@id/ and /.vite/deps when served via HTTP.
|
|
1705
|
-
// Only flag clearly invalid virtual placeholders if they surface in output.
|
|
1706
|
-
/\b__VITE_PLUGIN__\b/,
|
|
1707
|
-
/\b__VITE_PRELOAD__\b/,
|
|
1708
|
-
];
|
|
1709
|
-
// Absolute or relative local @nativescript/core usage indicates a split realm risk; fail fast
|
|
1710
|
-
const localCore = /(^|[^\w@])(?:\.\.?\/|\/)??@nativescript[\/_-]core\//i;
|
|
1711
|
-
for (let i = 0; i < lines.length; i++) {
|
|
1712
|
-
const ln = lines[i];
|
|
1713
|
-
for (const re of tests) {
|
|
1714
|
-
if (re.test(ln)) {
|
|
1715
|
-
offenders.push(`${i + 1}: ${ln.substring(0, 200)}`);
|
|
1716
|
-
break;
|
|
1717
|
-
}
|
|
1718
|
-
}
|
|
1719
|
-
if (localCore.test(ln)) {
|
|
1720
|
-
// Comments can never cause split-realm risk at runtime — skip them.
|
|
1721
|
-
// Library authors commonly reference @nativescript/core in comments
|
|
1722
|
-
// (e.g. TSDoc /// <reference> directives, module resolution notes).
|
|
1723
|
-
const trimmed = ln.trimStart();
|
|
1724
|
-
if (trimmed.startsWith('//') || trimmed.startsWith('/*') || trimmed.startsWith('*')) {
|
|
1725
|
-
continue;
|
|
1726
|
-
}
|
|
1727
|
-
if (shouldAllowLocalCoreSanitizerPaths(contextLabel)) {
|
|
1728
|
-
continue;
|
|
1729
|
-
}
|
|
1730
|
-
offenders.push(`${i + 1}: ${ln.substring(0, 200)} [local-core-path]`);
|
|
1731
|
-
}
|
|
1732
|
-
if (offenders.length >= 10)
|
|
1733
|
-
break;
|
|
1734
|
-
}
|
|
1735
|
-
if (offenders.length) {
|
|
1736
|
-
const msg = `[sanitize-fail] Optimized deps/virtual id artifacts detected in ${contextLabel}. These cannot be evaluated by the device HTTP ESM loader. Offending lines (first ${Math.min(5, offenders.length)} shown):\n` + offenders.slice(0, 5).join('\n');
|
|
1737
|
-
const err = new Error(msg);
|
|
1738
|
-
// Attach details for server logs / higher-level handlers
|
|
1739
|
-
err.code = 'NS_SANITIZE_FAIL';
|
|
1740
|
-
err.offenders = offenders;
|
|
1741
|
-
throw err;
|
|
1742
|
-
}
|
|
1743
|
-
}
|
|
1744
|
-
catch (e) {
|
|
1745
|
-
// If diagnostics generation itself fails, do not mask the underlying issue
|
|
1746
|
-
throw e;
|
|
1747
|
-
}
|
|
1748
|
-
}
|
|
1749
|
-
// Ensure there are no lingering named imports from the unified core bridge.
|
|
1750
|
-
// Converts named imports from `/ns/core[/<sub>]` into default import +
|
|
1751
|
-
// destructuring. The package-main bridge serves a shape-shifted module whose
|
|
1752
|
-
// named exports come from `__ns_core_bridge.default` rather than ESM named
|
|
1753
|
-
// exports, so a named-import binding would be `undefined` at evaluation.
|
|
1754
|
-
function ensureDestructureCoreImports(code) {
|
|
1755
|
-
try {
|
|
1756
|
-
let result = code;
|
|
1757
|
-
let coreImportCounter = 0;
|
|
1758
|
-
const toDestructure = (specList) => specList
|
|
1759
|
-
.split(',')
|
|
1760
|
-
.map((s) => s.trim())
|
|
1761
|
-
.filter(Boolean)
|
|
1762
|
-
.map((seg) => {
|
|
1763
|
-
const m = seg.split(/\s+as\s+/i);
|
|
1764
|
-
return m.length === 2 ? `${m[0].trim()}: ${m[1].trim()}` : seg;
|
|
1765
|
-
})
|
|
1766
|
-
.join(', ');
|
|
1767
|
-
// import { A, B } from '/ns/core[/<sub>]'
|
|
1768
|
-
const reNamed = /(^|\n)\s*import\s*\{([^}]+)\}\s*from\s*["']((?:https?:\/\/[^"']+)?\/ns\/core(?:\/[^"']+)?)['"];?\s*/gm;
|
|
1769
|
-
result = result.replace(reNamed, (_full, pfx, specList, src) => {
|
|
1770
|
-
// Deep subpath URLs serve actual ESM with real named exports — skip.
|
|
1771
|
-
if (isDeepCoreSubpath(src))
|
|
1772
|
-
return _full;
|
|
1773
|
-
const tmp = `__ns_core_ns_re${coreImportCounter > 0 ? `_${coreImportCounter}` : ''}`;
|
|
1774
|
-
coreImportCounter++;
|
|
1775
|
-
const decl = `const { ${toDestructure(specList)} } = ${tmp};`;
|
|
1776
|
-
return `${pfx}import ${tmp} from ${JSON.stringify(src)};\n${decl}\n`;
|
|
1777
|
-
});
|
|
1778
|
-
// import Default, { A, B } from '/ns/core[/<sub>]'
|
|
1779
|
-
const reMixed = /(^|\n)\s*import\s+([A-Za-z_$][\w$]*)\s*,\s*\{([^}]+)\}\s*from\s*["']((?:https?:\/\/[^"']+)?\/ns\/core(?:\/[^"']+)?)['"];?\s*/gm;
|
|
1780
|
-
result = result.replace(reMixed, (_full, pfx, defName, specList, src) => {
|
|
1781
|
-
if (isDeepCoreSubpath(src))
|
|
1782
|
-
return _full;
|
|
1783
|
-
const decl = `const { ${toDestructure(specList)} } = ${defName};`;
|
|
1784
|
-
return `${pfx}import ${defName} from ${JSON.stringify(src)};\n${decl}\n`;
|
|
1785
|
-
});
|
|
1786
|
-
return result;
|
|
1787
|
-
}
|
|
1788
|
-
catch {
|
|
1789
|
-
return code;
|
|
1790
|
-
}
|
|
1791
|
-
}
|
|
1792
|
-
// Converts any named imports from the runtime bridge (/ns/rt[/ver]) into a default import + destructuring.
|
|
1793
|
-
// This guarantees helper aliases like _resolveComponent remain bound even if we later normalize imports.
|
|
1794
|
-
function ensureDestructureRtImports(code) {
|
|
1795
|
-
try {
|
|
1796
|
-
let result = code;
|
|
1797
|
-
const toDestructure = (specList) => specList
|
|
1798
|
-
.split(',')
|
|
1799
|
-
.map((s) => s.trim())
|
|
1800
|
-
.filter(Boolean)
|
|
1801
|
-
.map((seg) => {
|
|
1802
|
-
// Preserve alias mapping (e.g., resolveComponent as _resolveComponent)
|
|
1803
|
-
const m = seg.split(/\s+as\s+/i);
|
|
1804
|
-
return m.length === 2 ? `${m[0].trim()}: ${m[1].trim()}` : seg;
|
|
1805
|
-
})
|
|
1806
|
-
.join(', ');
|
|
1807
|
-
const reNamed = /(^|\n)\s*import\s*\{([^}]+)\}\s*from\s*["']((?:https?:\/\/[^"']+)?\/ns\/rt(?:\/[\d]+)?)['"];?\s*/gm;
|
|
1808
|
-
result = result.replace(reNamed, (_full, pfx, specList, src) => {
|
|
1809
|
-
const tmp = `__ns_rt_ns_re`;
|
|
1810
|
-
const decl = `const { ${toDestructure(specList)} } = ${tmp};`;
|
|
1811
|
-
return `${pfx}import ${tmp} from ${JSON.stringify(src)};\n${decl}\n`;
|
|
1812
|
-
});
|
|
1813
|
-
const reMixed = /(^|\n)\s*import\s+([A-Za-z_$][\w$]*)\s*,\s*\{([^}]+)\}\s*from\s*["']((?:https?:\/\/[^"']+)?\/ns\/rt(?:\/[\d]+)?)['"];?\s*/gm;
|
|
1814
|
-
result = result.replace(reMixed, (_full, pfx, defName, specList, _src) => {
|
|
1815
|
-
const decl = `const { ${toDestructure(specList)} } = ${defName};`;
|
|
1816
|
-
return `${pfx}import ${defName} from ${JSON.stringify(_src)};\n${decl}\n`;
|
|
1817
|
-
});
|
|
1818
|
-
return result;
|
|
1819
|
-
}
|
|
1820
|
-
catch {
|
|
1821
|
-
return code;
|
|
1822
|
-
}
|
|
1823
|
-
}
|
|
1824
|
-
// Remove overlapping named imports from /ns/rt that duplicate bindings already provided
|
|
1825
|
-
// by destructuring a default /ns/rt import (e.g., const { $showModal } = __ns_rt_ns_1;).
|
|
1826
|
-
function dedupeRtNamedImportsAgainstDestructures(code) {
|
|
1827
|
-
try {
|
|
1828
|
-
let result = code;
|
|
1829
|
-
// Collect bindings created from any destructure of __ns_rt_ns* temps
|
|
1830
|
-
const rtDestructureRE = /(^|\n)\s*const\s*\{([^}]+)\}\s*=\s*(__ns_rt_ns(?:\d+|_re))\s*;?/gm;
|
|
1831
|
-
const rtBound = new Set();
|
|
1832
|
-
let m;
|
|
1833
|
-
while ((m = rtDestructureRE.exec(result)) !== null) {
|
|
1834
|
-
const specList = String(m[2] || '');
|
|
1835
|
-
specList
|
|
1836
|
-
.split(',')
|
|
1837
|
-
.map((s) => s.trim())
|
|
1838
|
-
.filter(Boolean)
|
|
1839
|
-
.forEach((seg) => {
|
|
1840
|
-
const bind = seg.includes(':') ? seg.split(':')[1].trim() : seg;
|
|
1841
|
-
if (bind)
|
|
1842
|
-
rtBound.add(bind);
|
|
1843
|
-
});
|
|
1844
|
-
}
|
|
1845
|
-
if (!rtBound.size)
|
|
1846
|
-
return result;
|
|
1847
|
-
// For any named import from /ns/rt (versioned or not), drop specifiers that are already bound
|
|
1848
|
-
const rtNamedImportRE = /(^|\n)\s*import\s*\{([^}]+)\}\s*from\s*["']((?:https?:\/\/[^"']+)?\/ns\/rt(?:\/[\d]+)?)["'];?\s*/gm;
|
|
1849
|
-
const edits = [];
|
|
1850
|
-
while ((m = rtNamedImportRE.exec(result)) !== null) {
|
|
1851
|
-
const full = m[0];
|
|
1852
|
-
const pfx = m[1] || '';
|
|
1853
|
-
const specList = String(m[2] || '');
|
|
1854
|
-
const src = m[3];
|
|
1855
|
-
const kept = [];
|
|
1856
|
-
specList
|
|
1857
|
-
.split(',')
|
|
1858
|
-
.map((s) => s.trim())
|
|
1859
|
-
.filter(Boolean)
|
|
1860
|
-
.forEach((seg) => {
|
|
1861
|
-
const importedName = seg.split(/\s+as\s+/i)[0].trim();
|
|
1862
|
-
if (!rtBound.has(importedName))
|
|
1863
|
-
kept.push(seg);
|
|
1864
|
-
});
|
|
1865
|
-
let replacement = '';
|
|
1866
|
-
if (kept.length) {
|
|
1867
|
-
replacement = `${pfx}import { ${kept.join(', ')} } from ${JSON.stringify(src)};`;
|
|
1868
|
-
}
|
|
1869
|
-
else {
|
|
1870
|
-
replacement = pfx || '';
|
|
1871
|
-
}
|
|
1872
|
-
edits.push({
|
|
1873
|
-
start: rtNamedImportRE.lastIndex - full.length,
|
|
1874
|
-
end: rtNamedImportRE.lastIndex,
|
|
1875
|
-
text: replacement,
|
|
1876
|
-
});
|
|
1877
|
-
}
|
|
1878
|
-
if (edits.length) {
|
|
1879
|
-
edits
|
|
1880
|
-
.sort((a, b) => b.start - a.start)
|
|
1881
|
-
.forEach((e) => {
|
|
1882
|
-
result = result.slice(0, e.start) + e.text + result.slice(e.end);
|
|
1883
|
-
});
|
|
1884
|
-
}
|
|
1885
|
-
return result;
|
|
1886
|
-
}
|
|
1887
|
-
catch {
|
|
1888
|
-
return code;
|
|
1889
|
-
}
|
|
1890
|
-
}
|
|
1891
1262
|
/**
|
|
1892
1263
|
* THE SINGLE REWRITE FUNCTION - used everywhere for consistency
|
|
1893
1264
|
*/
|
|
@@ -2476,9 +1847,7 @@ export function rewriteImports(code, importerPath, sfcFileMap, depFileMap, proje
|
|
|
2476
1847
|
});
|
|
2477
1848
|
return result;
|
|
2478
1849
|
}
|
|
2479
|
-
//
|
|
2480
|
-
// PLUGIN
|
|
2481
|
-
// ============================================================================
|
|
1850
|
+
// Plugin
|
|
2482
1851
|
function createHmrWebSocketPlugin(opts) {
|
|
2483
1852
|
const verbose = !!opts.verbose;
|
|
2484
1853
|
let wss = null;
|
|
@@ -3235,7 +2604,7 @@ function createHmrWebSocketPlugin(opts) {
|
|
|
3235
2604
|
try {
|
|
3236
2605
|
const origin = getServerOrigin(server);
|
|
3237
2606
|
code = ensureVersionedRtImports(code, origin, graphVersion);
|
|
3238
|
-
code = ACTIVE_STRATEGY.ensureVersionedImports(code, origin, graphVersion);
|
|
2607
|
+
code = ACTIVE_STRATEGY.ensureVersionedImports?.(code, origin, graphVersion) ?? code;
|
|
3239
2608
|
}
|
|
3240
2609
|
catch { }
|
|
3241
2610
|
// Compute rel .mjs output path
|
|
@@ -3291,7 +2660,7 @@ function createHmrWebSocketPlugin(opts) {
|
|
|
3291
2660
|
}
|
|
3292
2661
|
try {
|
|
3293
2662
|
depCode = ensureVersionedRtImports(depCode, getServerOrigin(server), graphVersion);
|
|
3294
|
-
depCode = ACTIVE_STRATEGY.ensureVersionedImports(depCode, getServerOrigin(server), graphVersion);
|
|
2663
|
+
depCode = ACTIVE_STRATEGY.ensureVersionedImports?.(depCode, getServerOrigin(server), graphVersion) ?? depCode;
|
|
3295
2664
|
}
|
|
3296
2665
|
catch { }
|
|
3297
2666
|
let depRel = depResolved.replace(/^\//, '').replace(/\.(tsx?|jsx?)$/i, '.mjs');
|
|
@@ -3788,79 +3157,10 @@ function createHmrWebSocketPlugin(opts) {
|
|
|
3788
3157
|
const pkg = bare;
|
|
3789
3158
|
let code = '';
|
|
3790
3159
|
if (pkg === 'vue' || pkg === 'nativescript-vue') {
|
|
3791
|
-
|
|
3792
|
-
code = `
|
|
3793
|
-
const g = globalThis;
|
|
3794
|
-
const reg = g.__nsVendorRegistry;
|
|
3795
|
-
const req = reg && g.__nsVendorRequire ? g.__nsVendorRequire : (g.__nsRequire || g.require);
|
|
3796
|
-
let mod = reg && reg.get('${pkg === 'vue' ? 'nativescript-vue' : 'nativescript-vue'}');
|
|
3797
|
-
if (!mod && req) {
|
|
3798
|
-
try { mod = req('${pkg === 'vue' ? 'nativescript-vue' : 'nativescript-vue'}'); } catch {}
|
|
3799
|
-
${pkg === 'vue' ? "if (!mod) { try { mod = req('vue'); } catch {} }" : ''}
|
|
3800
|
-
}
|
|
3801
|
-
mod = mod || {};
|
|
3802
|
-
const v = (mod.default ?? mod);
|
|
3803
|
-
export default v;
|
|
3804
|
-
export const defineComponent = v.defineComponent;
|
|
3805
|
-
export const resolveComponent = v.resolveComponent;
|
|
3806
|
-
export const createVNode = v.createVNode;
|
|
3807
|
-
export const createTextVNode = v.createTextVNode;
|
|
3808
|
-
export const createCommentVNode = v.createCommentVNode;
|
|
3809
|
-
export const Fragment = v.Fragment;
|
|
3810
|
-
export const withCtx = v.withCtx;
|
|
3811
|
-
export const openBlock = v.openBlock;
|
|
3812
|
-
export const createBlock = v.createBlock;
|
|
3813
|
-
export const createElementVNode = v.createElementVNode || v.createVNode;
|
|
3814
|
-
export const createElementBlock = v.createElementBlock || v.createBlock;
|
|
3815
|
-
export const renderSlot = v.renderSlot;
|
|
3816
|
-
export const mergeProps = v.mergeProps;
|
|
3817
|
-
export const toHandlers = v.toHandlers;
|
|
3818
|
-
export const renderList = v.renderList;
|
|
3819
|
-
export const normalizeProps = v.normalizeProps;
|
|
3820
|
-
export const guardReactiveProps = v.guardReactiveProps;
|
|
3821
|
-
export const withDirectives = v.withDirectives;
|
|
3822
|
-
export const resolveDirective = v.resolveDirective;
|
|
3823
|
-
export const withModifiers = v.withModifiers;
|
|
3824
|
-
export const withKeys = v.withKeys;
|
|
3825
|
-
export const ref = v.ref;
|
|
3826
|
-
export const shallowRef = v.shallowRef;
|
|
3827
|
-
export const unref = v.unref;
|
|
3828
|
-
export const computed = v.computed;
|
|
3829
|
-
export const onMounted = v.onMounted;
|
|
3830
|
-
export const onBeforeUnmount = v.onBeforeUnmount;
|
|
3831
|
-
export const onUnmounted = v.onUnmounted;
|
|
3832
|
-
export const watch = v.watch;
|
|
3833
|
-
export const nextTick = v.nextTick;
|
|
3834
|
-
export const createApp = v.createApp || (vm && vm.createApp);
|
|
3835
|
-
export const registerElement = v.registerElement || (vm && vm.registerElement);
|
|
3836
|
-
export const normalizeClass = v.normalizeClass;
|
|
3837
|
-
export const normalizeStyle = v.normalizeStyle;
|
|
3838
|
-
export const toDisplayString = v.toDisplayString;
|
|
3839
|
-
`;
|
|
3160
|
+
code = buildVueVendorShim(pkg);
|
|
3840
3161
|
}
|
|
3841
3162
|
else if (pkg === 'pinia') {
|
|
3842
|
-
|
|
3843
|
-
code = `
|
|
3844
|
-
const g = globalThis;
|
|
3845
|
-
const reg = g.__nsVendorRegistry;
|
|
3846
|
-
const req = reg && g.__nsVendorRequire ? g.__nsVendorRequire : (g.__nsRequire || g.require);
|
|
3847
|
-
let mod = reg && reg.get('pinia');
|
|
3848
|
-
if (!mod && req) { try { mod = req('pinia'); } catch {} }
|
|
3849
|
-
mod = mod || {};
|
|
3850
|
-
const p = (mod.default ?? mod);
|
|
3851
|
-
export default p;
|
|
3852
|
-
export const createPinia = p.createPinia;
|
|
3853
|
-
export const defineStore = p.defineStore;
|
|
3854
|
-
export const storeToRefs = p.storeToRefs;
|
|
3855
|
-
export const setActivePinia = p.setActivePinia;
|
|
3856
|
-
export const getActivePinia = p.getActivePinia;
|
|
3857
|
-
export const mapStores = p.mapStores;
|
|
3858
|
-
export const mapState = p.mapState;
|
|
3859
|
-
export const mapGetters = p.mapGetters;
|
|
3860
|
-
export const mapActions = p.mapActions;
|
|
3861
|
-
export const mapWritableState = p.mapWritableState;
|
|
3862
|
-
export const piniaSymbol = p.piniaSymbol;
|
|
3863
|
-
`;
|
|
3163
|
+
code = buildPiniaVendorShim();
|
|
3864
3164
|
}
|
|
3865
3165
|
res.statusCode = 200;
|
|
3866
3166
|
res.end(code || 'export {}\n');
|
|
@@ -4018,7 +3318,7 @@ export const piniaSymbol = p.piniaSymbol;
|
|
|
4018
3318
|
try {
|
|
4019
3319
|
const verNum = 0;
|
|
4020
3320
|
code = ensureVersionedRtImports(code, getServerOrigin(server), verNum);
|
|
4021
|
-
code = ACTIVE_STRATEGY.ensureVersionedImports(code, getServerOrigin(server), verNum);
|
|
3321
|
+
code = ACTIVE_STRATEGY.ensureVersionedImports?.(code, getServerOrigin(server), verNum) ?? code;
|
|
4022
3322
|
}
|
|
4023
3323
|
catch { }
|
|
4024
3324
|
// `/ns/m` URL finalize step.
|
|
@@ -5134,11 +4434,11 @@ export const piniaSymbol = p.piniaSymbol;
|
|
|
5134
4434
|
const verNum = Number(verFromPath || '0');
|
|
5135
4435
|
if (Number.isFinite(verNum) && verNum > 0) {
|
|
5136
4436
|
code = ensureVersionedRtImports(code, getServerOrigin(server), verNum);
|
|
5137
|
-
code = ACTIVE_STRATEGY.ensureVersionedImports(code, getServerOrigin(server), verNum);
|
|
4437
|
+
code = ACTIVE_STRATEGY.ensureVersionedImports?.(code, getServerOrigin(server), verNum) ?? code;
|
|
5138
4438
|
}
|
|
5139
4439
|
else {
|
|
5140
4440
|
code = ensureVersionedRtImports(code, getServerOrigin(server), graphVersion);
|
|
5141
|
-
code = ACTIVE_STRATEGY.ensureVersionedImports(code, getServerOrigin(server), graphVersion);
|
|
4441
|
+
code = ACTIVE_STRATEGY.ensureVersionedImports?.(code, getServerOrigin(server), graphVersion) ?? code;
|
|
5142
4442
|
}
|
|
5143
4443
|
}
|
|
5144
4444
|
catch { }
|
|
@@ -5845,7 +5145,7 @@ export const piniaSymbol = p.piniaSymbol;
|
|
|
5845
5145
|
try {
|
|
5846
5146
|
const origin = getServerOrigin(server);
|
|
5847
5147
|
inlineCode2 = ensureVersionedRtImports(inlineCode2, origin, Number(ver));
|
|
5848
|
-
inlineCode2 = ACTIVE_STRATEGY.ensureVersionedImports(inlineCode2, origin, Number(ver));
|
|
5148
|
+
inlineCode2 = ACTIVE_STRATEGY.ensureVersionedImports?.(inlineCode2, origin, Number(ver)) ?? inlineCode2;
|
|
5849
5149
|
}
|
|
5850
5150
|
catch { }
|
|
5851
5151
|
// Normalize imports/helpers via AST to ensure _defineComponent and other helpers are bound once
|
|
@@ -5959,7 +5259,7 @@ export const piniaSymbol = p.piniaSymbol;
|
|
|
5959
5259
|
try {
|
|
5960
5260
|
const origin = getServerOrigin(server);
|
|
5961
5261
|
code = ensureVersionedRtImports(code, origin, Number(ver));
|
|
5962
|
-
code = ACTIVE_STRATEGY.ensureVersionedImports(code, origin, Number(ver));
|
|
5262
|
+
code = ACTIVE_STRATEGY.ensureVersionedImports?.(code, origin, Number(ver)) ?? code;
|
|
5963
5263
|
}
|
|
5964
5264
|
catch { }
|
|
5965
5265
|
// Inline-template body path already runs processCodeForDevice (AST + sanitizers); no additional _defineComponent fix needed
|
|
@@ -6290,7 +5590,7 @@ export const piniaSymbol = p.piniaSymbol;
|
|
|
6290
5590
|
}
|
|
6291
5591
|
// Authoritative "what triggers HMR" gate, applied before the pending
|
|
6292
5592
|
// overlay broadcast below: react only to files inside the app source
|
|
6293
|
-
// dir (`appPath`) or a tsconfig-configured shared library.
|
|
5593
|
+
// dir (`appPath`) or a tsconfig-configured shared library.
|
|
6294
5594
|
if (!isWithinHmrScope(file, getHmrSourceRootsCached())) {
|
|
6295
5595
|
if (verbose) {
|
|
6296
5596
|
console.log(`[ns-hmr][server] ignored change (outside HMR source scope): ${file}`);
|
|
@@ -6539,8 +5839,9 @@ export const piniaSymbol = p.piniaSymbol;
|
|
|
6539
5839
|
// the framework's own template-update payload.
|
|
6540
5840
|
if (!file.endsWith('.css')) {
|
|
6541
5841
|
try {
|
|
6542
|
-
const
|
|
6543
|
-
const
|
|
5842
|
+
const appCssState = getAppCssState(server);
|
|
5843
|
+
const deps = appCssState?.deps;
|
|
5844
|
+
const appCssPath = appCssState?.path;
|
|
6544
5845
|
if (deps && appCssPath) {
|
|
6545
5846
|
const normalizedFile = path.resolve(file).replace(/\\/g, '/');
|
|
6546
5847
|
if (deps.has(normalizedFile)) {
|
|
@@ -7496,9 +6797,7 @@ if (typeof __VUE_HMR_RUNTIME__ === 'undefined') {
|
|
|
7496
6797
|
},
|
|
7497
6798
|
};
|
|
7498
6799
|
}
|
|
7499
|
-
// ----------
|
|
7500
6800
|
// Framework-specific HMR WebSocket plugins
|
|
7501
|
-
// ----------
|
|
7502
6801
|
export function hmrWebSocketVue(opts) {
|
|
7503
6802
|
ACTIVE_STRATEGY = resolveFrameworkStrategy('vue');
|
|
7504
6803
|
return createHmrWebSocketPlugin(opts);
|
|
@@ -7516,37 +6815,14 @@ export function hmrWebSocketTypescript(opts) {
|
|
|
7516
6815
|
return createHmrWebSocketPlugin(opts);
|
|
7517
6816
|
}
|
|
7518
6817
|
/**
|
|
7519
|
-
*
|
|
7520
|
-
*
|
|
7521
|
-
*
|
|
7522
|
-
*
|
|
7523
|
-
*
|
|
7524
|
-
*
|
|
7525
|
-
* `
|
|
7526
|
-
*
|
|
7527
|
-
* realms of `@nativescript/core` — a classic singleton-state split.
|
|
7528
|
-
* `internal/debug-sessions/LATEST-05-12-2026-HMR_CORE_REALM_SPLIT.md`
|
|
7529
|
-
* documents the symptom.
|
|
7530
|
-
*
|
|
7531
|
-
* Routing all platforms through `resolveDeviceReachableOrigin` keeps
|
|
7532
|
-
* them in lock-step:
|
|
7533
|
-
*
|
|
7534
|
-
* - Android wildcard / loopback → `10.0.2.2` (emulator NAT can't
|
|
7535
|
-
* reach the host's LAN IP; physical devices opt in via
|
|
7536
|
-
* `NS_HMR_PREFER_LAN_HOST=1`).
|
|
7537
|
-
*
|
|
7538
|
-
* - iOS / visionOS wildcard → `localhost` (simulator shares the
|
|
7539
|
-
* host's network stack; physical devices opt in via the same
|
|
7540
|
-
* `NS_HMR_PREFER_LAN_HOST=1` or `NS_HMR_HOST=<lan-ip>` env).
|
|
7541
|
-
*
|
|
7542
|
-
* - Explicit non-loopback `server.host` (e.g. a developer-set LAN
|
|
7543
|
-
* IP) on any platform → trusted verbatim.
|
|
7544
|
-
*
|
|
7545
|
-
* The old `resolvedUrls.network[0]` preference is intentionally
|
|
7546
|
-
* dropped — Vite reports a LAN IP whenever it detects one, but that
|
|
7547
|
-
* IP is neither reachable from an Android emulator nor consistent
|
|
7548
|
-
* with what `dev-host.ts` selects, so leaning on it created the
|
|
7549
|
-
* realm-split risk above.
|
|
6818
|
+
* Dev-server origin baked into every module served to the device
|
|
6819
|
+
* (`/ns/core/...`, `/ns/m/...`). MUST match the origin `dev-host.ts` bakes
|
|
6820
|
+
* into `bundle.mjs`; if they disagree V8 keys them as different modules and
|
|
6821
|
+
* the app ends up with two `@nativescript/core` realms (a singleton-state
|
|
6822
|
+
* split). `resolveDeviceReachableOrigin` keeps every platform in lock-step:
|
|
6823
|
+
* Android wildcard/loopback -> `10.0.2.2`, iOS/visionOS wildcard ->
|
|
6824
|
+
* `localhost`, explicit non-loopback `server.host` -> trusted verbatim
|
|
6825
|
+
* (physical devices opt into LAN via `NS_HMR_PREFER_LAN_HOST`/`NS_HMR_HOST`).
|
|
7550
6826
|
*/
|
|
7551
6827
|
function getServerOrigin(server) {
|
|
7552
6828
|
const platform = detectDevHostPlatform();
|