"import { x } from './x'
export const n = 1
+
+ const __default__ = {}
-export default {
+export default /*#__PURE__*/Object.assign(__default__, {
setup(__props, { expose }) {
expose();
return { n, x }
}
-}"
+})"
`;
exports[`SFC compile <script setup> <script> and <script setup> co-usage script setup first 1`] = `
-"import { x } from './x'
+"export const n = 1
+ const __default__ = {}
+ import { x } from './x'
-export default {
+export default /*#__PURE__*/Object.assign(__default__, {
setup(__props, { expose }) {
expose();
return { n, x }
}
-}
- export const n = 1"
+})"
`;
exports[`SFC compile <script setup> <script> and <script setup> co-usage script setup first, lang="ts", script block content export default 1`] = `
"import { defineComponent as _defineComponent } from 'vue'
-import { x } from './x'
+
+ const __default__ = {
+ name: \\"test\\"
+ }
+ import { x } from './x'
-function setup(__props, { expose }) {
+export default /*#__PURE__*/_defineComponent({
+ ...__default__,
+ setup(__props, { expose }) {
+ expose();
x()
return { x }
}
+})"
+`;
- const __default__ = {
- name: \\"test\\"
- }
+exports[`SFC compile <script setup> <script> and <script setup> co-usage script setup first, named default export 1`] = `
+"export const n = 1
+ const def = {}
-export default /*#__PURE__*/_defineComponent({
- ...__default__,
- setup})"
+
+const __default__ = def
+import { x } from './x'
+
+export default /*#__PURE__*/Object.assign(__default__, {
+ setup(__props, { expose }) {
+ expose();
+
+ x()
+
+return { n, def, x }
+}
+
+})"
`;
exports[`SFC compile <script setup> <script> and <script setup> co-usage spaces in ExportDefaultDeclaration node with many spaces and newline 1`] = `
some:'option'
}
-function setup(__props, { expose }) {
+export default /*#__PURE__*/Object.assign(__default__, {
+ setup(__props, { expose }) {
+ expose();
x()
return { n, x }
}
-
-export default /*#__PURE__*/ Object.assign(__default__, {
- setup
})"
`;
some:'option'
}
-function setup(__props, { expose }) {
+export default /*#__PURE__*/Object.assign(__default__, {
+ setup(__props, { expose }) {
+ expose();
x()
return { n, x }
}
-
-export default /*#__PURE__*/ Object.assign(__default__, {
- setup
})"
`;
`;
exports[`SFC compile <script setup> should expose top level declarations 1`] = `
-"import { x } from './x'
+"import { xx } from './x'
+ let aa = 1
+ const bb = 2
+ function cc() {}
+ class dd {}
+ import { x } from './x'
export default {
setup(__props, { expose }) {
return { aa, bb, cc, dd, a, b, c, d, xx, x }
}
-}
- import { xx } from './x'
- let aa = 1
- const bb = 2
- function cc() {}
- class dd {}"
+}"
`;
exports[`SFC compile <script setup> with TypeScript const Enum 1`] = `
})
describe('<script> and <script setup> co-usage', () => {
- describe('spaces in ExportDefaultDeclaration node', () => {
- // #4371
- test('with many spaces and newline', () => {
- // #4371
- const { content } = compile(`
- <script>
- export const n = 1
- export default
- {
- some:'option'
- }
- </script>
- <script setup>
- import { x } from './x'
- x()
- </script>
- `)
- assertCode(content)
- })
-
- test('with minimal spaces', () => {
- const { content } = compile(`
- <script>
- export const n = 1
- export default{
- some:'option'
- }
- </script>
- <script setup>
- import { x } from './x'
- x()
- </script>
- `)
- assertCode(content)
- })
- })
-
test('script first', () => {
const { content } = compile(`
<script>
export const n = 1
+
+ export default {}
</script>
<script setup>
import { x } from './x'
</script>
<script>
export const n = 1
+ export default {}
+ </script>
+ `)
+ assertCode(content)
+ })
+
+ test('script setup first, named default export', () => {
+ const { content } = compile(`
+ <script setup>
+ import { x } from './x'
+ x()
+ </script>
+ <script>
+ export const n = 1
+ const def = {}
+ export { def as default }
</script>
`)
assertCode(content)
expect(content).toMatch(/const __default__[\S\s]*\.\.\.__default__/m)
assertCode(content)
})
+
+ describe('spaces in ExportDefaultDeclaration node', () => {
+ // #4371
+ test('with many spaces and newline', () => {
+ // #4371
+ const { content } = compile(`
+ <script>
+ export const n = 1
+ export default
+ {
+ some:'option'
+ }
+ </script>
+ <script setup>
+ import { x } from './x'
+ x()
+ </script>
+ `)
+ assertCode(content)
+ })
+
+ test('with minimal spaces', () => {
+ const { content } = compile(`
+ <script>
+ export const n = 1
+ export default{
+ some:'option'
+ }
+ </script>
+ <script setup>
+ import { x } from './x'
+ x()
+ </script>
+ `)
+ assertCode(content)
+ })
+ })
})
describe('imports', () => {
const DEFINE_EXPOSE = 'defineExpose'
const WITH_DEFAULTS = 'withDefaults'
+// constants
+const DEFAULT_VAR = `__default__`
+
const isBuiltInDir = makeMap(
`once,memo,if,else,else-if,slot,text,html,on,bind,model,show,cloak,is`
)
}
}
if (cssVars.length) {
- content = rewriteDefault(content, `__default__`, plugins)
+ content = rewriteDefault(content, DEFAULT_VAR, plugins)
content += genNormalScriptCssVarsCode(
cssVars,
bindings,
scopeId,
isProd
)
- content += `\nexport default __default__`
+ content += `\nexport default ${DEFAULT_VAR}`
}
return {
...script,
// metadata that needs to be returned
const bindingMetadata: BindingMetadata = {}
- const defaultTempVar = `__default__`
const helperImports: Set<string> = new Set()
const userImports: Record<string, ImportBinding> = Object.create(null)
const userImportAlias: Record<string, string> = Object.create(null)
// 1. process normal <script> first if it exists
let scriptAst: Program | undefined
if (script) {
- // import dedupe between <script> and <script setup>
scriptAst = parse(
script.content,
{
} else if (node.type === 'ExportDefaultDeclaration') {
// export default
defaultExport = node
+ // export default { ... } --> const __default__ = { ... }
const start = node.start! + scriptStartOffset!
const end = node.declaration.start! + scriptStartOffset!
- s.overwrite(start, end, `const ${defaultTempVar} = `)
+ s.overwrite(start, end, `const ${DEFAULT_VAR} = `)
} else if (node.type === 'ExportNamedDeclaration') {
const defaultSpecifier = node.specifiers.find(
s => s.exported.type === 'Identifier' && s.exported.name === 'default'
// rewrite to `import { x as __default__ } from './x'` and
// add to top
s.prepend(
- `import { ${defaultSpecifier.local.name} as ${defaultTempVar} } from '${node.source.value}'\n`
+ `import { ${defaultSpecifier.local.name} as ${DEFAULT_VAR} } from '${node.source.value}'\n`
)
} else {
// export { x as default }
// rewrite to `const __default__ = x` and move to end
- s.append(
- `\nconst ${defaultTempVar} = ${defaultSpecifier.local.name}\n`
+ s.appendLeft(
+ scriptEndOffset!,
+ `\nconst ${DEFAULT_VAR} = ${defaultSpecifier.local.name}\n`
)
}
}
helperImports.add(h)
}
}
+
+ // <script> after <script setup>
+ // we need to move the block up so that `const __default__` is
+ // declared before being used in the actual component definition
+ if (scriptStartOffset! > startOffset) {
+ s.move(scriptStartOffset!, scriptEndOffset!, 0)
+ }
}
// 2. parse <script setup> and walk over top level statements
// explicitly call `defineExpose`, call expose() with no args.
const exposeCall =
hasDefineExposeCall || options.inlineTemplate ? `` : ` expose();\n`
+ // wrap setup code with function.
if (isTS) {
// for TS, make sure the exported type is still valid type with
// correct props information
// we have to use object spread for types to be merged properly
// user's TS setting should compile it down to proper targets
- const def = defaultExport ? `\n ...${defaultTempVar},` : ``
- // wrap setup code with function.
- // export the content of <script setup> as a named export, `setup`.
- // this allows `import { setup } from '*.vue'` for testing purposes.
- if (defaultExport) {
- s.prependLeft(
- startOffset,
- `\n${hasAwait ? `async ` : ``}function setup(${args}) {\n`
- )
- s.append(
- `\nexport default /*#__PURE__*/${helper(
- `defineComponent`
- )}({${def}${runtimeOptions}\n setup})`
- )
- } else {
- s.prependLeft(
- startOffset,
- `\nexport default /*#__PURE__*/${helper(
- `defineComponent`
- )}({${def}${runtimeOptions}\n ${
- hasAwait ? `async ` : ``
- }setup(${args}) {\n${exposeCall}`
- )
- s.appendRight(endOffset, `})`)
- }
+ // export default defineComponent({ ...__default__, ... })
+ const def = defaultExport ? `\n ...${DEFAULT_VAR},` : ``
+ s.prependLeft(
+ startOffset,
+ `\nexport default /*#__PURE__*/${helper(
+ `defineComponent`
+ )}({${def}${runtimeOptions}\n ${
+ hasAwait ? `async ` : ``
+ }setup(${args}) {\n${exposeCall}`
+ )
+ s.appendRight(endOffset, `})`)
} else {
if (defaultExport) {
- // can't rely on spread operator in non ts mode
+ // without TS, can't rely on rest spread, so we use Object.assign
+ // export default Object.assign(__default__, { ... })
s.prependLeft(
startOffset,
- `\n${hasAwait ? `async ` : ``}function setup(${args}) {\n`
- )
- s.append(
- `\nexport default /*#__PURE__*/ Object.assign(${defaultTempVar}, {${runtimeOptions}\n setup\n})\n`
+ `\nexport default /*#__PURE__*/Object.assign(${DEFAULT_VAR}, {${runtimeOptions}\n ` +
+ `${hasAwait ? `async ` : ``}setup(${args}) {\n${exposeCall}`
)
+ s.appendRight(endOffset, `})`)
} else {
s.prependLeft(
startOffset,