From 73e6523134a013f9e369f53f213a214497ac7c40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E5=88=98=28liulinboyi=29?= <814921718@qq.com> Date: Thu, 19 May 2022 07:51:44 +0800 Subject: [PATCH] fix(compiler-sfc): support `export { default } from '...'` (#5937) fix #5935 --- .../__tests__/rewriteDefault.spec.ts | 86 +++++++++++++++++++ packages/compiler-sfc/src/rewriteDefault.ts | 54 ++++++++++-- 2 files changed, 131 insertions(+), 9 deletions(-) diff --git a/packages/compiler-sfc/__tests__/rewriteDefault.spec.ts b/packages/compiler-sfc/__tests__/rewriteDefault.spec.ts index d44eeca0210..ce198fbc236 100644 --- a/packages/compiler-sfc/__tests__/rewriteDefault.spec.ts +++ b/packages/compiler-sfc/__tests__/rewriteDefault.spec.ts @@ -25,6 +25,17 @@ describe('compiler sfc: rewriteDefault', () => { export { a as b, a as c} const script = a" `) + + expect( + rewriteDefault( + `const a = 1 \n export { a as b, a as default , a as c}`, + 'script' + ) + ).toMatchInlineSnapshot(` + "const a = 1 + export { a as b, a as c} + const script = a" + `) }) test('w/ comments', async () => { @@ -63,6 +74,81 @@ describe('compiler sfc: rewriteDefault', () => { // export { myFunction as default } const script = a" `) + + expect( + rewriteDefault( + `const a = 1 \n export {\n a as b,\n a as default ,\n a as c}\n` + + `// export { myFunction as default }`, + 'script' + ) + ).toMatchInlineSnapshot(` + "const a = 1 + export { + a as b, + + a as c} + // export { myFunction as default } + const script = a" + `) + }) + + test(`export { default } from '...'`, async () => { + expect( + rewriteDefault(`export { default, foo } from './index.js'`, 'script') + ).toMatchInlineSnapshot(` + "import { default as __VUE_DEFAULT__ } from './index.js' + export { foo } from './index.js' + const script = __VUE_DEFAULT__" + `) + + expect( + rewriteDefault(`export { default , foo } from './index.js'`, 'script') + ).toMatchInlineSnapshot(` + "import { default as __VUE_DEFAULT__ } from './index.js' + export { foo } from './index.js' + const script = __VUE_DEFAULT__" + `) + + expect( + rewriteDefault(`export { foo, default } from './index.js'`, 'script') + ).toMatchInlineSnapshot(` + "import { default as __VUE_DEFAULT__ } from './index.js' + export { foo, } from './index.js' + const script = __VUE_DEFAULT__" + `) + + expect( + rewriteDefault( + `export { foo as default, bar } from './index.js'`, + 'script' + ) + ).toMatchInlineSnapshot(` + "import { foo } from './index.js' + export { bar } from './index.js' + const script = foo" + `) + + expect( + rewriteDefault( + `export { foo as default , bar } from './index.js'`, + 'script' + ) + ).toMatchInlineSnapshot(` + "import { foo } from './index.js' + export { bar } from './index.js' + const script = foo" + `) + + expect( + rewriteDefault( + `export { bar, foo as default } from './index.js'`, + 'script' + ) + ).toMatchInlineSnapshot(` + "import { foo } from './index.js' + export { bar, } from './index.js' + const script = foo" + `) }) test('export default class', async () => { diff --git a/packages/compiler-sfc/src/rewriteDefault.ts b/packages/compiler-sfc/src/rewriteDefault.ts index f4b2f2e87ae..53db1798b72 100644 --- a/packages/compiler-sfc/src/rewriteDefault.ts +++ b/packages/compiler-sfc/src/rewriteDefault.ts @@ -2,7 +2,7 @@ import { parse, ParserPlugin } from '@babel/parser' import MagicString from 'magic-string' const defaultExportRE = /((?:^|\n|;)\s*)export(\s*)default/ -const namedDefaultExportRE = /((?:^|\n|;)\s*)export(.+)as(\s*)default/s +const namedDefaultExportRE = /((?:^|\n|;)\s*)export(.+)(?:as)?(\s*)default/s const exportDefaultClassRE = /((?:^|\n|;)\s*)export\s+default\s+class\s+([\w$]+)/ @@ -45,21 +45,39 @@ export function rewriteDefault( s.overwrite(node.start!, node.declaration.start!, `const ${as} = `) } if (node.type === 'ExportNamedDeclaration') { - node.specifiers.forEach(specifier => { + for (const specifier of node.specifiers) { if ( specifier.type === 'ExportSpecifier' && specifier.exported.type === 'Identifier' && specifier.exported.name === 'default' ) { - const end = specifier.end! - s.overwrite( - specifier.start!, - input.charAt(end) === ',' ? end + 1 : end, - `` - ) + if (node.source) { + if (specifier.local.name === 'default') { + const end = specifierEnd(input, specifier.local.end!, node.end) + s.prepend( + `import { default as __VUE_DEFAULT__ } from '${node.source.value}'\n` + ) + s.overwrite(specifier.start!, end, ``) + s.append(`\nconst ${as} = __VUE_DEFAULT__`) + continue + } else { + const end = specifierEnd(input, specifier.exported.end!, node.end) + s.prepend( + `import { ${input.slice( + specifier.local.start!, + specifier.local.end! + )} } from '${node.source?.value}'\n` + ) + s.overwrite(specifier.start!, end, ``) + s.append(`\nconst ${as} = ${specifier.local.name}`) + continue + } + } + const end = specifierEnd(input, specifier.end!, node.end) + s.overwrite(specifier.start!, end, ``) s.append(`\nconst ${as} = ${specifier.local.name}`) } - }) + } } }) return s.toString() @@ -68,3 +86,21 @@ export function rewriteDefault( export function hasDefaultExport(input: string): boolean { return defaultExportRE.test(input) || namedDefaultExportRE.test(input) } + +function specifierEnd(input: string, end: number, nodeEnd: number | null) { + // export { default , foo } ... + let hasCommas = false + let oldEnd = end + while (end < nodeEnd!) { + if (/\s/.test(input.charAt(end))) { + end++ + } else if (input.charAt(end) === ',') { + end++ + hasCommas = true + break + } else if (input.charAt(end) === '}') { + break + } + } + return hasCommas ? end : oldEnd +}