@nativescript/vite 8.0.0-alpha.30 → 8.0.0-alpha.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (162) hide show
  1. package/configuration/angular.js +8 -8
  2. package/configuration/angular.js.map +1 -1
  3. package/configuration/solid.js +2 -2
  4. package/configuration/solid.js.map +1 -1
  5. package/hmr/client/framework-client-strategy.d.ts +73 -0
  6. package/hmr/client/framework-client-strategy.js +19 -0
  7. package/hmr/client/framework-client-strategy.js.map +1 -0
  8. package/hmr/client/index.js +77 -186
  9. package/hmr/client/index.js.map +1 -1
  10. package/hmr/client/utils.js.map +1 -1
  11. package/hmr/entry-runtime.js.map +1 -1
  12. package/hmr/frameworks/angular/build/angular-linker.js.map +1 -0
  13. package/hmr/frameworks/angular/build/inject-component-hmr-registration.js.map +1 -0
  14. package/hmr/frameworks/angular/build/inject-hmr-vite-ignore.js.map +1 -0
  15. package/hmr/frameworks/angular/build/inline-decorator-component-templates.js.map +1 -0
  16. package/hmr/frameworks/angular/build/js-lexer.js.map +1 -0
  17. package/hmr/frameworks/angular/build/shared-linker.js.map +1 -0
  18. package/hmr/frameworks/angular/build/synthesize-decorator-ctor-parameters.js.map +1 -0
  19. package/hmr/frameworks/angular/build/synthesize-injectable-factories.js.map +1 -0
  20. package/hmr/frameworks/angular/build/util.js.map +1 -0
  21. package/hmr/frameworks/angular/client/index.js.map +1 -1
  22. package/hmr/frameworks/angular/client/strategy.d.ts +9 -0
  23. package/hmr/frameworks/angular/client/strategy.js +19 -0
  24. package/hmr/frameworks/angular/client/strategy.js.map +1 -0
  25. package/hmr/frameworks/angular/server/angular-root-component.js.map +1 -0
  26. package/hmr/frameworks/angular/server/strategy.js +440 -2
  27. package/hmr/frameworks/angular/server/strategy.js.map +1 -1
  28. package/hmr/{server → frameworks/angular/server}/websocket-angular-entry.js +2 -2
  29. package/hmr/frameworks/angular/server/websocket-angular-entry.js.map +1 -0
  30. package/hmr/{server → frameworks/angular/server}/websocket-angular-hot-update.d.ts +0 -11
  31. package/hmr/{server → frameworks/angular/server}/websocket-angular-hot-update.js +3 -80
  32. package/hmr/frameworks/angular/server/websocket-angular-hot-update.js.map +1 -0
  33. package/hmr/frameworks/solid/build/solid-jsx-deps.js.map +1 -0
  34. package/hmr/frameworks/solid/server/strategy.js +360 -1
  35. package/hmr/frameworks/solid/server/strategy.js.map +1 -1
  36. package/hmr/frameworks/typescript/server/strategy.js +27 -0
  37. package/hmr/frameworks/typescript/server/strategy.js.map +1 -1
  38. package/hmr/frameworks/vue/client/index.js.map +1 -1
  39. package/hmr/frameworks/vue/client/strategy.d.ts +7 -0
  40. package/hmr/frameworks/vue/client/strategy.js +83 -0
  41. package/hmr/frameworks/vue/client/strategy.js.map +1 -0
  42. package/hmr/frameworks/vue/client/vue-sfc-update-overlay.js.map +1 -0
  43. package/hmr/frameworks/vue/server/sfc-route-assemble.d.ts +7 -0
  44. package/hmr/{server/websocket-sfc.js → frameworks/vue/server/sfc-route-assemble.js} +19 -536
  45. package/hmr/frameworks/vue/server/sfc-route-assemble.js.map +1 -0
  46. package/hmr/frameworks/vue/server/sfc-route-meta.d.ts +7 -0
  47. package/hmr/frameworks/vue/server/sfc-route-meta.js +80 -0
  48. package/hmr/frameworks/vue/server/sfc-route-meta.js.map +1 -0
  49. package/hmr/frameworks/vue/server/sfc-route-serve.d.ts +8 -0
  50. package/hmr/frameworks/vue/server/sfc-route-serve.js +457 -0
  51. package/hmr/frameworks/vue/server/sfc-route-serve.js.map +1 -0
  52. package/hmr/frameworks/vue/server/sfc-route-shared.d.ts +19 -0
  53. package/hmr/frameworks/vue/server/sfc-route-shared.js +14 -0
  54. package/hmr/frameworks/vue/server/sfc-route-shared.js.map +1 -0
  55. package/hmr/frameworks/vue/server/strategy.js +244 -0
  56. package/hmr/frameworks/vue/server/strategy.js.map +1 -1
  57. package/hmr/frameworks/vue/server/websocket-sfc.d.ts +15 -0
  58. package/hmr/frameworks/vue/server/websocket-sfc.js +20 -0
  59. package/hmr/frameworks/vue/server/websocket-sfc.js.map +1 -0
  60. package/hmr/server/device-transform-helpers.d.ts +24 -0
  61. package/hmr/server/device-transform-helpers.js +327 -0
  62. package/hmr/server/device-transform-helpers.js.map +1 -0
  63. package/hmr/server/framework-strategy.d.ts +95 -1
  64. package/hmr/server/hmr-module-graph.js.map +1 -1
  65. package/hmr/server/import-map.d.ts +11 -2
  66. package/hmr/server/import-map.js +21 -54
  67. package/hmr/server/import-map.js.map +1 -1
  68. package/hmr/server/index.js +7 -17
  69. package/hmr/server/index.js.map +1 -1
  70. package/hmr/server/process-code-for-device.d.ts +15 -0
  71. package/hmr/server/process-code-for-device.js +654 -0
  72. package/hmr/server/process-code-for-device.js.map +1 -0
  73. package/hmr/server/rewrite-imports.d.ts +2 -0
  74. package/hmr/server/rewrite-imports.js +604 -0
  75. package/hmr/server/rewrite-imports.js.map +1 -0
  76. package/hmr/server/transform-cache-invalidation.d.ts +11 -0
  77. package/hmr/server/transform-cache-invalidation.js +84 -0
  78. package/hmr/server/transform-cache-invalidation.js.map +1 -0
  79. package/hmr/server/websocket-device-transform.d.ts +3 -21
  80. package/hmr/server/websocket-device-transform.js +6 -1569
  81. package/hmr/server/websocket-device-transform.js.map +1 -1
  82. package/hmr/server/websocket-hmr-pending.d.ts +2 -8
  83. package/hmr/server/websocket-hmr-pending.js.map +1 -1
  84. package/hmr/server/websocket-hot-update.d.ts +40 -14
  85. package/hmr/server/websocket-hot-update.js +24 -854
  86. package/hmr/server/websocket-hot-update.js.map +1 -1
  87. package/hmr/server/websocket-import-map-route.js +3 -1
  88. package/hmr/server/websocket-import-map-route.js.map +1 -1
  89. package/hmr/server/websocket-ns-core.d.ts +4 -4
  90. package/hmr/server/websocket-ns-core.js +3 -2
  91. package/hmr/server/websocket-ns-core.js.map +1 -1
  92. package/hmr/server/websocket-ns-entry.d.ts +0 -1
  93. package/hmr/server/websocket-ns-entry.js +1 -1
  94. package/hmr/server/websocket-ns-entry.js.map +1 -1
  95. package/hmr/server/websocket-ns-m.d.ts +0 -1
  96. package/hmr/server/websocket-ns-m.js +24 -129
  97. package/hmr/server/websocket-ns-m.js.map +1 -1
  98. package/hmr/server/websocket-vendor-unifier.d.ts +0 -1
  99. package/hmr/server/websocket-vendor-unifier.js +2 -1
  100. package/hmr/server/websocket-vendor-unifier.js.map +1 -1
  101. package/hmr/server/websocket.d.ts +11 -12
  102. package/hmr/server/websocket.js +25 -33
  103. package/hmr/server/websocket.js.map +1 -1
  104. package/hmr/shared/ns-globals.d.ts +118 -0
  105. package/hmr/shared/ns-globals.js +27 -0
  106. package/hmr/shared/ns-globals.js.map +1 -0
  107. package/hmr/shared/protocol.d.ts +136 -0
  108. package/hmr/shared/protocol.js +28 -0
  109. package/hmr/shared/protocol.js.map +1 -0
  110. package/hmr/shared/vendor/manifest-collect.d.ts +0 -28
  111. package/hmr/shared/vendor/manifest-collect.js +2 -2
  112. package/hmr/shared/vendor/manifest-collect.js.map +1 -1
  113. package/hmr/shared/vendor/manifest.d.ts +1 -3
  114. package/hmr/shared/vendor/manifest.js +1 -3
  115. package/hmr/shared/vendor/manifest.js.map +1 -1
  116. package/hmr/shared/vendor/vendor-esbuild-plugins.js +1 -1
  117. package/hmr/shared/vendor/vendor-esbuild-plugins.js.map +1 -1
  118. package/package.json +1 -1
  119. package/helpers/angular/angular-linker.js.map +0 -1
  120. package/helpers/angular/inject-component-hmr-registration.js.map +0 -1
  121. package/helpers/angular/inject-hmr-vite-ignore.js.map +0 -1
  122. package/helpers/angular/inline-decorator-component-templates.js.map +0 -1
  123. package/helpers/angular/js-lexer.js.map +0 -1
  124. package/helpers/angular/shared-linker.js.map +0 -1
  125. package/helpers/angular/synthesize-decorator-ctor-parameters.js.map +0 -1
  126. package/helpers/angular/synthesize-injectable-factories.js.map +0 -1
  127. package/helpers/angular/util.js.map +0 -1
  128. package/helpers/prelink-angular.d.ts +0 -2
  129. package/helpers/prelink-angular.js +0 -96
  130. package/helpers/prelink-angular.js.map +0 -1
  131. package/helpers/solid-jsx-deps.js.map +0 -1
  132. package/hmr/client/vue-sfc-update-overlay.js.map +0 -1
  133. package/hmr/server/angular-root-component.js.map +0 -1
  134. package/hmr/server/websocket-angular-entry.js.map +0 -1
  135. package/hmr/server/websocket-angular-hot-update.js.map +0 -1
  136. package/hmr/server/websocket-sfc.d.ts +0 -24
  137. package/hmr/server/websocket-sfc.js.map +0 -1
  138. /package/{helpers/angular → hmr/frameworks/angular/build}/angular-linker.d.ts +0 -0
  139. /package/{helpers/angular → hmr/frameworks/angular/build}/angular-linker.js +0 -0
  140. /package/{helpers/angular → hmr/frameworks/angular/build}/inject-component-hmr-registration.d.ts +0 -0
  141. /package/{helpers/angular → hmr/frameworks/angular/build}/inject-component-hmr-registration.js +0 -0
  142. /package/{helpers/angular → hmr/frameworks/angular/build}/inject-hmr-vite-ignore.d.ts +0 -0
  143. /package/{helpers/angular → hmr/frameworks/angular/build}/inject-hmr-vite-ignore.js +0 -0
  144. /package/{helpers/angular → hmr/frameworks/angular/build}/inline-decorator-component-templates.d.ts +0 -0
  145. /package/{helpers/angular → hmr/frameworks/angular/build}/inline-decorator-component-templates.js +0 -0
  146. /package/{helpers/angular → hmr/frameworks/angular/build}/js-lexer.d.ts +0 -0
  147. /package/{helpers/angular → hmr/frameworks/angular/build}/js-lexer.js +0 -0
  148. /package/{helpers/angular → hmr/frameworks/angular/build}/shared-linker.d.ts +0 -0
  149. /package/{helpers/angular → hmr/frameworks/angular/build}/shared-linker.js +0 -0
  150. /package/{helpers/angular → hmr/frameworks/angular/build}/synthesize-decorator-ctor-parameters.d.ts +0 -0
  151. /package/{helpers/angular → hmr/frameworks/angular/build}/synthesize-decorator-ctor-parameters.js +0 -0
  152. /package/{helpers/angular → hmr/frameworks/angular/build}/synthesize-injectable-factories.d.ts +0 -0
  153. /package/{helpers/angular → hmr/frameworks/angular/build}/synthesize-injectable-factories.js +0 -0
  154. /package/{helpers/angular → hmr/frameworks/angular/build}/util.d.ts +0 -0
  155. /package/{helpers/angular → hmr/frameworks/angular/build}/util.js +0 -0
  156. /package/hmr/{server → frameworks/angular/server}/angular-root-component.d.ts +0 -0
  157. /package/hmr/{server → frameworks/angular/server}/angular-root-component.js +0 -0
  158. /package/hmr/{server → frameworks/angular/server}/websocket-angular-entry.d.ts +0 -0
  159. /package/{helpers → hmr/frameworks/solid/build}/solid-jsx-deps.d.ts +0 -0
  160. /package/{helpers → hmr/frameworks/solid/build}/solid-jsx-deps.js +0 -0
  161. /package/hmr/{client → frameworks/vue/client}/vue-sfc-update-overlay.d.ts +0 -0
  162. /package/hmr/{client → frameworks/vue/client}/vue-sfc-update-overlay.js +0 -0
@@ -1,539 +1,22 @@
1
- import { createRequire } from 'node:module';
2
1
  import { createHash } from 'crypto';
3
2
  import { readFileSync } from 'fs';
4
3
  import * as path from 'path';
5
4
  import babelCore from '@babel/core';
6
- import { parse as babelParse } from '@babel/parser';
7
- import traverse from '@babel/traverse';
8
- import * as t from '@babel/types';
9
- import { genCode } from '../helpers/babel.js';
10
- import { setDeviceModuleHeaders } from './route-helpers.js';
11
- import { astExtractImportsAndStripTypes } from '../helpers/ast-extract.js';
12
- import { astNormalizeModuleImportsAndHelpers, astVerifyAndAnnotateDuplicates } from '../helpers/ast-normalizer.js';
13
- import { stripRtCoreSentinel, stripDanglingViteCjsImports } from '../helpers/sanitize.js';
14
- import { vueSfcCompiler } from '../frameworks/vue/server/compiler.js';
15
- import { buildInlineTemplateBlock, extractTemplateRender, processTemplateVariantMinimal } from '../frameworks/vue/server/sfc-transforms.js';
16
- import { NS_NATIVE_TAGS } from './compiler.js';
17
- import { ensureDestructureCoreImports, ensureGuardPlainDynamicImports, ensureVariableDynamicImportHelper, ensureVersionedRtImports, extractExportMetadata } from './websocket-served-module-helpers.js';
18
- import { cleanCode, processCodeForDevice, rewriteImports } from './websocket-device-transform.js';
19
- import { REQUIRE_GUARD_SNIPPET } from './require-guard.js';
20
- const babelTraverse = traverse?.default || traverse;
21
- const { parse, compileTemplate, compileScript } = vueSfcCompiler;
22
- const pluginTransformTypescript = (() => {
23
- const requireFromHere = createRequire(import.meta.url);
24
- const loaded = requireFromHere('@babel/plugin-transform-typescript');
25
- return loaded?.default || loaded;
26
- })();
5
+ import { setDeviceModuleHeaders } from '../../../server/route-helpers.js';
6
+ import { astExtractImportsAndStripTypes } from '../../../helpers/ast-extract.js';
7
+ import { astNormalizeModuleImportsAndHelpers, astVerifyAndAnnotateDuplicates } from '../../../helpers/ast-normalizer.js';
8
+ import { buildInlineTemplateBlock, extractTemplateRender } from './sfc-transforms.js';
9
+ import { NS_NATIVE_TAGS } from '../../../server/compiler.js';
10
+ import { ensureDestructureCoreImports, ensureGuardPlainDynamicImports, ensureVariableDynamicImportHelper, ensureVersionedRtImports } from '../../../server/websocket-served-module-helpers.js';
11
+ import { processCodeForDevice, rewriteImports } from '../../../server/websocket-device-transform.js';
12
+ import { REQUIRE_GUARD_SNIPPET } from '../../../server/require-guard.js';
13
+ import { getServerOrigin } from '../../../server/server-origin.js';
14
+ import { compileScript, compileTemplate, parse, pluginTransformTypescript } from './sfc-route-shared.js';
27
15
  /**
28
- * Registers the three Vue SFC endpoints on the dev server:
29
- * - `GET /ns/sfc` serves SFC modules (full delegates to the assembler; variants processed)
30
- * - `GET /ns/sfc-meta` — JSON metadata (script exports, render presence) for an SFC
31
- * - `GET /ns/asm` — deterministic, self-contained SFC assembler module
16
+ * Registers `GET /ns/asm` the deterministic, self-contained SFC assembler module.
17
+ * Extracted verbatim from `websocket-sfc.ts` (pure move, no behavior change).
32
18
  */
33
- export function registerSfcHandlers(server, options) {
34
- // 3) ESM endpoint for SFC modules: GET /ns/sfc?path=/src/Comp.vue[?vue&type=*] OR /ns/sfc/src/Comp.vue[?vue&type=*]
35
- // Also accept alias /ns/sfc
36
- // Preserves variant queries (?vue&type=script|template|style) and adds a diagnostic signature comment.
37
- server.middlewares.use(async (req, res, next) => {
38
- const strategy = options.getStrategy();
39
- try {
40
- const urlObj = new URL(req.url || '', 'http://localhost');
41
- const p = urlObj.pathname;
42
- // Only match exactly "/ns/sfc" or paths under it.
43
- const isNs = p === '/ns/sfc' || p.startsWith('/ns/sfc/');
44
- if (!isNs)
45
- return next();
46
- if (p.startsWith('/ns/asm') || p.startsWith('/ns/sfc-meta'))
47
- return next();
48
- setDeviceModuleHeaders(res);
49
- const base = '/ns/sfc';
50
- // Determine request spec, preserving variant query when present and handling optional version in path
51
- let pathParam = urlObj.searchParams.get('path') || ''; // may include its own query
52
- const rawRemainder = urlObj.pathname.slice(base.length) || '';
53
- let verFromPath = null;
54
- let pathStyle = rawRemainder;
55
- if (rawRemainder && rawRemainder.startsWith('/')) {
56
- const parts = rawRemainder.split('/'); // ["", maybe "<ver>", ...]
57
- if (parts.length > 2 && /^[0-9]+$/.test(parts[1] || '')) {
58
- verFromPath = parts[1];
59
- pathStyle = '/' + parts.slice(2).join('/');
60
- }
61
- }
62
- if (pathStyle && pathStyle !== '/' && !pathParam) {
63
- if (!pathStyle.startsWith('/'))
64
- pathStyle = '/' + pathStyle;
65
- // Include endpoint query for variant-style requests (e.g. /ns/sfc/Comp.vue?vue&type=template)
66
- pathParam = pathStyle + (urlObj.search || '');
67
- }
68
- let fullSpec = pathParam || '';
69
- if (!fullSpec) {
70
- res.statusCode = 200;
71
- res.end('export {}\n');
72
- return;
73
- }
74
- if (fullSpec.startsWith('@/'))
75
- fullSpec = options.appVirtualWithSlash + fullSpec.slice(2);
76
- if (!fullSpec.startsWith('/'))
77
- fullSpec = '/' + fullSpec;
78
- const isVariant = /[?&]vue&type=/.test(fullSpec);
79
- const variantTypeMatch = /[?&]type=([^&]+)/.exec(fullSpec);
80
- const variantType = variantTypeMatch?.[1] || null;
81
- const isStyleVariant = /[?&]type=style\b/.test(fullSpec);
82
- // Determine candidate for transformRequest
83
- // For full SFCs we prefer a clean base path + '?vue'; if that fails, try base without query as fallback.
84
- let candidate = fullSpec;
85
- let transformed = null;
86
- if (!isVariant) {
87
- const basePath = fullSpec.replace(/[?#].*$/, '');
88
- const candidates = [basePath + (basePath.includes('?') ? '&' : '?') + 'vue', basePath];
89
- for (const c of candidates) {
90
- try {
91
- const r = await server.transformRequest(c);
92
- if (r?.code) {
93
- transformed = r;
94
- candidate = c;
95
- break;
96
- }
97
- }
98
- catch { }
99
- }
100
- if (!transformed?.code) {
101
- if (options.verbose) {
102
- console.warn(`[sfc][serve] transform miss for`, fullSpec);
103
- }
104
- // Emit an erroring module to surface the failure at import site with helpful hints
105
- try {
106
- const tried = candidates.slice(0, 8);
107
- const out = `// [sfc] transform miss kind=full path=${fullSpec.replace(/\n/g, '')} tried=${tried.length}\n` + `throw new Error(${JSON.stringify('[ns/sfc] transform failed for full SFC: ' + fullSpec + ' (tried ' + tried.length + ')')});\nexport {}\n`;
108
- res.statusCode = 404;
109
- res.end(out);
110
- return;
111
- }
112
- catch {
113
- res.statusCode = 404;
114
- res.end('export {}\n');
115
- return;
116
- }
117
- }
118
- }
119
- else {
120
- try {
121
- transformed = await server.transformRequest(candidate);
122
- }
123
- catch { }
124
- if (!transformed?.code) {
125
- try {
126
- const out = `// [sfc] transform miss kind=variant path=${fullSpec.replace(/\n/g, '')}\n` + `throw new Error(${JSON.stringify('[ns/sfc] transform failed for variant: ' + fullSpec)});\nexport {}\n`;
127
- res.statusCode = 404;
128
- res.end(out);
129
- return;
130
- }
131
- catch {
132
- res.statusCode = 404;
133
- res.end('export {}\n');
134
- return;
135
- }
136
- }
137
- }
138
- // For style variants, return an empty module immediately
139
- if (isStyleVariant) {
140
- const sig = `// [sfc] kind=variant:style path=${fullSpec.replace(/\n/g, '')} len=0 default=false\n`;
141
- res.statusCode = 200;
142
- res.end(`${sig}export {}\n`);
143
- return;
144
- }
145
- let code = transformed.code;
146
- // Prepend guard to capture any URL-based require attempts
147
- code = REQUIRE_GUARD_SNIPPET + code;
148
- const projectRoot = server.config?.root || process.cwd();
149
- // IMPORTANT: Do not run cleanCode() on template variant; it can strip required pieces.
150
- // We'll handle script/full SFC below, and treat template minimally right away.
151
- // Full SFCs delegate to deterministic assembler module; variants (script/template) still go through processing
152
- if (!isVariant) {
153
- const importerPath = fullSpec.replace(/[?#].*$/, '');
154
- const ver = verFromPath || '0';
155
- const asmPath = `/ns/asm/${ver}?path=${encodeURIComponent(importerPath)}`;
156
- const delegated = `// [sfc] kind=full (delegated to assembler) path=${importerPath}\nexport * from ${JSON.stringify(asmPath)};\nexport { default } from ${JSON.stringify(asmPath)};\n`;
157
- res.statusCode = 200;
158
- res.end(delegated);
159
- return;
160
- }
161
- else {
162
- // Variants
163
- if (variantType === 'template') {
164
- const preferSelfCompile = !!process.env.NS_HMR_SELF_COMPILE_TEMPLATE;
165
- // Compile the template ourselves to guarantee no Vite HMR code and stable output
166
- if (preferSelfCompile)
167
- try {
168
- const projectRootT = server.config?.root || process.cwd();
169
- const basePath = fullSpec.replace(/[?#].*$/, '');
170
- const abs = path.join(projectRootT, basePath.replace(/^\//, ''));
171
- let sfcSrc = '';
172
- try {
173
- sfcSrc = readFileSync(abs, 'utf-8');
174
- }
175
- catch { }
176
- if (sfcSrc) {
177
- const { descriptor } = parse(sfcSrc, { filename: abs });
178
- const id = createHash('md5').update(abs).digest('hex').slice(0, 8);
179
- let bindingMetadata = undefined;
180
- try {
181
- const s = compileScript(descriptor, {
182
- id,
183
- inlineTemplate: false,
184
- reactivityTransform: false,
185
- });
186
- bindingMetadata = s?.bindings;
187
- }
188
- catch { }
189
- const tpl = descriptor.template?.content || '';
190
- const ct = compileTemplate({
191
- source: tpl,
192
- id,
193
- filename: abs,
194
- isProd: false,
195
- ssr: false,
196
- compilerOptions: {
197
- bindingMetadata,
198
- isCustomElement: (tag) => NS_NATIVE_TAGS.has(tag),
199
- },
200
- });
201
- let out = (ct && (ct.code || '')) || '';
202
- // Map Vue helper imports to runtime bridge
203
- try {
204
- out = out.replace(/from\s+["'](?:nativescript-vue|vue)[^"']*["']/g, 'from "/ns/rt"');
205
- }
206
- catch { }
207
- // No import.meta.hot present when compiling ourselves, but keep minimal sanitizer just in case
208
- out = processTemplateVariantMinimal(out);
209
- code = out;
210
- }
211
- else {
212
- code = 'export {}\n';
213
- }
214
- }
215
- catch (eTplSelf) {
216
- if (options.verbose) {
217
- console.warn('[sfc][template][self-compile][fail]', fullSpec, eTplSelf?.message);
218
- }
219
- code = transformed.code || 'export {}\n';
220
- code = processTemplateVariantMinimal(code);
221
- }
222
- else {
223
- // Prefer using Vite's template transform and apply minimal sanitization; avoids compiler mismatches and warnings
224
- code = transformed.code || 'export {}\n';
225
- code = processTemplateVariantMinimal(code);
226
- }
227
- // fall through to shared post-processing (versioning, signature, etc.)
228
- }
229
- // Script variants still need vendor mappings and general device processing (no SFC assembly)
230
- // IMPORTANT: Use a Babel AST transform to remove imports of the template variant and
231
- // neutralize their usage without brittle regex.
232
- try {
233
- const ast = babelParse(code, {
234
- sourceType: 'module',
235
- plugins: ['typescript'],
236
- });
237
- const templateBindings = new Set();
238
- const navToLocals = [];
239
- const navBackLocals = [];
240
- babelTraverse(ast, {
241
- ImportDeclaration(path) {
242
- const spec = path.node.source.value || '';
243
- // Remove template variant imports and collect their local identifiers for neutralization
244
- if (typeof spec === 'string' && /\.vue\?[^\n]*type=template/.test(spec)) {
245
- const ids = [];
246
- for (const s of path.node.specifiers) {
247
- if (t.isImportSpecifier(s)) {
248
- const imported = t.isIdentifier(s.imported) ? s.imported.name : undefined;
249
- const local = t.isIdentifier(s.local) ? s.local.name : undefined;
250
- if ((imported === 'render' || imported === undefined) && local)
251
- ids.push(local);
252
- }
253
- else if (t.isImportDefaultSpecifier(s) || t.isImportNamespaceSpecifier(s)) {
254
- if (t.isIdentifier(s.local))
255
- ids.push(s.local.name);
256
- }
257
- }
258
- ids.forEach((n) => templateBindings.add(n));
259
- path.remove();
260
- return;
261
- }
262
- // Rewrite $navigateTo/$navigateBack imports from nativescript-vue (or prebundle) to use globals
263
- const isNsVue = typeof spec === 'string' && (/nativescript-vue/.test(spec) || /vendor\.mjs$/.test(spec) || /\/node_modules\/\.vite\/deps\/nativescript-vue\.js/.test(spec));
264
- if (isNsVue) {
265
- const remain = [];
266
- for (const s of path.node.specifiers) {
267
- if (t.isImportSpecifier(s)) {
268
- const imported = t.isIdentifier(s.imported) ? s.imported.name : undefined;
269
- const local = t.isIdentifier(s.local) ? s.local.name : undefined;
270
- if (local && (imported === '$navigateTo' || imported === 'navigateTo')) {
271
- navToLocals.push(local);
272
- continue;
273
- }
274
- if (local && (imported === '$navigateBack' || imported === 'navigateBack')) {
275
- navBackLocals.push(local);
276
- continue;
277
- }
278
- }
279
- remain.push(s);
280
- }
281
- if (remain.length) {
282
- path.node.specifiers = remain;
283
- }
284
- else {
285
- path.remove();
286
- }
287
- }
288
- },
289
- });
290
- if (templateBindings.size) {
291
- babelTraverse(ast, {
292
- Identifier(path) {
293
- if (templateBindings.has(path.node.name)) {
294
- path.replaceWith(t.identifier('undefined'));
295
- }
296
- },
297
- AssignmentExpression(path) {
298
- // Guard component.render = <alias> to avoid TDZ when alias is undefined
299
- if (t.isMemberExpression(path.node.left) &&
300
- t.isIdentifier(path.node.left.property, {
301
- name: 'render',
302
- })) {
303
- const e = t.identifier('__e');
304
- const guarded = t.tryStatement(t.blockStatement([t.variableDeclaration('const', [t.variableDeclarator(e, path.node.right)]), t.ifStatement(t.logicalExpression('&&', t.binaryExpression('!==', t.unaryExpression('typeof', path.node.left.object, true), t.stringLiteral('undefined')), t.binaryExpression('!==', t.unaryExpression('typeof', e, true), t.stringLiteral('undefined'))), t.blockStatement([t.expressionStatement(t.assignmentExpression('=', path.node.left, e))]))]), t.catchClause(t.identifier('_e'), t.blockStatement([])));
305
- path.replaceWithMultiple([guarded]);
306
- }
307
- },
308
- });
309
- }
310
- let outCode = genCode(ast).code;
311
- if (navToLocals.length || navBackLocals.length) {
312
- const shimLines = [];
313
- for (const n of navToLocals)
314
- shimLines.push(`import __ns_rt_nav_to_mod from "/ns/rt";\nconst ${n} = (...args) => __ns_rt_nav_to_mod.$navigateTo(...args);`);
315
- for (const n of navBackLocals)
316
- shimLines.push(`import __ns_rt_nav_back_mod from "/ns/rt";\nconst ${n} = (...args) => __ns_rt_nav_back_mod.$navigateBack(...args);`);
317
- outCode = shimLines.join('\n') + '\n' + outCode;
318
- }
319
- code = outCode;
320
- }
321
- catch { }
322
- code = processCodeForDevice(code, false, true, /(?:^|\/)node_modules\//.test(fullSpec), fullSpec);
323
- // Transform static .vue imports into static imports from the assembler (no TLA) via AST
324
- try {
325
- const importerPath = fullSpec.replace(/[?#].*$/, '');
326
- const ver = verFromPath || '0';
327
- const ast2 = babelParse(code, {
328
- sourceType: 'module',
329
- plugins: ['typescript'],
330
- });
331
- babelTraverse(ast2, {
332
- ImportDeclaration(p) {
333
- const src = p.node.source.value || '';
334
- if (typeof src !== 'string')
335
- return;
336
- if (/^https?:\/\//.test(src))
337
- return; // leave absolute URLs
338
- if (/\.vue(?:$|\?)/.test(src)) {
339
- let spec = src;
340
- // Resolve to absolute project path
341
- if (spec.startsWith('./') || spec.startsWith('../')) {
342
- spec = path.posix.normalize(path.posix.join(path.posix.dirname(importerPath), spec));
343
- if (!spec.startsWith('/'))
344
- spec = '/' + spec;
345
- }
346
- else if (!spec.startsWith('/')) {
347
- // Handle '@/'
348
- if (spec.startsWith('@@/'))
349
- spec = '/' + spec.slice(2);
350
- if (spec.startsWith('@/'))
351
- spec = options.appVirtualWithSlash + spec.slice(2);
352
- }
353
- // Strip query for plain .vue (keep variant imports intact)
354
- if (!/\bvue&type=/.test(src)) {
355
- spec = spec.replace(/[?#].*$/, '');
356
- const asmUrl = `/ns/asm/${ver}?path=${encodeURIComponent(spec)}&mode=inline`;
357
- p.node.source = t.stringLiteral(asmUrl);
358
- }
359
- }
360
- },
361
- });
362
- code = genCode(ast2).code;
363
- }
364
- catch { }
365
- // After rewrites, strip any TypeScript syntax from the script variant to avoid device-side parse errors
366
- try {
367
- const importerPath = fullSpec.replace(/[?#].*$/, '');
368
- const tsRes = await babelCore.transformAsync(code, {
369
- plugins: [[pluginTransformTypescript, { allowDeclareFields: true }]],
370
- sourceType: 'module',
371
- // Help Babel infer TS parsing even if the virtual filename isn't .ts
372
- filename: importerPath.endsWith('.vue') ? importerPath.replace(/\.vue$/, '.ts') : importerPath + '.ts',
373
- comments: true,
374
- configFile: false,
375
- babelrc: false,
376
- });
377
- if (tsRes?.code) {
378
- code = tsRes.code;
379
- }
380
- }
381
- catch (eTsVar) {
382
- if (options.verbose) {
383
- console.warn('[sfc][variant:script][babel-ts][fail]', fullSpec, eTsVar?.message);
384
- }
385
- }
386
- }
387
- const importerPath = fullSpec.replace(/[?#].*$/, '');
388
- // Only run cleanCode for non-template cases (script/full). Template code must remain intact.
389
- if (!isVariant || variantType !== 'template') {
390
- code = cleanCode(code, strategy);
391
- }
392
- code = rewriteImports(code, importerPath, options.sfcFileMap, options.depFileMap, projectRoot, !!options.verbose, undefined, options.getServerOrigin(server));
393
- code = ensureVariableDynamicImportHelper(code);
394
- try {
395
- // For variant requests under /ns/sfc, prefer the version from the path segment when present
396
- // so that any internal '/ns/rt' or '/ns/sfc' imports are aligned with the same version.
397
- // `/ns/core` URLs are intentionally unversioned (realm-split history).
398
- const verNum = Number(verFromPath || '0');
399
- if (Number.isFinite(verNum) && verNum > 0) {
400
- code = ensureVersionedRtImports(code, options.getServerOrigin(server), verNum);
401
- code = strategy.ensureVersionedImports?.(code, options.getServerOrigin(server), verNum) ?? code;
402
- }
403
- else {
404
- code = ensureVersionedRtImports(code, options.getServerOrigin(server), options.getGraphVersion());
405
- code = strategy.ensureVersionedImports?.(code, options.getServerOrigin(server), options.getGraphVersion()) ?? code;
406
- }
407
- }
408
- catch { }
409
- // Final guard for SFC variant output as well
410
- try {
411
- code = ensureDestructureCoreImports(code);
412
- }
413
- catch { }
414
- // CRITICAL: As a last step for script/template variants, re-run AST normalization and strip
415
- // any sentinel destructures that could cause duplicate locals, then re-apply rt versioning.
416
- try {
417
- code = astNormalizeModuleImportsAndHelpers(code);
418
- }
419
- catch { }
420
- try {
421
- // Remove any rt->core sentinel destructures that slipped in late
422
- code = stripRtCoreSentinel(code);
423
- }
424
- catch { }
425
- try {
426
- const verNum = Number(verFromPath || '0');
427
- if (Number.isFinite(verNum) && verNum > 0) {
428
- code = ensureVersionedRtImports(code, options.getServerOrigin(server), verNum);
429
- }
430
- else {
431
- code = ensureVersionedRtImports(code, options.getServerOrigin(server), options.getGraphVersion());
432
- }
433
- }
434
- catch { }
435
- // Last-chance sanitizer for dangling Vite CJS import helper usages that may surface after late transforms
436
- try {
437
- code = stripDanglingViteCjsImports(code);
438
- }
439
- catch { }
440
- const hasDefault = /\bexport\s+default\b/.test(code);
441
- const kind = isVariant ? `variant:${variantType || 'unknown'}` : 'full';
442
- const sig = `// [sfc] kind=${kind} path=${importerPath} len=${code.length} default=${hasDefault} wrapped=${false}\n`;
443
- if (options.verbose) {
444
- console.log(`[sfc][serve] ${fullSpec} kind=${kind} default=${hasDefault} bytes=${code.length}`);
445
- }
446
- // Ensure script variants always provide a default export if they declare a component
447
- if (!hasDefault) {
448
- // Prefer an explicit identifier if present
449
- const m = code.match(/\b(?:const|let|var)\s+(__ns_sfc__|_sfc_main)\b/);
450
- if (m && m[1]) {
451
- code += `\nexport default ${m[1]};`;
452
- }
453
- else if (/\b_defineComponent\s*\(|\bdefineComponent\s*\(/.test(code)) {
454
- // Fallback: export whichever is defined at runtime without throwing on missing identifiers
455
- code += `\nexport default (typeof __ns_sfc__ !== "undefined" ? __ns_sfc__ : (typeof _sfc_main !== "undefined" ? _sfc_main : undefined));`;
456
- }
457
- }
458
- res.statusCode = 200;
459
- res.end(sig + code);
460
- }
461
- catch (e) {
462
- res.statusCode = 500;
463
- res.end('export {}\n');
464
- }
465
- });
466
- // 4) JSON metadata endpoint for SFCs: GET /ns/sfc-meta?path=/src/Comp.vue OR /ns/sfc-meta/<ver>?path=/src/Comp.vue
467
- server.middlewares.use(async (req, res, next) => {
468
- try {
469
- const urlObj = new URL(req.url || '', 'http://localhost');
470
- if (!urlObj.pathname.startsWith('/ns/sfc-meta'))
471
- return next();
472
- res.setHeader('Access-Control-Allow-Origin', '*');
473
- res.setHeader('Content-Type', 'application/json; charset=utf-8');
474
- res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0');
475
- res.setHeader('Pragma', 'no-cache');
476
- res.setHeader('Expires', '0');
477
- // Accept optional version segment similar to /ns/sfc
478
- {
479
- const metaBase = '/ns/sfc-meta';
480
- if (urlObj.pathname.startsWith(metaBase + '/')) {
481
- const rawRemainder = urlObj.pathname.slice(metaBase.length);
482
- const parts = rawRemainder.split('/');
483
- if (parts.length > 2 && /^[0-9]+$/.test(parts[1] || '')) {
484
- // consume version but we don't need it server-side
485
- }
486
- }
487
- }
488
- let spec = urlObj.searchParams.get('path') || '';
489
- if (!spec) {
490
- res.statusCode = 400;
491
- res.end(JSON.stringify({ error: 'missing path' }));
492
- return;
493
- }
494
- if (spec.startsWith('@/'))
495
- spec = options.appVirtualWithSlash + spec.slice(2);
496
- if (!spec.startsWith('/'))
497
- spec = '/' + spec;
498
- const base = spec.replace(/[?#].*$/, '');
499
- // Transform variants to inspect exports
500
- const [scriptR, templateR] = await Promise.all([server.transformRequest(base + '?vue&type=script'), server.transformRequest(base + '?vue&type=template')]);
501
- const scriptCode = scriptR?.code || '';
502
- const templateCode = templateR?.code || '';
503
- const scriptMeta = extractExportMetadata(scriptCode);
504
- // Robust render detection: Vue compiler may emit several shapes:
505
- // 1) export function render(_ctx, _cache) { ... }
506
- // 2) function render(_ctx,_cache) { ... } (later exported)
507
- // 3) export const render = (_ctx,_cache) => { ... }
508
- // 4) const render = (...) => { ... } (later exported)
509
- // 5) export { render } or export { render as render }
510
- // 6) Object property forms (rare in template output) render: (...) => {}
511
- const hasRender = /export\s+function\s+render\s*\(/.test(templateCode) || /(?:^|\n)\s*function\s+render\s*\(/.test(templateCode) || /export\s+(?:const|let|var)\s+render\s*=/.test(templateCode) || /(?:^|\n)\s*(?:const|let|var)\s+render\s*=/.test(templateCode) || /\brender\s*[:=]\s*/.test(templateCode) || /export\s*\{\s*render\s*(?:as\s*render)?\s*\}/.test(templateCode);
512
- if (hasRender && options.verbose) {
513
- console.log('[sfc-meta] detected render for', base);
514
- }
515
- else if (!hasRender && options.verbose) {
516
- console.warn('[sfc-meta] render NOT detected for', base);
517
- }
518
- const hash = createHash('md5').update(base).digest('hex').slice(0, 8);
519
- const payload = {
520
- path: base,
521
- hasScript: !!scriptCode,
522
- hasTemplate: !!templateCode,
523
- hasStyle: false,
524
- scriptExports: scriptMeta.named,
525
- scriptHasDefault: scriptMeta.hasDefault,
526
- templateHasRender: hasRender,
527
- hmrId: hash,
528
- };
529
- res.statusCode = 200;
530
- res.end(JSON.stringify(payload));
531
- }
532
- catch (e) {
533
- res.statusCode = 500;
534
- res.end(JSON.stringify({ error: e?.message || String(e) }));
535
- }
536
- });
19
+ export function registerSfcAsmRoute(server, options) {
537
20
  // 5) Deterministic SFC assembler: GET /ns/asm?path=/src/Comp.vue
538
21
  // Place BEFORE any broader /ns/sfc* handlers that might accidentally match and delegate.
539
22
  server.middlewares.use(async (req, res, next) => {
@@ -586,7 +69,7 @@ export function registerSfcHandlers(server, options) {
586
69
  // Warm Vite's transform cache for the full-SFC URL; result is unused (the
587
70
  // assembler reads the SFC from disk and compiles it inline below).
588
71
  await safeTransform(base + '?vue');
589
- const origin = options.getServerOrigin(server);
72
+ const origin = getServerOrigin(server);
590
73
  const ver = String(verFromPath || options.getGraphVersion() || Date.now());
591
74
  const scriptUrl = `${origin}/ns/sfc/${ver}${base}?vue&type=script`;
592
75
  const templateCode = templateR?.code || '';
@@ -942,7 +425,7 @@ export function registerSfcHandlers(server, options) {
942
425
  // Removed redundant render closure heal that could inject an extra '}' before component script.
943
426
  // Rewrite any remaining imports (e.g., relative app paths) to HTTP ESM endpoints
944
427
  try {
945
- inlineCode2 = rewriteImports(inlineCode2, base, options.sfcFileMap, options.depFileMap, projectRoot, !!options.verbose, undefined, options.getServerOrigin(server));
428
+ inlineCode2 = rewriteImports(inlineCode2, base, options.sfcFileMap, options.depFileMap, projectRoot, !!options.verbose, undefined, getServerOrigin(server));
946
429
  }
947
430
  catch { }
948
431
  // Final TS strip on the whole assembled module (safety net)
@@ -1091,7 +574,7 @@ export function registerSfcHandlers(server, options) {
1091
574
  catch { }
1092
575
  // Bust device cache for runtime bridge so helpers are always current for this graph version
1093
576
  try {
1094
- const origin = options.getServerOrigin(server);
577
+ const origin = getServerOrigin(server);
1095
578
  inlineCode2 = ensureVersionedRtImports(inlineCode2, origin, Number(ver));
1096
579
  inlineCode2 = strategy.ensureVersionedImports?.(inlineCode2, origin, Number(ver)) ?? inlineCode2;
1097
580
  }
@@ -1197,7 +680,7 @@ export function registerSfcHandlers(server, options) {
1197
680
  // Run full device processing so helper aliasing and globals are consistent in this path too
1198
681
  let code = REQUIRE_GUARD_SNIPPET + asm;
1199
682
  code = processCodeForDevice(code, false, true, /(?:^|\/)node_modules\//.test(base), base);
1200
- code = rewriteImports(code, base, options.sfcFileMap, options.depFileMap, projectRoot, !!options.verbose, undefined, options.getServerOrigin(server));
683
+ code = rewriteImports(code, base, options.sfcFileMap, options.depFileMap, projectRoot, !!options.verbose, undefined, getServerOrigin(server));
1201
684
  try {
1202
685
  code = ensureDestructureCoreImports(code);
1203
686
  }
@@ -1205,7 +688,7 @@ export function registerSfcHandlers(server, options) {
1205
688
  code = ensureVariableDynamicImportHelper(code);
1206
689
  code = ensureGuardPlainDynamicImports(code);
1207
690
  try {
1208
- const origin = options.getServerOrigin(server);
691
+ const origin = getServerOrigin(server);
1209
692
  code = ensureVersionedRtImports(code, origin, Number(ver));
1210
693
  code = strategy.ensureVersionedImports?.(code, origin, Number(ver)) ?? code;
1211
694
  }
@@ -1220,4 +703,4 @@ export function registerSfcHandlers(server, options) {
1220
703
  }
1221
704
  });
1222
705
  }
1223
- //# sourceMappingURL=websocket-sfc.js.map
706
+ //# sourceMappingURL=sfc-route-assemble.js.map