Skip to content

Commit 64d385d

Browse files
fix(vite): preserve Vue plugin imports and canonical runtime bridge
1 parent 3224f1b commit 64d385d

4 files changed

Lines changed: 41 additions & 5 deletions

File tree

‎packages/vite/hmr/frameworks/vue/server/strategy.spec.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ const __hmrId = "foo";
6464
export default {};
6565
`;
6666
const rewritten = vueServerStrategy.rewriteFrameworkImports(raw);
67-
expect(rewritten).toContain('/@nativescript/vendor.mjs');
67+
expect(rewritten).toContain('/ns/rt');
6868

6969
const post = vueServerStrategy.postClean(rewritten);
7070
expect(post).not.toContain('__VUE_HMR_RUNTIME__.reload');

‎packages/vite/hmr/frameworks/vue/server/strategy.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import type { VueSfcRegistryEntry, VueSfcRegistryMessage, VueSfcRegistryUpdateMe
1919
// imports this to inject it as the `processSfcCode` helper for Vue's hooks.
2020
export const processSfcCode = createProcessSfcCode(processCodeForDevice);
2121

22-
const VENDOR_MJS = '/@nativescript/vendor.mjs';
22+
const VUE_RUNTIME = '/ns/rt';
2323
const VUE_HTTP_SFC_DIR = `${getProjectAppPath()}/sfc`;
2424
const VUE_IMPORTS_TO_VENDOR: RegExp[] = [/(from\s+["'])vue(?:\/[A-Za-z0-9_\-\/]+)?(["'])/g, /(from\s+["'])nativescript-vue(?:\/[A-Za-z0-9_\-\/]+)?(["'])/g];
2525

@@ -585,7 +585,7 @@ if (typeof __VUE_HMR_RUNTIME__ === 'undefined') {
585585
rewriteFrameworkImports(code: string) {
586586
let result = code;
587587
for (const pattern of VUE_IMPORTS_TO_VENDOR) {
588-
result = result.replace(pattern, `from "${VENDOR_MJS}"`);
588+
result = result.replace(pattern, `from "${VUE_RUNTIME}"`);
589589
}
590590
return result;
591591
},

‎packages/vite/hmr/helpers/ast-normalizer.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,8 @@ export function astNormalizeModuleImportsAndHelpers(code: string, opts?: { under
7979
const isRtLike = (src: string | null | undefined) => !!src && /(?:https?:\/\/[^"']+)?\/ns\/rt(?:\/[\d]+)?(?:\?p=[^"']+)?$/.test(src);
8080
const isCoreLike = (src: string | null | undefined) => !!src && /(?:https?:\/\/[^"']+)?\/ns\/core(?:\/[\d]+)?(?:\?p=[^"']+)?$/.test(src);
8181
const isSfcPath = (src: string | null | undefined) => !!src && /\.vue(?:\?|$)/.test(src);
82-
const isVuePrebundle = (src: string | null | undefined) => !!src && /\.vite\/deps\/(?:vue|nativescript-vue)[^/]*\.js/.test(src);
83-
const isVuePackage = (src: string | null | undefined) => !!src && (src === 'vue' || src.startsWith('vue/') || src.includes('nativescript-vue'));
82+
const isVuePrebundle = (src: string | null | undefined) => !!src && /\.vite\/deps\/(?:vue|nativescript-vue)(?:_[^/]*)?\.js(?:[?#]|$)/.test(src);
83+
const isVuePackage = (src: string | null | undefined) => !!src && (src === 'vue' || src.startsWith('vue/') || /(?:^|\/)nativescript-vue(?:\/|[?#]|$)/.test(src));
8484
const isVueLike = (src: string | null | undefined) => (isVuePackage(src) || isVuePrebundle(src)) && !isSfcPath(src);
8585
// True virtual modules only (`\0`/`__x00__`-marked). A plain `/@id/<id>`
8686
// is Vite's URL form for any REAL resolved bare id that isn't a file
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { describe, expect, it } from 'vitest';
2+
import { parse } from '@babel/parser';
3+
import { vueServerStrategy } from '../frameworks/vue/server/strategy.js';
4+
import { astNormalizeModuleImportsAndHelpers } from '../helpers/ast-normalizer.js';
5+
import { cleanCode, processCodeForDevice, rewriteImports } from './websocket-device-transform.js';
6+
7+
describe('Vue package imports in HTTP modules', () => {
8+
it('keeps native navigation helpers on the runtime bridge through the full transform', () => {
9+
const source = `import { $navigateTo, ref } from 'nativescript-vue';\nexport const current = ref(null);\nexport function go(page) { $navigateTo(page); }`;
10+
const cleaned = cleanCode(source, vueServerStrategy);
11+
const processed = processCodeForDevice(cleaned, false, true, true, '/node_modules/native-router/dist/frame.js');
12+
const output = rewriteImports(processed, '/node_modules/native-router/dist/frame.js', new Map(), new Map(), '/', false, undefined, 'http://localhost:5173');
13+
expect(output).not.toContain('/@nativescript/vendor.mjs');
14+
expect(output).toContain('/ns/rt');
15+
expect(() => parse(output, { sourceType: 'module' })).not.toThrow();
16+
});
17+
18+
it.each(['vue-router-ns', 'vue-router-ns_file-routing', 'vue-demi', 'nativescript-vue-router'])('does not redirect the %s prebundle to the Vue runtime', (name) => {
19+
const url = `/node_modules/.vite/deps/${name}.js?v=abc`;
20+
const output = astNormalizeModuleImportsAndHelpers(`import { createRouter } from '${url}'; export const router = createRouter();`);
21+
expect(output).toContain(url);
22+
expect(output).not.toContain('/ns/rt');
23+
});
24+
25+
it.each(['vue', 'nativescript-vue', 'vue_dist_vue_runtime_esm-bundler'])('still redirects the %s runtime prebundle', (name) => {
26+
const output = astNormalizeModuleImportsAndHelpers(`import { ref } from '/node_modules/.vite/deps/${name}.js?v=abc'; export const value = ref(0);`);
27+
expect(output).toContain('/ns/rt');
28+
expect(output).not.toContain('/node_modules/.vite/deps/');
29+
});
30+
31+
it('preserves a similarly named bare plugin import', () => {
32+
const output = astNormalizeModuleImportsAndHelpers(`import { createRouter } from 'nativescript-vue-router'; export const router = createRouter();`);
33+
expect(output).toContain('nativescript-vue-router');
34+
expect(output).not.toContain('/ns/rt');
35+
});
36+
});

0 commit comments

Comments
 (0)