diff --git a/src/transform.ts b/src/transform.ts index 68b5b6e4..43d6bee1 100644 --- a/src/transform.ts +++ b/src/transform.ts @@ -6,6 +6,7 @@ import type { } from 'vue/compiler-sfc' import { type Transform, transform } from 'sucrase' import hashId from 'hash-sum' +import { extractVueImport, mergeVueImports } from './utils' export const COMP_IDENTIFIER = `__sfc__` @@ -172,7 +173,20 @@ export async function compileFile( if (Array.isArray(clientTemplateResult)) { return clientTemplateResult } - clientCode += `;${clientTemplateResult}` + + if (isJSX) { + // Template compilation products may have the same Vue import as script compilation products + const { cleanedCode: clientCleanedCode, imports: clientImports } = + extractVueImport(clientCode) + const { cleanedCode: templateCleanedCode, imports: templateImports } = + extractVueImport(clientTemplateResult) + const mergeImports = mergeVueImports(clientImports, templateImports) + + clientCode = `${mergeImports} +${clientCleanedCode};${templateCleanedCode}` + } else { + clientCode += `;${clientTemplateResult}` + } const ssrTemplateResult = await doCompileTemplate( store, @@ -185,7 +199,19 @@ export async function compileFile( ) if (typeof ssrTemplateResult === 'string') { // ssr compile failure is fine - ssrCode += `;${ssrTemplateResult}` + if (isJSX) { + // Template compilation products may have the same Vue import as script compilation products + const { cleanedCode: ssrCleanedCode, imports: ssrImports } = + extractVueImport(ssrCode) + const { cleanedCode: templateCleanedCode, imports: templateImports } = + extractVueImport(ssrTemplateResult) + const mergeImports = mergeVueImports(ssrImports, templateImports) + + ssrCode = `${mergeImports} +${ssrCleanedCode};${templateCleanedCode}` + } else { + ssrCode += `;${ssrTemplateResult}` + } } else { ssrCode = `/* SSR compile error: ${ssrTemplateResult[0]} */` } diff --git a/src/utils.ts b/src/utils.ts index 3b453ca1..13148223 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -31,3 +31,44 @@ export function atou(base64: string): string { // https://base64.guru/developers/javascript/examples/unicode-strings return decodeURIComponent(escape(binary)) } + +export function extractVueImport(sourceCode: string) { + const importPattern = /^import\s*{[^}]*}\s*from\s*["']vue["'];?/gm + + const importMatches = sourceCode.match(importPattern) + + const imports = importMatches + ? importMatches.map((match) => match.trim())[0] + : '' + + const cleanedCode = sourceCode.replace(importPattern, '') + + return { + cleanedCode, + imports, + } +} + +export function mergeVueImports(imports1: string, imports2: string) { + const importPattern = /{([\s\S]*?)}/ + + const matches1 = imports1.match(importPattern) + const content1 = matches1 ? matches1[1].trim() : '' + + const matches2 = imports2.match(importPattern) + const content2 = matches2 ? matches2[1].trim() : '' + + const mergedContent = Array.from( + new Set( + content1 + .split(',') + .map((item) => item.trim()) + .concat(content2.split(',').map((item) => item.trim())), + ), + ).join(', ') + + //Merge import statements of template and jsx + const mergedImport = `import { ${mergedContent} } from 'vue';` + + return mergedImport +}