Skip to content

Commit 73e6523

Browse files
authored
fix(compiler-sfc): support export { default } from '...' (#5937)
fix #5935
1 parent 991d623 commit 73e6523

File tree

2 files changed

+131
-9
lines changed

2 files changed

+131
-9
lines changed

packages/compiler-sfc/__tests__/rewriteDefault.spec.ts

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,17 @@ describe('compiler sfc: rewriteDefault', () => {
2525
export { a as b, a as c}
2626
const script = a"
2727
`)
28+
29+
expect(
30+
rewriteDefault(
31+
`const a = 1 \n export { a as b, a as default , a as c}`,
32+
'script'
33+
)
34+
).toMatchInlineSnapshot(`
35+
"const a = 1
36+
export { a as b, a as c}
37+
const script = a"
38+
`)
2839
})
2940

3041
test('w/ comments', async () => {
@@ -63,6 +74,81 @@ describe('compiler sfc: rewriteDefault', () => {
6374
// export { myFunction as default }
6475
const script = a"
6576
`)
77+
78+
expect(
79+
rewriteDefault(
80+
`const a = 1 \n export {\n a as b,\n a as default ,\n a as c}\n` +
81+
`// export { myFunction as default }`,
82+
'script'
83+
)
84+
).toMatchInlineSnapshot(`
85+
"const a = 1
86+
export {
87+
a as b,
88+
89+
a as c}
90+
// export { myFunction as default }
91+
const script = a"
92+
`)
93+
})
94+
95+
test(`export { default } from '...'`, async () => {
96+
expect(
97+
rewriteDefault(`export { default, foo } from './index.js'`, 'script')
98+
).toMatchInlineSnapshot(`
99+
"import { default as __VUE_DEFAULT__ } from './index.js'
100+
export { foo } from './index.js'
101+
const script = __VUE_DEFAULT__"
102+
`)
103+
104+
expect(
105+
rewriteDefault(`export { default , foo } from './index.js'`, 'script')
106+
).toMatchInlineSnapshot(`
107+
"import { default as __VUE_DEFAULT__ } from './index.js'
108+
export { foo } from './index.js'
109+
const script = __VUE_DEFAULT__"
110+
`)
111+
112+
expect(
113+
rewriteDefault(`export { foo, default } from './index.js'`, 'script')
114+
).toMatchInlineSnapshot(`
115+
"import { default as __VUE_DEFAULT__ } from './index.js'
116+
export { foo, } from './index.js'
117+
const script = __VUE_DEFAULT__"
118+
`)
119+
120+
expect(
121+
rewriteDefault(
122+
`export { foo as default, bar } from './index.js'`,
123+
'script'
124+
)
125+
).toMatchInlineSnapshot(`
126+
"import { foo } from './index.js'
127+
export { bar } from './index.js'
128+
const script = foo"
129+
`)
130+
131+
expect(
132+
rewriteDefault(
133+
`export { foo as default , bar } from './index.js'`,
134+
'script'
135+
)
136+
).toMatchInlineSnapshot(`
137+
"import { foo } from './index.js'
138+
export { bar } from './index.js'
139+
const script = foo"
140+
`)
141+
142+
expect(
143+
rewriteDefault(
144+
`export { bar, foo as default } from './index.js'`,
145+
'script'
146+
)
147+
).toMatchInlineSnapshot(`
148+
"import { foo } from './index.js'
149+
export { bar, } from './index.js'
150+
const script = foo"
151+
`)
66152
})
67153

68154
test('export default class', async () => {

packages/compiler-sfc/src/rewriteDefault.ts

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { parse, ParserPlugin } from '@babel/parser'
22
import MagicString from 'magic-string'
33

44
const defaultExportRE = /((?:^|\n|;)\s*)export(\s*)default/
5-
const namedDefaultExportRE = /((?:^|\n|;)\s*)export(.+)as(\s*)default/s
5+
const namedDefaultExportRE = /((?:^|\n|;)\s*)export(.+)(?:as)?(\s*)default/s
66
const exportDefaultClassRE =
77
/((?:^|\n|;)\s*)export\s+default\s+class\s+([\w$]+)/
88

@@ -45,21 +45,39 @@ export function rewriteDefault(
4545
s.overwrite(node.start!, node.declaration.start!, `const ${as} = `)
4646
}
4747
if (node.type === 'ExportNamedDeclaration') {
48-
node.specifiers.forEach(specifier => {
48+
for (const specifier of node.specifiers) {
4949
if (
5050
specifier.type === 'ExportSpecifier' &&
5151
specifier.exported.type === 'Identifier' &&
5252
specifier.exported.name === 'default'
5353
) {
54-
const end = specifier.end!
55-
s.overwrite(
56-
specifier.start!,
57-
input.charAt(end) === ',' ? end + 1 : end,
58-
``
59-
)
54+
if (node.source) {
55+
if (specifier.local.name === 'default') {
56+
const end = specifierEnd(input, specifier.local.end!, node.end)
57+
s.prepend(
58+
`import { default as __VUE_DEFAULT__ } from '${node.source.value}'\n`
59+
)
60+
s.overwrite(specifier.start!, end, ``)
61+
s.append(`\nconst ${as} = __VUE_DEFAULT__`)
62+
continue
63+
} else {
64+
const end = specifierEnd(input, specifier.exported.end!, node.end)
65+
s.prepend(
66+
`import { ${input.slice(
67+
specifier.local.start!,
68+
specifier.local.end!
69+
)} } from '${node.source?.value}'\n`
70+
)
71+
s.overwrite(specifier.start!, end, ``)
72+
s.append(`\nconst ${as} = ${specifier.local.name}`)
73+
continue
74+
}
75+
}
76+
const end = specifierEnd(input, specifier.end!, node.end)
77+
s.overwrite(specifier.start!, end, ``)
6078
s.append(`\nconst ${as} = ${specifier.local.name}`)
6179
}
62-
})
80+
}
6381
}
6482
})
6583
return s.toString()
@@ -68,3 +86,21 @@ export function rewriteDefault(
6886
export function hasDefaultExport(input: string): boolean {
6987
return defaultExportRE.test(input) || namedDefaultExportRE.test(input)
7088
}
89+
90+
function specifierEnd(input: string, end: number, nodeEnd: number | null) {
91+
// export { default , foo } ...
92+
let hasCommas = false
93+
let oldEnd = end
94+
while (end < nodeEnd!) {
95+
if (/\s/.test(input.charAt(end))) {
96+
end++
97+
} else if (input.charAt(end) === ',') {
98+
end++
99+
hasCommas = true
100+
break
101+
} else if (input.charAt(end) === '}') {
102+
break
103+
}
104+
}
105+
return hasCommas ? end : oldEnd
106+
}

0 commit comments

Comments
 (0)