diff --git a/packages/core/src/server/transform/transform-vue.ts b/packages/core/src/server/transform/transform-vue.ts index 66e8204b..cad789e7 100644 --- a/packages/core/src/server/transform/transform-vue.ts +++ b/packages/core/src/server/transform/transform-vue.ts @@ -16,16 +16,30 @@ import { } from './transform-vue-pug'; const VueElementType = 1; -type VueCompilerDom = Pick; +type VueCompilerDom = Pick< + typeof import('@vue/compiler-dom'), + 'parse' | 'transform' +>; const VUE_COMPILER_DOM = '@vue/compiler-dom'; let vueCompilerDomPromise: Promise | undefined; +export function resolveVueCompilerDom(mod: any): VueCompilerDom { + const parse = mod?.parse ?? mod?.default?.parse; + const transform = mod?.transform ?? mod?.default?.transform; + + if (typeof parse !== 'function' || typeof transform !== 'function') { + throw new Error('Failed to load @vue/compiler-dom parse/transform exports'); + } + + return { parse, transform }; +} + async function getVueCompilerDom(): Promise { if (!vueCompilerDomPromise) { vueCompilerDomPromise = import( /* @vite-ignore */ VUE_COMPILER_DOM - ).then(({ parse, transform }) => ({ parse, transform })); + ).then((mod) => resolveVueCompilerDom(mod)); } return vueCompilerDomPromise; } @@ -33,10 +47,11 @@ async function getVueCompilerDom(): Promise { export async function transformVue( content: string, filePath: string, - escapeTags: EscapeTags + escapeTags: EscapeTags, ) { // 兼容 pug 热更新时逻辑 - let prefixSubstring = '', suffixSubstring = ''; + let prefixSubstring = '', + suffixSubstring = ''; if (pugMap.has(filePath)) { try { const absolutePath = @@ -64,7 +79,7 @@ export async function transformVue( // 判断是否为 Pug 模版 const templateNode = ast.children.find( - (node) => node.type === VueElementType && node.tag === 'template' + (node) => node.type === VueElementType && node.tag === 'template', ) as ElementNode; // Check if template uses Pug @@ -82,7 +97,10 @@ export async function transformVue( } let result = s.toString(); - return result.slice(prefixSubstring.length, result.length - suffixSubstring.length); + return result.slice( + prefixSubstring.length, + result.length - suffixSubstring.length, + ); } /** @@ -97,7 +115,7 @@ function transformVueTemplate( filePath: string, escapeTags: EscapeTags, s: MagicString, - transform: VueCompilerDom['transform'] + transform: VueCompilerDom['transform'], ): void { transform(ast, { nodeTransforms: [ diff --git a/packages/core/types/server/transform/transform-vue.d.ts b/packages/core/types/server/transform/transform-vue.d.ts index c60632a0..2cd6417e 100644 --- a/packages/core/types/server/transform/transform-vue.d.ts +++ b/packages/core/types/server/transform/transform-vue.d.ts @@ -1,2 +1,5 @@ import { EscapeTags } from '../../shared'; +type VueCompilerDom = Pick; +export declare function resolveVueCompilerDom(mod: any): VueCompilerDom; export declare function transformVue(content: string, filePath: string, escapeTags: EscapeTags): Promise; +export {}; diff --git a/test/core/server/transform/transform-vue.test.ts b/test/core/server/transform/transform-vue.test.ts index 0502885f..be4d854c 100644 --- a/test/core/server/transform/transform-vue.test.ts +++ b/test/core/server/transform/transform-vue.test.ts @@ -1,6 +1,9 @@ import { describe, it, expect, vi } from 'vitest'; import fs from 'fs'; -import { transformVue } from '@/core/src/server/transform/transform-vue'; +import { + resolveVueCompilerDom, + transformVue, +} from '@/core/src/server/transform/transform-vue'; import { PathName } from '@/core/src/shared/constant'; // Only mock server module, not fs @@ -665,4 +668,21 @@ const count = ref(0); expect(result).toContain(':div"'); }); }); + + describe('compiler-dom interop', () => { + it('should support transform export provided on default namespace', async () => { + const parse = vi.fn(); + const transform = vi.fn(); + + const compilerDom = resolveVueCompilerDom({ + parse, + default: { + transform, + }, + }); + + expect(compilerDom.parse).toBe(parse); + expect(compilerDom.transform).toBe(transform); + }); + }); });