@nativescript/vite 8.0.0-alpha.3 → 8.0.0-alpha.4
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/hmr/server/websocket-ns-m-finalize.d.ts +32 -0
- package/hmr/server/websocket-ns-m-finalize.js +73 -0
- package/hmr/server/websocket-ns-m-finalize.js.map +1 -0
- package/hmr/server/websocket-ns-m-paths.d.ts +3 -0
- package/hmr/server/websocket-ns-m-paths.js +47 -0
- package/hmr/server/websocket-ns-m-paths.js.map +1 -0
- package/hmr/server/websocket-ns-m-request.d.ts +35 -0
- package/hmr/server/websocket-ns-m-request.js +203 -0
- package/hmr/server/websocket-ns-m-request.js.map +1 -0
- package/hmr/server/websocket-runtime-compat.d.ts +19 -0
- package/hmr/server/websocket-runtime-compat.js +286 -0
- package/hmr/server/websocket-runtime-compat.js.map +1 -0
- package/hmr/server/websocket-txn.d.ts +6 -0
- package/hmr/server/websocket-txn.js +45 -0
- package/hmr/server/websocket-txn.js.map +1 -0
- package/hmr/server/websocket-vendor-unifier.d.ts +10 -0
- package/hmr/server/websocket-vendor-unifier.js +51 -0
- package/hmr/server/websocket-vendor-unifier.js.map +1 -0
- package/hmr/server/websocket-vue-sfc.d.ts +35 -0
- package/hmr/server/websocket-vue-sfc.js +1116 -0
- package/hmr/server/websocket-vue-sfc.js.map +1 -0
- package/hmr/server/websocket.d.ts +1 -1
- package/hmr/server/websocket.js +98 -2028
- package/hmr/server/websocket.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,1116 @@
|
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
2
|
+
import { createHash } from 'crypto';
|
|
3
|
+
import { readFileSync } from 'fs';
|
|
4
|
+
import * as path from 'path';
|
|
5
|
+
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 { astExtractImportsAndStripTypes } from '../helpers/ast-extract.js';
|
|
11
|
+
import { astNormalizeModuleImportsAndHelpers, astVerifyAndAnnotateDuplicates } from '../helpers/ast-normalizer.js';
|
|
12
|
+
import { stripRtCoreSentinel, stripDanglingViteCjsImports } from '../helpers/sanitize.js';
|
|
13
|
+
import { vueSfcCompiler } from '../frameworks/vue/server/compiler.js';
|
|
14
|
+
import { buildInlineTemplateBlock, extractTemplateRender, processTemplateVariantMinimal } from '../frameworks/vue/server/sfc-transforms.js';
|
|
15
|
+
import { NS_NATIVE_TAGS } from './compiler.js';
|
|
16
|
+
const babelTraverse = traverse?.default || traverse;
|
|
17
|
+
const { parse, compileTemplate, compileScript } = vueSfcCompiler;
|
|
18
|
+
const pluginTransformTypescript = (() => {
|
|
19
|
+
const requireFromHere = createRequire(import.meta.url);
|
|
20
|
+
const loaded = requireFromHere('@babel/plugin-transform-typescript');
|
|
21
|
+
return loaded?.default || loaded;
|
|
22
|
+
})();
|
|
23
|
+
function setJavascriptResponseHeaders(res) {
|
|
24
|
+
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
25
|
+
res.setHeader('Content-Type', 'application/javascript; charset=utf-8');
|
|
26
|
+
res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0');
|
|
27
|
+
res.setHeader('Pragma', 'no-cache');
|
|
28
|
+
res.setHeader('Expires', '0');
|
|
29
|
+
}
|
|
30
|
+
function setJsonResponseHeaders(res) {
|
|
31
|
+
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
32
|
+
res.setHeader('Content-Type', 'application/json; charset=utf-8');
|
|
33
|
+
res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0');
|
|
34
|
+
res.setHeader('Pragma', 'no-cache');
|
|
35
|
+
res.setHeader('Expires', '0');
|
|
36
|
+
}
|
|
37
|
+
export function parseVersionedEndpointPath(basePath, pathname) {
|
|
38
|
+
const rawRemainder = pathname.slice(basePath.length) || '';
|
|
39
|
+
let verFromPath = null;
|
|
40
|
+
let pathStyle = rawRemainder;
|
|
41
|
+
if (rawRemainder && rawRemainder.startsWith('/')) {
|
|
42
|
+
const parts = rawRemainder.split('/');
|
|
43
|
+
if (parts.length > 2 && /^[0-9]+$/.test(parts[1] || '')) {
|
|
44
|
+
verFromPath = parts[1];
|
|
45
|
+
pathStyle = '/' + parts.slice(2).join('/');
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return { verFromPath, pathStyle };
|
|
49
|
+
}
|
|
50
|
+
export function buildSfcDelegatedModule(importerPath, version) {
|
|
51
|
+
const asmPath = `/ns/asm/${version}?path=${encodeURIComponent(importerPath)}`;
|
|
52
|
+
return `// [sfc] kind=full (delegated to assembler) path=${importerPath}\nexport * from ${JSON.stringify(asmPath)};\nexport { default } from ${JSON.stringify(asmPath)};\n`;
|
|
53
|
+
}
|
|
54
|
+
export function templateHasRender(templateCode) {
|
|
55
|
+
return /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);
|
|
56
|
+
}
|
|
57
|
+
function normalizeRequestedSpec(spec, appVirtualWithSlash) {
|
|
58
|
+
let normalized = spec || '';
|
|
59
|
+
if (normalized.startsWith('@/'))
|
|
60
|
+
normalized = appVirtualWithSlash + normalized.slice(2);
|
|
61
|
+
if (!normalized.startsWith('/'))
|
|
62
|
+
normalized = '/' + normalized;
|
|
63
|
+
return normalized;
|
|
64
|
+
}
|
|
65
|
+
export function registerVueSfcHandlers(server, options) {
|
|
66
|
+
server.middlewares.use(async (req, res, next) => {
|
|
67
|
+
try {
|
|
68
|
+
const urlObj = new URL(req.url || '', 'http://localhost');
|
|
69
|
+
const pathname = urlObj.pathname;
|
|
70
|
+
const isNs = pathname === '/ns/sfc' || pathname.startsWith('/ns/sfc/');
|
|
71
|
+
if (!isNs)
|
|
72
|
+
return next();
|
|
73
|
+
if (pathname.startsWith('/ns/asm') || pathname.startsWith('/ns/sfc-meta'))
|
|
74
|
+
return next();
|
|
75
|
+
setJavascriptResponseHeaders(res);
|
|
76
|
+
const basePath = '/ns/sfc';
|
|
77
|
+
let pathParam = urlObj.searchParams.get('path') || '';
|
|
78
|
+
const { verFromPath, pathStyle: rawPathStyle } = parseVersionedEndpointPath(basePath, pathname);
|
|
79
|
+
let pathStyle = rawPathStyle;
|
|
80
|
+
if (pathStyle && pathStyle !== '/' && !pathParam) {
|
|
81
|
+
if (!pathStyle.startsWith('/'))
|
|
82
|
+
pathStyle = '/' + pathStyle;
|
|
83
|
+
pathParam = pathStyle + (urlObj.search || '');
|
|
84
|
+
}
|
|
85
|
+
let fullSpec = pathParam || '';
|
|
86
|
+
if (!fullSpec) {
|
|
87
|
+
res.statusCode = 200;
|
|
88
|
+
res.end('export {}\n');
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
fullSpec = normalizeRequestedSpec(fullSpec, options.appVirtualWithSlash);
|
|
92
|
+
const isVariant = /[?&]vue&type=/.test(fullSpec);
|
|
93
|
+
const variantTypeMatch = /[?&]type=([^&]+)/.exec(fullSpec);
|
|
94
|
+
const variantType = variantTypeMatch?.[1] || null;
|
|
95
|
+
const isStyleVariant = /[?&]type=style\b/.test(fullSpec);
|
|
96
|
+
let candidate = fullSpec;
|
|
97
|
+
let transformed = null;
|
|
98
|
+
if (!isVariant) {
|
|
99
|
+
const baseFilePath = fullSpec.replace(/[?#].*$/, '');
|
|
100
|
+
const candidates = [baseFilePath + (baseFilePath.includes('?') ? '&' : '?') + 'vue', baseFilePath];
|
|
101
|
+
for (const currentCandidate of candidates) {
|
|
102
|
+
try {
|
|
103
|
+
const result = await server.transformRequest(currentCandidate);
|
|
104
|
+
if (result?.code) {
|
|
105
|
+
transformed = result;
|
|
106
|
+
candidate = currentCandidate;
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
catch { }
|
|
111
|
+
}
|
|
112
|
+
if (!transformed?.code) {
|
|
113
|
+
if (options.verbose) {
|
|
114
|
+
try {
|
|
115
|
+
console.warn('[sfc][serve] transform miss for', fullSpec);
|
|
116
|
+
}
|
|
117
|
+
catch { }
|
|
118
|
+
}
|
|
119
|
+
try {
|
|
120
|
+
const tried = candidates.slice(0, 8);
|
|
121
|
+
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`;
|
|
122
|
+
res.statusCode = 404;
|
|
123
|
+
res.end(out);
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
res.statusCode = 404;
|
|
128
|
+
res.end('export {}\n');
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
try {
|
|
135
|
+
transformed = await server.transformRequest(candidate);
|
|
136
|
+
}
|
|
137
|
+
catch { }
|
|
138
|
+
if (!transformed?.code) {
|
|
139
|
+
try {
|
|
140
|
+
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`;
|
|
141
|
+
res.statusCode = 404;
|
|
142
|
+
res.end(out);
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
catch {
|
|
146
|
+
res.statusCode = 404;
|
|
147
|
+
res.end('export {}\n');
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
if (isStyleVariant) {
|
|
153
|
+
const sig = `// [sfc] kind=variant:style path=${fullSpec.replace(/\n/g, '')} len=0 default=false\n`;
|
|
154
|
+
res.statusCode = 200;
|
|
155
|
+
res.end(`${sig}export {}\n`);
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
let code = transformed.code;
|
|
159
|
+
code = options.requireGuardSnippet + code;
|
|
160
|
+
const projectRoot = server.config?.root || process.cwd();
|
|
161
|
+
if (!isVariant) {
|
|
162
|
+
const importerPath = fullSpec.replace(/[?#].*$/, '');
|
|
163
|
+
const version = verFromPath || '0';
|
|
164
|
+
res.statusCode = 200;
|
|
165
|
+
res.end(buildSfcDelegatedModule(importerPath, version));
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
if (variantType === 'template') {
|
|
169
|
+
const preferSelfCompile = !!process.env.NS_HMR_SELF_COMPILE_TEMPLATE;
|
|
170
|
+
if (preferSelfCompile) {
|
|
171
|
+
try {
|
|
172
|
+
const projectRootTemplate = server.config?.root || process.cwd();
|
|
173
|
+
const baseFilePath = fullSpec.replace(/[?#].*$/, '');
|
|
174
|
+
const absolutePath = path.join(projectRootTemplate, baseFilePath.replace(/^\//, ''));
|
|
175
|
+
let sfcSource = '';
|
|
176
|
+
try {
|
|
177
|
+
sfcSource = readFileSync(absolutePath, 'utf-8');
|
|
178
|
+
}
|
|
179
|
+
catch { }
|
|
180
|
+
if (sfcSource) {
|
|
181
|
+
const { descriptor } = parse(sfcSource, { filename: absolutePath });
|
|
182
|
+
const id = createHash('md5').update(absolutePath).digest('hex').slice(0, 8);
|
|
183
|
+
let bindingMetadata = undefined;
|
|
184
|
+
try {
|
|
185
|
+
const script = compileScript(descriptor, {
|
|
186
|
+
id,
|
|
187
|
+
inlineTemplate: false,
|
|
188
|
+
reactivityTransform: false,
|
|
189
|
+
});
|
|
190
|
+
bindingMetadata = script?.bindings;
|
|
191
|
+
}
|
|
192
|
+
catch { }
|
|
193
|
+
const templateSource = descriptor.template?.content || '';
|
|
194
|
+
const compiledTemplate = compileTemplate({
|
|
195
|
+
source: templateSource,
|
|
196
|
+
id,
|
|
197
|
+
filename: absolutePath,
|
|
198
|
+
isProd: false,
|
|
199
|
+
ssr: false,
|
|
200
|
+
compilerOptions: {
|
|
201
|
+
bindingMetadata,
|
|
202
|
+
isCustomElement: (tag) => NS_NATIVE_TAGS.has(tag),
|
|
203
|
+
},
|
|
204
|
+
});
|
|
205
|
+
let out = (compiledTemplate && (compiledTemplate.code || '')) || '';
|
|
206
|
+
try {
|
|
207
|
+
out = out.replace(/from\s+["'](?:nativescript-vue|vue)[^"']*["']/g, 'from "/ns/rt"');
|
|
208
|
+
}
|
|
209
|
+
catch { }
|
|
210
|
+
code = processTemplateVariantMinimal(out);
|
|
211
|
+
}
|
|
212
|
+
else {
|
|
213
|
+
code = 'export {}\n';
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
catch (templateError) {
|
|
217
|
+
if (options.verbose) {
|
|
218
|
+
try {
|
|
219
|
+
console.warn('[sfc][template][self-compile][fail]', fullSpec, templateError?.message);
|
|
220
|
+
}
|
|
221
|
+
catch { }
|
|
222
|
+
}
|
|
223
|
+
code = transformed.code || 'export {}\n';
|
|
224
|
+
code = processTemplateVariantMinimal(code);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
else {
|
|
228
|
+
code = transformed.code || 'export {}\n';
|
|
229
|
+
code = processTemplateVariantMinimal(code);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
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(pathNode) {
|
|
242
|
+
const spec = pathNode.node.source.value || '';
|
|
243
|
+
if (typeof spec === 'string' && /\.vue\?[^\n]*type=template/.test(spec)) {
|
|
244
|
+
const ids = [];
|
|
245
|
+
for (const currentSpecifier of pathNode.node.specifiers) {
|
|
246
|
+
if (t.isImportSpecifier(currentSpecifier)) {
|
|
247
|
+
const imported = t.isIdentifier(currentSpecifier.imported) ? currentSpecifier.imported.name : undefined;
|
|
248
|
+
const local = t.isIdentifier(currentSpecifier.local) ? currentSpecifier.local.name : undefined;
|
|
249
|
+
if ((imported === 'render' || imported === undefined) && local)
|
|
250
|
+
ids.push(local);
|
|
251
|
+
}
|
|
252
|
+
else if (t.isImportDefaultSpecifier(currentSpecifier) || t.isImportNamespaceSpecifier(currentSpecifier)) {
|
|
253
|
+
if (t.isIdentifier(currentSpecifier.local))
|
|
254
|
+
ids.push(currentSpecifier.local.name);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
ids.forEach((name) => templateBindings.add(name));
|
|
258
|
+
pathNode.remove();
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
const isNsVue = typeof spec === 'string' && (/nativescript-vue/.test(spec) || /vendor\.mjs$/.test(spec) || /\/node_modules\/\.vite\/deps\/nativescript-vue\.js/.test(spec));
|
|
262
|
+
if (isNsVue) {
|
|
263
|
+
const remain = [];
|
|
264
|
+
for (const currentSpecifier of pathNode.node.specifiers) {
|
|
265
|
+
if (t.isImportSpecifier(currentSpecifier)) {
|
|
266
|
+
const imported = t.isIdentifier(currentSpecifier.imported) ? currentSpecifier.imported.name : undefined;
|
|
267
|
+
const local = t.isIdentifier(currentSpecifier.local) ? currentSpecifier.local.name : undefined;
|
|
268
|
+
if (local && (imported === '$navigateTo' || imported === 'navigateTo')) {
|
|
269
|
+
navToLocals.push(local);
|
|
270
|
+
continue;
|
|
271
|
+
}
|
|
272
|
+
if (local && (imported === '$navigateBack' || imported === 'navigateBack')) {
|
|
273
|
+
navBackLocals.push(local);
|
|
274
|
+
continue;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
remain.push(currentSpecifier);
|
|
278
|
+
}
|
|
279
|
+
if (remain.length) {
|
|
280
|
+
pathNode.node.specifiers = remain;
|
|
281
|
+
}
|
|
282
|
+
else {
|
|
283
|
+
pathNode.remove();
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
},
|
|
287
|
+
});
|
|
288
|
+
if (templateBindings.size) {
|
|
289
|
+
babelTraverse(ast, {
|
|
290
|
+
Identifier(pathNode) {
|
|
291
|
+
if (templateBindings.has(pathNode.node.name)) {
|
|
292
|
+
pathNode.replaceWith(t.identifier('undefined'));
|
|
293
|
+
}
|
|
294
|
+
},
|
|
295
|
+
AssignmentExpression(pathNode) {
|
|
296
|
+
if (t.isMemberExpression(pathNode.node.left) && t.isIdentifier(pathNode.node.left.property, { name: 'render' })) {
|
|
297
|
+
const e = t.identifier('__e');
|
|
298
|
+
const guarded = t.tryStatement(t.blockStatement([
|
|
299
|
+
t.variableDeclaration('const', [t.variableDeclarator(e, pathNode.node.right)]),
|
|
300
|
+
t.ifStatement(t.logicalExpression('&&', t.binaryExpression('!==', t.unaryExpression('typeof', pathNode.node.left.object, true), t.stringLiteral('undefined')), t.binaryExpression('!==', t.unaryExpression('typeof', e, true), t.stringLiteral('undefined'))), t.blockStatement([t.expressionStatement(t.assignmentExpression('=', pathNode.node.left, e))])),
|
|
301
|
+
]), t.catchClause(t.identifier('_e'), t.blockStatement([])));
|
|
302
|
+
pathNode.replaceWithMultiple([guarded]);
|
|
303
|
+
}
|
|
304
|
+
},
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
let outCode = genCode(ast).code;
|
|
308
|
+
if (navToLocals.length || navBackLocals.length) {
|
|
309
|
+
const shimLines = [];
|
|
310
|
+
for (const currentName of navToLocals)
|
|
311
|
+
shimLines.push(`import __ns_rt_nav_to_mod from "/ns/rt";\nconst ${currentName} = (...args) => __ns_rt_nav_to_mod.$navigateTo(...args);`);
|
|
312
|
+
for (const currentName of navBackLocals)
|
|
313
|
+
shimLines.push(`import __ns_rt_nav_back_mod from "/ns/rt";\nconst ${currentName} = (...args) => __ns_rt_nav_back_mod.$navigateBack(...args);`);
|
|
314
|
+
outCode = shimLines.join('\n') + '\n' + outCode;
|
|
315
|
+
}
|
|
316
|
+
code = outCode;
|
|
317
|
+
}
|
|
318
|
+
catch { }
|
|
319
|
+
code = options.processCodeForDevice(code, false, true, /(?:^|\/)node_modules\//.test(fullSpec), fullSpec);
|
|
320
|
+
try {
|
|
321
|
+
const importerPath = fullSpec.replace(/[?#].*$/, '');
|
|
322
|
+
const version = verFromPath || '0';
|
|
323
|
+
const ast = babelParse(code, {
|
|
324
|
+
sourceType: 'module',
|
|
325
|
+
plugins: ['typescript'],
|
|
326
|
+
});
|
|
327
|
+
babelTraverse(ast, {
|
|
328
|
+
ImportDeclaration(pathNode) {
|
|
329
|
+
const src = pathNode.node.source.value || '';
|
|
330
|
+
if (typeof src !== 'string')
|
|
331
|
+
return;
|
|
332
|
+
if (/^https?:\/\//.test(src))
|
|
333
|
+
return;
|
|
334
|
+
if (/\.vue(?:$|\?)/.test(src)) {
|
|
335
|
+
let spec = src;
|
|
336
|
+
if (spec.startsWith('./') || spec.startsWith('../')) {
|
|
337
|
+
spec = path.posix.normalize(path.posix.join(path.posix.dirname(importerPath), spec));
|
|
338
|
+
if (!spec.startsWith('/'))
|
|
339
|
+
spec = '/' + spec;
|
|
340
|
+
}
|
|
341
|
+
else if (!spec.startsWith('/')) {
|
|
342
|
+
if (spec.startsWith('@@/'))
|
|
343
|
+
spec = '/' + spec.slice(2);
|
|
344
|
+
if (spec.startsWith('@/'))
|
|
345
|
+
spec = options.appVirtualWithSlash + spec.slice(2);
|
|
346
|
+
}
|
|
347
|
+
if (!/\bvue&type=/.test(src)) {
|
|
348
|
+
spec = spec.replace(/[?#].*$/, '');
|
|
349
|
+
const asmUrl = `/ns/asm/${version}?path=${encodeURIComponent(spec)}&mode=inline`;
|
|
350
|
+
pathNode.node.source = t.stringLiteral(asmUrl);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
},
|
|
354
|
+
});
|
|
355
|
+
code = genCode(ast).code;
|
|
356
|
+
}
|
|
357
|
+
catch { }
|
|
358
|
+
try {
|
|
359
|
+
const importerPath = fullSpec.replace(/[?#].*$/, '');
|
|
360
|
+
const tsResult = await babelCore.transformAsync(code, {
|
|
361
|
+
plugins: [[pluginTransformTypescript, { allowDeclareFields: true }]],
|
|
362
|
+
sourceType: 'module',
|
|
363
|
+
filename: importerPath.endsWith('.vue') ? importerPath.replace(/\.vue$/, '.ts') : importerPath + '.ts',
|
|
364
|
+
comments: true,
|
|
365
|
+
configFile: false,
|
|
366
|
+
babelrc: false,
|
|
367
|
+
});
|
|
368
|
+
if (tsResult?.code) {
|
|
369
|
+
code = tsResult.code;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
catch (variantTsError) {
|
|
373
|
+
if (options.verbose) {
|
|
374
|
+
try {
|
|
375
|
+
console.warn('[sfc][variant:script][babel-ts][fail]', fullSpec, variantTsError?.message);
|
|
376
|
+
}
|
|
377
|
+
catch { }
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
const importerPath = fullSpec.replace(/[?#].*$/, '');
|
|
381
|
+
if (variantType !== 'template') {
|
|
382
|
+
code = options.cleanCode(code);
|
|
383
|
+
}
|
|
384
|
+
code = options.rewriteImports(code, importerPath, options.sfcFileMap, options.depFileMap, projectRoot, !!options.verbose, undefined, options.getServerOrigin(server));
|
|
385
|
+
code = options.ensureVariableDynamicImportHelper(code);
|
|
386
|
+
try {
|
|
387
|
+
const versionNumber = Number(verFromPath || '0');
|
|
388
|
+
const currentVersion = Number.isFinite(versionNumber) && versionNumber > 0 ? versionNumber : options.getGraphVersion();
|
|
389
|
+
const origin = options.getServerOrigin(server);
|
|
390
|
+
code = options.ensureVersionedRtImports(code, origin, currentVersion);
|
|
391
|
+
code = options.getStrategy().ensureVersionedImports(code, origin, currentVersion);
|
|
392
|
+
code = options.ensureVersionedCoreImports(code, origin, currentVersion);
|
|
393
|
+
}
|
|
394
|
+
catch { }
|
|
395
|
+
try {
|
|
396
|
+
code = options.ensureDestructureCoreImports(code);
|
|
397
|
+
}
|
|
398
|
+
catch { }
|
|
399
|
+
try {
|
|
400
|
+
code = astNormalizeModuleImportsAndHelpers(code);
|
|
401
|
+
}
|
|
402
|
+
catch { }
|
|
403
|
+
try {
|
|
404
|
+
code = stripRtCoreSentinel(code);
|
|
405
|
+
}
|
|
406
|
+
catch { }
|
|
407
|
+
try {
|
|
408
|
+
const versionNumber = Number(verFromPath || '0');
|
|
409
|
+
const currentVersion = Number.isFinite(versionNumber) && versionNumber > 0 ? versionNumber : options.getGraphVersion();
|
|
410
|
+
const origin = options.getServerOrigin(server);
|
|
411
|
+
code = options.ensureVersionedRtImports(code, origin, currentVersion);
|
|
412
|
+
code = options.ensureVersionedCoreImports(code, origin, currentVersion);
|
|
413
|
+
}
|
|
414
|
+
catch { }
|
|
415
|
+
try {
|
|
416
|
+
code = stripDanglingViteCjsImports(code);
|
|
417
|
+
}
|
|
418
|
+
catch { }
|
|
419
|
+
const hasDefault = /\bexport\s+default\b/.test(code);
|
|
420
|
+
const kind = isVariant ? `variant:${variantType || 'unknown'}` : 'full';
|
|
421
|
+
const sig = `// [sfc] kind=${kind} path=${importerPath} len=${code.length} default=${hasDefault} wrapped=${false}\n`;
|
|
422
|
+
if (options.verbose) {
|
|
423
|
+
try {
|
|
424
|
+
console.log(`[sfc][serve] ${fullSpec} kind=${kind} default=${hasDefault} bytes=${code.length}`);
|
|
425
|
+
}
|
|
426
|
+
catch { }
|
|
427
|
+
}
|
|
428
|
+
if (!hasDefault) {
|
|
429
|
+
const match = code.match(/\b(?:const|let|var)\s+(__ns_sfc__|_sfc_main)\b/);
|
|
430
|
+
if (match && match[1]) {
|
|
431
|
+
code += `\nexport default ${match[1]};`;
|
|
432
|
+
}
|
|
433
|
+
else if (/\b_defineComponent\s*\(|\bdefineComponent\s*\(/.test(code)) {
|
|
434
|
+
code += '\nexport default (typeof __ns_sfc__ !== "undefined" ? __ns_sfc__ : (typeof _sfc_main !== "undefined" ? _sfc_main : undefined));';
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
res.statusCode = 200;
|
|
438
|
+
res.end(sig + code);
|
|
439
|
+
}
|
|
440
|
+
catch {
|
|
441
|
+
res.statusCode = 500;
|
|
442
|
+
res.end('export {}\n');
|
|
443
|
+
}
|
|
444
|
+
});
|
|
445
|
+
server.middlewares.use(async (req, res, next) => {
|
|
446
|
+
try {
|
|
447
|
+
const urlObj = new URL(req.url || '', 'http://localhost');
|
|
448
|
+
if (!urlObj.pathname.startsWith('/ns/sfc-meta'))
|
|
449
|
+
return next();
|
|
450
|
+
setJsonResponseHeaders(res);
|
|
451
|
+
let spec = urlObj.searchParams.get('path') || '';
|
|
452
|
+
if (!spec) {
|
|
453
|
+
res.statusCode = 400;
|
|
454
|
+
res.end(JSON.stringify({ error: 'missing path' }));
|
|
455
|
+
return;
|
|
456
|
+
}
|
|
457
|
+
spec = normalizeRequestedSpec(spec, options.appVirtualWithSlash);
|
|
458
|
+
const base = spec.replace(/[?#].*$/, '');
|
|
459
|
+
const [scriptResult, templateResult] = await Promise.all([server.transformRequest(base + '?vue&type=script'), server.transformRequest(base + '?vue&type=template')]);
|
|
460
|
+
const scriptCode = scriptResult?.code || '';
|
|
461
|
+
const templateCode = templateResult?.code || '';
|
|
462
|
+
const scriptMeta = options.extractExportMetadata(scriptCode);
|
|
463
|
+
const hasRender = templateHasRender(templateCode);
|
|
464
|
+
if (hasRender && options.verbose) {
|
|
465
|
+
try {
|
|
466
|
+
console.log('[sfc-meta] detected render for', base);
|
|
467
|
+
}
|
|
468
|
+
catch { }
|
|
469
|
+
}
|
|
470
|
+
else if (!hasRender && options.verbose) {
|
|
471
|
+
try {
|
|
472
|
+
console.warn('[sfc-meta] render NOT detected for', base);
|
|
473
|
+
}
|
|
474
|
+
catch { }
|
|
475
|
+
}
|
|
476
|
+
const hash = createHash('md5').update(base).digest('hex').slice(0, 8);
|
|
477
|
+
const payload = {
|
|
478
|
+
path: base,
|
|
479
|
+
hasScript: !!scriptCode,
|
|
480
|
+
hasTemplate: !!templateCode,
|
|
481
|
+
hasStyle: false,
|
|
482
|
+
scriptExports: scriptMeta.named,
|
|
483
|
+
scriptHasDefault: scriptMeta.hasDefault,
|
|
484
|
+
templateHasRender: hasRender,
|
|
485
|
+
hmrId: hash,
|
|
486
|
+
};
|
|
487
|
+
res.statusCode = 200;
|
|
488
|
+
res.end(JSON.stringify(payload));
|
|
489
|
+
}
|
|
490
|
+
catch (error) {
|
|
491
|
+
res.statusCode = 500;
|
|
492
|
+
res.end(JSON.stringify({ error: error?.message || String(error) }));
|
|
493
|
+
}
|
|
494
|
+
});
|
|
495
|
+
server.middlewares.use(async (req, res, next) => {
|
|
496
|
+
try {
|
|
497
|
+
const urlObj = new URL(req.url || '', 'http://localhost');
|
|
498
|
+
if (!urlObj.pathname.startsWith('/ns/asm'))
|
|
499
|
+
return next();
|
|
500
|
+
setJavascriptResponseHeaders(res);
|
|
501
|
+
const asmBase = '/ns/asm';
|
|
502
|
+
const { verFromPath } = parseVersionedEndpointPath(asmBase, urlObj.pathname);
|
|
503
|
+
let spec = urlObj.searchParams.get('path') || '';
|
|
504
|
+
const diag = urlObj.searchParams.get('diag') === '1';
|
|
505
|
+
if (!spec) {
|
|
506
|
+
res.statusCode = 400;
|
|
507
|
+
res.end('export {}\n');
|
|
508
|
+
return;
|
|
509
|
+
}
|
|
510
|
+
spec = normalizeRequestedSpec(spec, options.appVirtualWithSlash);
|
|
511
|
+
const base = spec.replace(/[?#].*$/, '');
|
|
512
|
+
if (diag) {
|
|
513
|
+
const code = `// [sfc-asm] ${base} (diag)\n` + `// vue shim for diag-only instantiation\n` + `var _createElementVNode = globalThis.createElementVNode || globalThis._createElementVNode;\n` + `const __ns_sfc__ = { name: ${JSON.stringify(base.split('/').pop() || 'DiagComp')}, render(){ return _createElementVNode ? _createElementVNode('StackLayout') : (globalThis.createElementVNode ? globalThis.createElementVNode('StackLayout') : {}); } };\nexport default __ns_sfc__;\n`;
|
|
514
|
+
res.statusCode = 200;
|
|
515
|
+
res.end(code);
|
|
516
|
+
return;
|
|
517
|
+
}
|
|
518
|
+
const projectRoot = server.config?.root || process.cwd();
|
|
519
|
+
const safeTransform = async (candidate) => {
|
|
520
|
+
try {
|
|
521
|
+
return await server.transformRequest(candidate);
|
|
522
|
+
}
|
|
523
|
+
catch {
|
|
524
|
+
return null;
|
|
525
|
+
}
|
|
526
|
+
};
|
|
527
|
+
const scriptResult = await safeTransform(base + '?vue&type=script');
|
|
528
|
+
const templateResult = await safeTransform(base + '?vue&type=template');
|
|
529
|
+
await safeTransform(base + '?vue');
|
|
530
|
+
const origin = options.getServerOrigin(server);
|
|
531
|
+
const version = String(verFromPath || options.getGraphVersion() || Date.now());
|
|
532
|
+
const scriptUrl = `${origin}/ns/sfc/${version}${base}?vue&type=script`;
|
|
533
|
+
const templateCode = templateResult?.code || '';
|
|
534
|
+
try {
|
|
535
|
+
const root = server.config?.root || process.cwd();
|
|
536
|
+
const absolutePath = path.join(root, base.replace(/^\//, ''));
|
|
537
|
+
let sfcSource = '';
|
|
538
|
+
try {
|
|
539
|
+
sfcSource = readFileSync(absolutePath, 'utf-8');
|
|
540
|
+
}
|
|
541
|
+
catch { }
|
|
542
|
+
if (sfcSource) {
|
|
543
|
+
const { descriptor } = parse(sfcSource, { filename: absolutePath });
|
|
544
|
+
const id = createHash('md5').update(absolutePath).digest('hex').slice(0, 8);
|
|
545
|
+
let compiledScript = '';
|
|
546
|
+
let bindingMetadata = undefined;
|
|
547
|
+
let usedInlineScript = false;
|
|
548
|
+
try {
|
|
549
|
+
const isNSNative = (tag) => NS_NATIVE_TAGS.has(tag);
|
|
550
|
+
const inlineScript = compileScript(descriptor, {
|
|
551
|
+
id,
|
|
552
|
+
inlineTemplate: true,
|
|
553
|
+
reactivityTransform: false,
|
|
554
|
+
templateOptions: {
|
|
555
|
+
compilerOptions: { isCustomElement: isNSNative },
|
|
556
|
+
},
|
|
557
|
+
});
|
|
558
|
+
if (/export\s+default/.test(inlineScript?.content || '')) {
|
|
559
|
+
compiledScript = inlineScript.content;
|
|
560
|
+
bindingMetadata = inlineScript?.bindings;
|
|
561
|
+
usedInlineScript = true;
|
|
562
|
+
}
|
|
563
|
+
else {
|
|
564
|
+
const fallbackScript = compileScript(descriptor, {
|
|
565
|
+
id,
|
|
566
|
+
inlineTemplate: false,
|
|
567
|
+
reactivityTransform: false,
|
|
568
|
+
});
|
|
569
|
+
compiledScript = fallbackScript?.content || '';
|
|
570
|
+
bindingMetadata = fallbackScript?.bindings;
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
catch (scriptError) {
|
|
574
|
+
if (options.verbose) {
|
|
575
|
+
try {
|
|
576
|
+
console.warn('[sfc-asm][compileScript] failed', base, scriptError?.message);
|
|
577
|
+
}
|
|
578
|
+
catch { }
|
|
579
|
+
}
|
|
580
|
+
try {
|
|
581
|
+
const fallbackScript = compileScript(descriptor, {
|
|
582
|
+
id,
|
|
583
|
+
inlineTemplate: false,
|
|
584
|
+
reactivityTransform: false,
|
|
585
|
+
});
|
|
586
|
+
compiledScript = fallbackScript?.content || '';
|
|
587
|
+
bindingMetadata = fallbackScript?.bindings;
|
|
588
|
+
}
|
|
589
|
+
catch (fallbackError) {
|
|
590
|
+
if (options.verbose) {
|
|
591
|
+
try {
|
|
592
|
+
console.warn('[sfc-asm][compileScript][no-inline-fallback] failed', base, fallbackError?.message);
|
|
593
|
+
}
|
|
594
|
+
catch { }
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
if (!compiledScript && scriptResult?.code) {
|
|
599
|
+
compiledScript = scriptResult.code;
|
|
600
|
+
}
|
|
601
|
+
if (usedInlineScript) {
|
|
602
|
+
try {
|
|
603
|
+
const noInlineScript = compileScript(descriptor, {
|
|
604
|
+
id,
|
|
605
|
+
inlineTemplate: false,
|
|
606
|
+
reactivityTransform: false,
|
|
607
|
+
});
|
|
608
|
+
compiledScript = noInlineScript?.content || compiledScript;
|
|
609
|
+
bindingMetadata = noInlineScript?.bindings || bindingMetadata;
|
|
610
|
+
}
|
|
611
|
+
catch (noInlineError) {
|
|
612
|
+
if (options.verbose) {
|
|
613
|
+
try {
|
|
614
|
+
console.warn('[sfc-asm][compileScript][no-inline-fallback] failed', base, noInlineError?.message);
|
|
615
|
+
}
|
|
616
|
+
catch { }
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
let compiledTemplateCode = '';
|
|
621
|
+
try {
|
|
622
|
+
const templateSource = descriptor.template?.content || '';
|
|
623
|
+
if (templateSource) {
|
|
624
|
+
const compiledTemplate = compileTemplate({
|
|
625
|
+
source: templateSource,
|
|
626
|
+
id,
|
|
627
|
+
filename: absolutePath,
|
|
628
|
+
isProd: false,
|
|
629
|
+
ssr: false,
|
|
630
|
+
compilerOptions: {
|
|
631
|
+
bindingMetadata,
|
|
632
|
+
isCustomElement: (tag) => NS_NATIVE_TAGS.has(tag),
|
|
633
|
+
},
|
|
634
|
+
});
|
|
635
|
+
compiledTemplateCode = (compiledTemplate && (compiledTemplate.code || '')) || '';
|
|
636
|
+
if (compiledTemplate?.errors?.length && options.verbose) {
|
|
637
|
+
try {
|
|
638
|
+
console.warn('[sfc-asm][compileTemplate][errors]', base, compiledTemplate.errors);
|
|
639
|
+
}
|
|
640
|
+
catch { }
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
catch (templateError) {
|
|
645
|
+
if (options.verbose) {
|
|
646
|
+
try {
|
|
647
|
+
console.warn('[sfc-asm][compileTemplate] failed', base, templateError?.message);
|
|
648
|
+
}
|
|
649
|
+
catch { }
|
|
650
|
+
}
|
|
651
|
+
if (templateResult?.code)
|
|
652
|
+
compiledTemplateCode = templateResult.code;
|
|
653
|
+
}
|
|
654
|
+
if (!compiledTemplateCode) {
|
|
655
|
+
compiledTemplateCode = "export function render(){ const _ = (globalThis.createElementVNode||globalThis._createElementVNode); return _? _('StackLayout') : {}; }\n";
|
|
656
|
+
}
|
|
657
|
+
let scriptBody = compiledScript || '';
|
|
658
|
+
if (scriptBody) {
|
|
659
|
+
scriptBody = scriptBody.replace(/(^|\n)\s*import\s+([^;\n]+)\s+from\s+["'](?:vue|nativescript-vue|~\/vendor\.mjs)(?:\/[^\"]*)?["'];?/g, (_match, prefix, clause) => `${prefix}import ${clause} from "/ns/rt";`);
|
|
660
|
+
try {
|
|
661
|
+
const importerDir = path.posix.dirname(base);
|
|
662
|
+
scriptBody = scriptBody.replace(/(^|\n)\s*import\s+([^;\n]+)\s+from\s+["']([^"'\n]+\.vue)(?:\?[^"'\n]*)?["'];?/g, (_match, prefix, clause, importSpec) => {
|
|
663
|
+
let absoluteImport = importSpec;
|
|
664
|
+
if (importSpec.startsWith('./') || importSpec.startsWith('../')) {
|
|
665
|
+
absoluteImport = path.posix.normalize(path.posix.join(importerDir, importSpec));
|
|
666
|
+
if (!absoluteImport.startsWith('/'))
|
|
667
|
+
absoluteImport = '/' + absoluteImport;
|
|
668
|
+
}
|
|
669
|
+
else if (!importSpec.startsWith('/')) {
|
|
670
|
+
if (absoluteImport.startsWith('@/'))
|
|
671
|
+
absoluteImport = options.appVirtualWithSlash + absoluteImport.slice(2);
|
|
672
|
+
}
|
|
673
|
+
const asmUrl = `/ns/asm/${version}?path=${encodeURIComponent(absoluteImport)}&mode=inline`;
|
|
674
|
+
return `${prefix}import ${clause} from ${JSON.stringify(asmUrl)};`;
|
|
675
|
+
});
|
|
676
|
+
}
|
|
677
|
+
catch { }
|
|
678
|
+
}
|
|
679
|
+
let helperBindings = '';
|
|
680
|
+
let renderDecl = '';
|
|
681
|
+
let inlineBlock;
|
|
682
|
+
let renderOk = false;
|
|
683
|
+
if (compiledTemplateCode) {
|
|
684
|
+
try {
|
|
685
|
+
inlineBlock = buildInlineTemplateBlock(compiledTemplateCode) || undefined;
|
|
686
|
+
if (!inlineBlock) {
|
|
687
|
+
const extracted = extractTemplateRender(compiledTemplateCode);
|
|
688
|
+
helperBindings = extracted.helperBindings;
|
|
689
|
+
renderDecl = extracted.renderDecl;
|
|
690
|
+
inlineBlock = extracted.inlineBlock;
|
|
691
|
+
renderOk = extracted.ok;
|
|
692
|
+
}
|
|
693
|
+
else {
|
|
694
|
+
renderOk = true;
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
catch (extractError) {
|
|
698
|
+
if (options.verbose) {
|
|
699
|
+
try {
|
|
700
|
+
console.warn('[sfc-asm][extractTemplateRender] failed', base, extractError?.message);
|
|
701
|
+
}
|
|
702
|
+
catch { }
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
if (!renderOk && !inlineBlock) {
|
|
707
|
+
try {
|
|
708
|
+
const templateUrl = `${origin}/ns/sfc/${version}${base}?vue&type=template`;
|
|
709
|
+
const importLine = `import * as __template from ${JSON.stringify(templateUrl)};`;
|
|
710
|
+
helperBindings += `\n${importLine}`;
|
|
711
|
+
renderDecl += `\nfunction __ns_getRender(){\n try {\n if (__template && __template.render) return __template.render;\n } catch (_e) {}\n try {\n const _ = globalThis.createElementVNode || globalThis._createElementVNode;\n return _ ? function(){ return _('StackLayout'); } : function(){ return {}; };\n } catch (_e) { return function(){ return {}; }; }\n}\n`;
|
|
712
|
+
renderOk = true;
|
|
713
|
+
}
|
|
714
|
+
catch { }
|
|
715
|
+
}
|
|
716
|
+
let scriptTransformed = scriptBody;
|
|
717
|
+
if (scriptTransformed) {
|
|
718
|
+
scriptTransformed = scriptTransformed.replace(/(^|\n)\s*export\s+default\s+/g, '$1const __ns_sfc__ = ').replace(/(^|\n)\s*export\s*\{[^}]*\}\s*;?\s*/g, '\n/* removed named exports for inline asm */\n');
|
|
719
|
+
scriptTransformed = scriptTransformed.replace(/(^|[\n;])\s*(?:const|let|var)\s+__ns_sfc__\s*=\s*/g, '$1__ns_sfc__ = ');
|
|
720
|
+
if (!/(^|[\n;])\s*(?:const|let|var)\s+__ns_sfc__\b/.test(scriptTransformed)) {
|
|
721
|
+
scriptTransformed = 'let __ns_sfc__;\n' + scriptTransformed;
|
|
722
|
+
}
|
|
723
|
+
scriptTransformed = scriptTransformed.replace(/^\s*\}+(?=\s*[^}])/, (value) => `/* [asm-fix] removed ${value.length} stray leading braces */\n`);
|
|
724
|
+
}
|
|
725
|
+
else {
|
|
726
|
+
try {
|
|
727
|
+
const componentName = (base.split('/').pop() || 'Component').replace(/\.vue$/i, '') || 'Component';
|
|
728
|
+
scriptTransformed = `import { defineComponent as _defineComponent } from "/ns/rt";\nlet __ns_sfc__;\n__ns_sfc__ = /*@__PURE__*/_defineComponent({ __name: ${JSON.stringify(componentName)} });`;
|
|
729
|
+
}
|
|
730
|
+
catch {
|
|
731
|
+
scriptTransformed = 'import { defineComponent as _defineComponent } from "/ns/rt";\nlet __ns_sfc__;\n__ns_sfc__ = /*@__PURE__*/_defineComponent({});';
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
const parts = [];
|
|
735
|
+
parts.push(`// [sfc-asm] ${base} (inline-compiled)`);
|
|
736
|
+
if (helperBindings)
|
|
737
|
+
parts.push(helperBindings);
|
|
738
|
+
parts.push(scriptTransformed);
|
|
739
|
+
parts.push(renderDecl);
|
|
740
|
+
parts.push(`try { if (!__ns_sfc__.render) Object.defineProperty(__ns_sfc__, 'render', { configurable: true, enumerable: true, get(){ const r = (typeof __ns_getRender==='function' ? __ns_getRender() : undefined); Object.defineProperty(__ns_sfc__, 'render', { value: r, writable: true, configurable: true, enumerable: true }); return r; }, set(v){ Object.defineProperty(__ns_sfc__, 'render', { value: v, writable: true, configurable: true, enumerable: true }); } }); } catch(_e){}`);
|
|
741
|
+
parts.push('export function render(){ const f = (typeof __ns_getRender===\'function\' ? __ns_getRender() : (__ns_sfc__ && __ns_sfc__.render)); return typeof f===\'function\' ? f.apply(this, arguments) : undefined; }');
|
|
742
|
+
parts.push('export default __ns_sfc__');
|
|
743
|
+
let inlineCode = parts.filter(Boolean).join('\n');
|
|
744
|
+
inlineCode = options.processCodeForDevice(inlineCode, false, true);
|
|
745
|
+
try {
|
|
746
|
+
inlineCode = options.ensureVersionedCoreImports(inlineCode, options.getServerOrigin(server), Number(version));
|
|
747
|
+
}
|
|
748
|
+
catch { }
|
|
749
|
+
try {
|
|
750
|
+
inlineCode = options.ensureDestructureCoreImports(inlineCode);
|
|
751
|
+
}
|
|
752
|
+
catch { }
|
|
753
|
+
try {
|
|
754
|
+
const tsResult = await babelCore.transformAsync(scriptTransformed, {
|
|
755
|
+
plugins: [[pluginTransformTypescript, { allowDeclareFields: true }]],
|
|
756
|
+
ast: false,
|
|
757
|
+
sourceType: 'module',
|
|
758
|
+
configFile: false,
|
|
759
|
+
babelrc: false,
|
|
760
|
+
});
|
|
761
|
+
if (tsResult?.code)
|
|
762
|
+
scriptTransformed = tsResult.code;
|
|
763
|
+
}
|
|
764
|
+
catch (tsError) {
|
|
765
|
+
if (options.verbose) {
|
|
766
|
+
try {
|
|
767
|
+
console.warn('[sfc-asm][babel-ts][fail]', base, tsError?.message);
|
|
768
|
+
}
|
|
769
|
+
catch { }
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
let importLines = [];
|
|
773
|
+
try {
|
|
774
|
+
const astResult = astExtractImportsAndStripTypes(scriptTransformed);
|
|
775
|
+
importLines = astResult.imports;
|
|
776
|
+
scriptTransformed = astResult.body;
|
|
777
|
+
if (astResult.diagnostics.length && options.verbose) {
|
|
778
|
+
try {
|
|
779
|
+
console.warn('[sfc-asm][ast]', base, astResult.diagnostics.join('; '));
|
|
780
|
+
}
|
|
781
|
+
catch { }
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
catch (astError) {
|
|
785
|
+
if (options.verbose) {
|
|
786
|
+
try {
|
|
787
|
+
console.warn('[sfc-asm][ast][fail]', base, astError?.message);
|
|
788
|
+
}
|
|
789
|
+
catch { }
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
if (renderDecl && /(^|\n)\s*(?:export\s+)?function\s+__ns_render\s*\(/.test(renderDecl) && !/\}\s*$/.test(renderDecl)) {
|
|
793
|
+
renderDecl = renderDecl.trimEnd() + '\n}';
|
|
794
|
+
}
|
|
795
|
+
const outParts = [];
|
|
796
|
+
outParts.push(`// [sfc-asm] ${base} (inline-compiled)`);
|
|
797
|
+
outParts.push('// [sfc-asm][canonical]');
|
|
798
|
+
if (importLines.length)
|
|
799
|
+
outParts.push(Array.from(new Set(importLines)).join('\n'));
|
|
800
|
+
outParts.push(scriptTransformed);
|
|
801
|
+
if (inlineBlock) {
|
|
802
|
+
outParts.push(inlineBlock);
|
|
803
|
+
}
|
|
804
|
+
else {
|
|
805
|
+
if (helperBindings)
|
|
806
|
+
outParts.push(helperBindings);
|
|
807
|
+
if (renderDecl && renderDecl.trim())
|
|
808
|
+
outParts.push(renderDecl);
|
|
809
|
+
}
|
|
810
|
+
outParts.push(`try { if (!__ns_sfc__.render) Object.defineProperty(__ns_sfc__, 'render', { configurable: true, enumerable: true, get(){ const r = (typeof __ns_getRender==='function' ? __ns_getRender() : (typeof __ns_render==='function' ? __ns_render : undefined)); Object.defineProperty(__ns_sfc__, 'render', { value: r, writable: true, configurable: true, enumerable: true }); return r; }, set(v){ Object.defineProperty(__ns_sfc__, 'render', { value: v, writable: true, configurable: true, enumerable: true }); } }); } catch(_e){}`);
|
|
811
|
+
outParts.push('export function render(){ const f = (typeof __ns_getRender==="function" ? __ns_getRender() : (typeof __ns_render==="function" ? __ns_render : (__ns_sfc__ && __ns_sfc__.render))); return typeof f === "function" ? f.apply(this, arguments) : undefined; }');
|
|
812
|
+
outParts.push('export default __ns_sfc__');
|
|
813
|
+
let inlineCode2 = outParts.filter(Boolean).join('\n');
|
|
814
|
+
inlineCode2 = options.processCodeForDevice(inlineCode2, false, true);
|
|
815
|
+
try {
|
|
816
|
+
inlineCode2 = options.ensureVersionedCoreImports(inlineCode2, options.getServerOrigin(server), Number(version));
|
|
817
|
+
}
|
|
818
|
+
catch { }
|
|
819
|
+
try {
|
|
820
|
+
inlineCode2 = options.ensureDestructureCoreImports(inlineCode2);
|
|
821
|
+
}
|
|
822
|
+
catch { }
|
|
823
|
+
try {
|
|
824
|
+
const lateImportPattern = /^(?!\/\/).*^\s*import\s+[^;]+;?$/gm;
|
|
825
|
+
const allImports = [];
|
|
826
|
+
inlineCode2 = inlineCode2.replace(lateImportPattern, (value) => {
|
|
827
|
+
allImports.push(value);
|
|
828
|
+
return '';
|
|
829
|
+
});
|
|
830
|
+
if (allImports.length) {
|
|
831
|
+
inlineCode2 = inlineCode2.replace(/(\/\/ \[sfc-asm\]\[canonical\]\n)/, `$1${Array.from(new Set(allImports)).join('\n')}\n/* [asm-fix] re-hoisted ${allImports.length} imports */\n`);
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
catch { }
|
|
835
|
+
try {
|
|
836
|
+
inlineCode2 = astNormalizeModuleImportsAndHelpers(inlineCode2);
|
|
837
|
+
}
|
|
838
|
+
catch { }
|
|
839
|
+
try {
|
|
840
|
+
inlineCode2 = astVerifyAndAnnotateDuplicates(inlineCode2);
|
|
841
|
+
if (/^\s*\/\/ \[ast-verify\]\[duplicate-bindings\]/m.test(inlineCode2)) {
|
|
842
|
+
const diagnosticLine = (inlineCode2.match(/^\s*\/\/ \[ast-verify\]\[duplicate-bindings\][^\n]*/m) || [])[0] || '// [ast-verify][duplicate-bindings]';
|
|
843
|
+
const brief = diagnosticLine.replace(/^[^:]*:?\s?/, '');
|
|
844
|
+
const escaped = brief.replace(/["\\]/g, '\\$&');
|
|
845
|
+
const thrower = `throw new Error("[nsv-hmr] Duplicate top-level bindings detected post-hoist: ${escaped}");`;
|
|
846
|
+
inlineCode2 = `${thrower}\n` + inlineCode2;
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
catch { }
|
|
850
|
+
try {
|
|
851
|
+
inlineCode2 = inlineCode2.replace(/\bdefault\b\s*(?=\}|,|\n)/g, 'default: undefined');
|
|
852
|
+
inlineCode2 = inlineCode2.replace(/<unknown>/g, '');
|
|
853
|
+
inlineCode2 = inlineCode2.replace(/}\s*=>\s*\{/g, '');
|
|
854
|
+
}
|
|
855
|
+
catch { }
|
|
856
|
+
try {
|
|
857
|
+
inlineCode2 = options.rewriteImports(inlineCode2, base, options.sfcFileMap, options.depFileMap, projectRoot, !!options.verbose, undefined, options.getServerOrigin(server));
|
|
858
|
+
}
|
|
859
|
+
catch { }
|
|
860
|
+
try {
|
|
861
|
+
const finalTs = await babelCore.transformAsync(inlineCode2, {
|
|
862
|
+
plugins: [[pluginTransformTypescript, { allowDeclareFields: true }]],
|
|
863
|
+
ast: false,
|
|
864
|
+
sourceType: 'module',
|
|
865
|
+
configFile: false,
|
|
866
|
+
babelrc: false,
|
|
867
|
+
});
|
|
868
|
+
if (finalTs?.code)
|
|
869
|
+
inlineCode2 = finalTs.code;
|
|
870
|
+
}
|
|
871
|
+
catch { }
|
|
872
|
+
try {
|
|
873
|
+
const missingElse = /"onUpdate:modelValue"\s*:\s*_cache\[(\d+)\]\s*\|\|\s*\(_cache\[\1\]\s*=\s*\$event\s*=>\s*_isRef\(\s*([A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)*)\s*\)\s*\?\s*\2\.value\s*=\s*\$event\s*\)/g;
|
|
874
|
+
inlineCode2 = inlineCode2.replace(missingElse, (_match, idx, expr) => `"onUpdate:modelValue": _cache[${idx}] || (_cache[${idx}] = $event => (_isRef(${expr}) ? (${expr}.value = $event) : (${expr} = $event)))`);
|
|
875
|
+
const malformed = /"onUpdate:modelValue"\s*:\s*_cache\[(\d+)\]\s*\|\|\s*\(_cache\[\1\]\s*=\s*[^=]*\(\s*([A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)*)\s*\)[^=]*=\s*\$event\s*\)\s*\)/g;
|
|
876
|
+
inlineCode2 = inlineCode2.replace(malformed, (_match, idx, expr) => `"onUpdate:modelValue": _cache[${idx}] || (_cache[${idx}] = $event => (_isRef(${expr}) ? (${expr}.value = $event) : (${expr} = $event)))`);
|
|
877
|
+
}
|
|
878
|
+
catch { }
|
|
879
|
+
try {
|
|
880
|
+
const firstImportIndex = inlineCode2.search(/^[\t ]*import\b/m);
|
|
881
|
+
if (firstImportIndex > 0) {
|
|
882
|
+
const prefix = inlineCode2.slice(0, firstImportIndex);
|
|
883
|
+
let open = 0;
|
|
884
|
+
let close = 0;
|
|
885
|
+
let inSingle = false;
|
|
886
|
+
let inDouble = false;
|
|
887
|
+
let inTemplate = false;
|
|
888
|
+
let inLineComment = false;
|
|
889
|
+
let inBlockComment = false;
|
|
890
|
+
for (let index = 0; index < prefix.length; index++) {
|
|
891
|
+
const ch = prefix[index];
|
|
892
|
+
const nextChar = prefix[index + 1];
|
|
893
|
+
if (inLineComment) {
|
|
894
|
+
if (ch === '\n')
|
|
895
|
+
inLineComment = false;
|
|
896
|
+
continue;
|
|
897
|
+
}
|
|
898
|
+
if (inBlockComment) {
|
|
899
|
+
if (ch === '*' && nextChar === '/') {
|
|
900
|
+
inBlockComment = false;
|
|
901
|
+
index++;
|
|
902
|
+
}
|
|
903
|
+
continue;
|
|
904
|
+
}
|
|
905
|
+
if (inSingle) {
|
|
906
|
+
if (ch === '\\') {
|
|
907
|
+
index++;
|
|
908
|
+
continue;
|
|
909
|
+
}
|
|
910
|
+
if (ch === "'")
|
|
911
|
+
inSingle = false;
|
|
912
|
+
continue;
|
|
913
|
+
}
|
|
914
|
+
if (inDouble) {
|
|
915
|
+
if (ch === '\\') {
|
|
916
|
+
index++;
|
|
917
|
+
continue;
|
|
918
|
+
}
|
|
919
|
+
if (ch === '"')
|
|
920
|
+
inDouble = false;
|
|
921
|
+
continue;
|
|
922
|
+
}
|
|
923
|
+
if (inTemplate) {
|
|
924
|
+
if (ch === '\\') {
|
|
925
|
+
index++;
|
|
926
|
+
continue;
|
|
927
|
+
}
|
|
928
|
+
if (ch === '`')
|
|
929
|
+
inTemplate = false;
|
|
930
|
+
continue;
|
|
931
|
+
}
|
|
932
|
+
if (ch === '/' && nextChar === '/') {
|
|
933
|
+
inLineComment = true;
|
|
934
|
+
index++;
|
|
935
|
+
continue;
|
|
936
|
+
}
|
|
937
|
+
if (ch === '/' && nextChar === '*') {
|
|
938
|
+
inBlockComment = true;
|
|
939
|
+
index++;
|
|
940
|
+
continue;
|
|
941
|
+
}
|
|
942
|
+
if (ch === "'") {
|
|
943
|
+
inSingle = true;
|
|
944
|
+
continue;
|
|
945
|
+
}
|
|
946
|
+
if (ch === '"') {
|
|
947
|
+
inDouble = true;
|
|
948
|
+
continue;
|
|
949
|
+
}
|
|
950
|
+
if (ch === '`') {
|
|
951
|
+
inTemplate = true;
|
|
952
|
+
continue;
|
|
953
|
+
}
|
|
954
|
+
if (ch === '{')
|
|
955
|
+
open++;
|
|
956
|
+
else if (ch === '}')
|
|
957
|
+
close++;
|
|
958
|
+
}
|
|
959
|
+
const missing = open - close;
|
|
960
|
+
if (missing > 0) {
|
|
961
|
+
inlineCode2 = inlineCode2.slice(0, firstImportIndex) + '}'.repeat(missing) + '\n' + inlineCode2.slice(firstImportIndex);
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
catch { }
|
|
966
|
+
try {
|
|
967
|
+
const finalTs = await babelCore.transformAsync(inlineCode2, {
|
|
968
|
+
plugins: [[pluginTransformTypescript, { allowDeclareFields: true }]],
|
|
969
|
+
ast: false,
|
|
970
|
+
sourceType: 'module',
|
|
971
|
+
configFile: false,
|
|
972
|
+
babelrc: false,
|
|
973
|
+
});
|
|
974
|
+
if (finalTs?.code)
|
|
975
|
+
inlineCode2 = finalTs.code;
|
|
976
|
+
}
|
|
977
|
+
catch { }
|
|
978
|
+
inlineCode2 = options.ensureVariableDynamicImportHelper(inlineCode2);
|
|
979
|
+
inlineCode2 = options.ensureGuardPlainDynamicImports(inlineCode2, origin);
|
|
980
|
+
inlineCode2 = options.requireGuardSnippet + inlineCode2;
|
|
981
|
+
try {
|
|
982
|
+
const lacksRender = !/__ns_render\b/.test(inlineCode2) && !/__ns_sfc__\.render\s*=/.test(inlineCode2);
|
|
983
|
+
if (lacksRender) {
|
|
984
|
+
const err = `throw new Error("[sfc-asm] ${base}: no render generated by assembler");\nexport default {};`;
|
|
985
|
+
res.statusCode = 200;
|
|
986
|
+
res.end(err);
|
|
987
|
+
return;
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
catch { }
|
|
991
|
+
try {
|
|
992
|
+
inlineCode2 = inlineCode2.replace(/(\/\/ \[sfc-asm\]\[canonical\])(?!\n)/, '$1\n');
|
|
993
|
+
}
|
|
994
|
+
catch { }
|
|
995
|
+
try {
|
|
996
|
+
const origin = options.getServerOrigin(server);
|
|
997
|
+
inlineCode2 = options.ensureVersionedRtImports(inlineCode2, origin, Number(version));
|
|
998
|
+
inlineCode2 = options.getStrategy().ensureVersionedImports(inlineCode2, origin, Number(version));
|
|
999
|
+
inlineCode2 = options.ensureVersionedCoreImports(inlineCode2, origin, Number(version));
|
|
1000
|
+
}
|
|
1001
|
+
catch { }
|
|
1002
|
+
try {
|
|
1003
|
+
inlineCode2 = astNormalizeModuleImportsAndHelpers(inlineCode2);
|
|
1004
|
+
}
|
|
1005
|
+
catch { }
|
|
1006
|
+
try {
|
|
1007
|
+
const hasDecl = /(^|[\n;])\s*(?:const|let|var)\s+__ns_sfc__\b/.test(inlineCode2);
|
|
1008
|
+
if (!hasDecl) {
|
|
1009
|
+
inlineCode2 = inlineCode2.replace(/(\/\/ \[sfc-asm\]\[canonical\]\n)/, '$1let __ns_sfc__ = {};\n');
|
|
1010
|
+
}
|
|
1011
|
+
inlineCode2 = inlineCode2.replace(/(^|[\n;])\s*let\s+__ns_sfc__\s*;?/g, '$1let __ns_sfc__ = {};');
|
|
1012
|
+
inlineCode2 = inlineCode2.replace(/(^|[\n;])\s*var\s+__ns_sfc__\s*;?/g, '$1var __ns_sfc__ = {};');
|
|
1013
|
+
}
|
|
1014
|
+
catch { }
|
|
1015
|
+
if (!/export\s+default\s+__ns_sfc__/.test(inlineCode2) && /__ns_sfc__/.test(inlineCode2))
|
|
1016
|
+
inlineCode2 += '\nexport default __ns_sfc__';
|
|
1017
|
+
res.statusCode = 200;
|
|
1018
|
+
res.end(inlineCode2);
|
|
1019
|
+
return;
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
catch { }
|
|
1023
|
+
let inlineOk = false;
|
|
1024
|
+
let helperBindings = '';
|
|
1025
|
+
let renderDecl = '';
|
|
1026
|
+
let inlineBlock;
|
|
1027
|
+
try {
|
|
1028
|
+
const root = server.config?.root || process.cwd();
|
|
1029
|
+
const absolutePath = path.join(root, base.replace(/^\//, ''));
|
|
1030
|
+
let sfcSource = '';
|
|
1031
|
+
try {
|
|
1032
|
+
sfcSource = readFileSync(absolutePath, 'utf-8');
|
|
1033
|
+
}
|
|
1034
|
+
catch { }
|
|
1035
|
+
if (sfcSource) {
|
|
1036
|
+
const { descriptor } = parse(sfcSource, { filename: absolutePath });
|
|
1037
|
+
const templateSource = descriptor.template?.content || '';
|
|
1038
|
+
if (templateSource) {
|
|
1039
|
+
const id = createHash('md5').update(absolutePath).digest('hex').slice(0, 8);
|
|
1040
|
+
const compiledTemplate = compileTemplate({
|
|
1041
|
+
source: templateSource,
|
|
1042
|
+
id,
|
|
1043
|
+
filename: absolutePath,
|
|
1044
|
+
isProd: false,
|
|
1045
|
+
ssr: false,
|
|
1046
|
+
compilerOptions: {
|
|
1047
|
+
isCustomElement: (tag) => NS_NATIVE_TAGS.has(tag),
|
|
1048
|
+
},
|
|
1049
|
+
});
|
|
1050
|
+
const compiled = (compiledTemplate?.code || '');
|
|
1051
|
+
if (compiled) {
|
|
1052
|
+
inlineBlock = buildInlineTemplateBlock(compiled) || undefined;
|
|
1053
|
+
if (inlineBlock) {
|
|
1054
|
+
inlineOk = true;
|
|
1055
|
+
}
|
|
1056
|
+
else {
|
|
1057
|
+
const extracted = extractTemplateRender(compiled);
|
|
1058
|
+
inlineOk = extracted.ok;
|
|
1059
|
+
helperBindings = extracted.helperBindings;
|
|
1060
|
+
renderDecl = extracted.renderDecl;
|
|
1061
|
+
inlineBlock = extracted.inlineBlock;
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
}
|
|
1067
|
+
catch { }
|
|
1068
|
+
if (!inlineOk) {
|
|
1069
|
+
const extracted = extractTemplateRender(templateCode);
|
|
1070
|
+
inlineOk = extracted.ok;
|
|
1071
|
+
helperBindings = extracted.helperBindings;
|
|
1072
|
+
renderDecl = extracted.renderDecl;
|
|
1073
|
+
inlineBlock = extracted.inlineBlock;
|
|
1074
|
+
}
|
|
1075
|
+
if (!inlineOk) {
|
|
1076
|
+
res.statusCode = 500;
|
|
1077
|
+
res.end(`throw new Error('[sfc-asm] ${base}: template extraction failed');\nexport default {};`);
|
|
1078
|
+
return;
|
|
1079
|
+
}
|
|
1080
|
+
let asm;
|
|
1081
|
+
if (inlineBlock && inlineBlock.trim()) {
|
|
1082
|
+
asm = [`// [sfc-asm] ${base} (inlined template body)`, `export * from ${JSON.stringify(scriptUrl)};`, `import * as __script from ${JSON.stringify(scriptUrl)};`, inlineBlock, `const __ns_sfc__ = (__script && __script.default) ? __script.default : {};`, `try { if (typeof __ns_render === 'function' && !__ns_sfc__.render) __ns_sfc__.render = __ns_render; } catch {}`, 'export default __ns_sfc__;'].join('\n');
|
|
1083
|
+
}
|
|
1084
|
+
else {
|
|
1085
|
+
asm = [`// [sfc-asm] ${base} (inlined template)`, `export * from ${JSON.stringify(scriptUrl)};`, `import * as __script from ${JSON.stringify(scriptUrl)};`, helperBindings, renderDecl, `const __ns_sfc__ = (__script && __script.default) ? __script.default : {};`, `try { if (typeof __ns_render === 'function' && !__ns_sfc__.render) __ns_sfc__.render = __ns_render; } catch {}`, 'export default __ns_sfc__;'].filter(Boolean).join('\n');
|
|
1086
|
+
}
|
|
1087
|
+
let code = options.requireGuardSnippet + asm;
|
|
1088
|
+
code = options.processCodeForDevice(code, false, true, /(?:^|\/)node_modules\//.test(base), base);
|
|
1089
|
+
try {
|
|
1090
|
+
code = options.ensureVersionedCoreImports(code, options.getServerOrigin(server), Number(version));
|
|
1091
|
+
}
|
|
1092
|
+
catch { }
|
|
1093
|
+
code = options.rewriteImports(code, base, options.sfcFileMap, options.depFileMap, projectRoot, !!options.verbose, undefined, options.getServerOrigin(server));
|
|
1094
|
+
try {
|
|
1095
|
+
code = options.ensureDestructureCoreImports(code);
|
|
1096
|
+
}
|
|
1097
|
+
catch { }
|
|
1098
|
+
code = options.ensureVariableDynamicImportHelper(code);
|
|
1099
|
+
code = options.ensureGuardPlainDynamicImports(code, origin);
|
|
1100
|
+
try {
|
|
1101
|
+
const origin = options.getServerOrigin(server);
|
|
1102
|
+
code = options.ensureVersionedRtImports(code, origin, Number(version));
|
|
1103
|
+
code = options.getStrategy().ensureVersionedImports(code, origin, Number(version));
|
|
1104
|
+
code = options.ensureVersionedCoreImports(code, origin, Number(version));
|
|
1105
|
+
}
|
|
1106
|
+
catch { }
|
|
1107
|
+
res.statusCode = 200;
|
|
1108
|
+
res.end(code);
|
|
1109
|
+
}
|
|
1110
|
+
catch {
|
|
1111
|
+
res.statusCode = 500;
|
|
1112
|
+
res.end('export {}\n');
|
|
1113
|
+
}
|
|
1114
|
+
});
|
|
1115
|
+
}
|
|
1116
|
+
//# sourceMappingURL=websocket-vue-sfc.js.map
|