mirror of https://github.com/vuejs/core.git
feat(compiler-sfc): support generating variable instead of default export in compileScript
This commit is contained in:
parent
6bda4b6688
commit
71635be68d
|
@ -1963,3 +1963,102 @@ return { props }
|
||||||
|
|
||||||
})"
|
})"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`SFC genDefaultAs > <script setup> only 1`] = `
|
||||||
|
"const a = 1
|
||||||
|
|
||||||
|
const _sfc_ = {
|
||||||
|
setup(__props, { expose: __expose }) {
|
||||||
|
__expose();
|
||||||
|
|
||||||
|
|
||||||
|
return { a }
|
||||||
|
}
|
||||||
|
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`SFC genDefaultAs > <script setup> only w/ ts 1`] = `
|
||||||
|
"import { defineComponent as _defineComponent } from 'vue'
|
||||||
|
const a = 1
|
||||||
|
|
||||||
|
const _sfc_ = /*#__PURE__*/_defineComponent({
|
||||||
|
setup(__props, { expose: __expose }) {
|
||||||
|
__expose();
|
||||||
|
|
||||||
|
|
||||||
|
return { a }
|
||||||
|
}
|
||||||
|
|
||||||
|
})"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`SFC genDefaultAs > <script> + <script setup> 1`] = `
|
||||||
|
"const __default__ = {}
|
||||||
|
|
||||||
|
const _sfc_ = /*#__PURE__*/Object.assign(__default__, {
|
||||||
|
setup(__props, { expose: __expose }) {
|
||||||
|
__expose();
|
||||||
|
|
||||||
|
const a = 1
|
||||||
|
|
||||||
|
return { a }
|
||||||
|
}
|
||||||
|
|
||||||
|
})"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`SFC genDefaultAs > <script> + <script setup> 2`] = `
|
||||||
|
"const __default__ = {}
|
||||||
|
|
||||||
|
const _sfc_ = /*#__PURE__*/Object.assign(__default__, {
|
||||||
|
setup(__props, { expose: __expose }) {
|
||||||
|
__expose();
|
||||||
|
|
||||||
|
const a = 1
|
||||||
|
|
||||||
|
return { a }
|
||||||
|
}
|
||||||
|
|
||||||
|
})"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`SFC genDefaultAs > <script> + <script setup> w/ ts 1`] = `
|
||||||
|
"import { defineComponent as _defineComponent } from 'vue'
|
||||||
|
|
||||||
|
const __default__ = {}
|
||||||
|
|
||||||
|
const _sfc_ = /*#__PURE__*/_defineComponent({
|
||||||
|
...__default__,
|
||||||
|
setup(__props, { expose: __expose }) {
|
||||||
|
__expose();
|
||||||
|
|
||||||
|
const a = 1
|
||||||
|
|
||||||
|
return { a }
|
||||||
|
}
|
||||||
|
|
||||||
|
})"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`SFC genDefaultAs > normal <script> only 1`] = `
|
||||||
|
"
|
||||||
|
const _sfc_ = {}
|
||||||
|
"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`SFC genDefaultAs > normal <script> w/ cssVars 1`] = `
|
||||||
|
"
|
||||||
|
const _sfc_ = {}
|
||||||
|
|
||||||
|
import { useCssVars as _useCssVars } from 'vue'
|
||||||
|
const __injectCSSVars__ = () => {
|
||||||
|
_useCssVars(_ctx => ({
|
||||||
|
\\"xxxxxxxx-x\\": (_ctx.x)
|
||||||
|
}))}
|
||||||
|
const __setup__ = _sfc_.setup
|
||||||
|
_sfc_.setup = __setup__
|
||||||
|
? (props, ctx) => { __injectCSSVars__();return __setup__(props, ctx) }
|
||||||
|
: __injectCSSVars__
|
||||||
|
"
|
||||||
|
`;
|
||||||
|
|
|
@ -2190,3 +2190,122 @@ describe('SFC analyze <script> bindings', () => {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('SFC genDefaultAs', () => {
|
||||||
|
test('normal <script> only', () => {
|
||||||
|
const { content } = compile(
|
||||||
|
`<script>
|
||||||
|
export default {}
|
||||||
|
</script>`,
|
||||||
|
{
|
||||||
|
genDefaultAs: '_sfc_'
|
||||||
|
}
|
||||||
|
)
|
||||||
|
expect(content).not.toMatch('export default')
|
||||||
|
expect(content).toMatch(`const _sfc_ = {}`)
|
||||||
|
assertCode(content)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('normal <script> w/ cssVars', () => {
|
||||||
|
const { content } = compile(
|
||||||
|
`<script>
|
||||||
|
export default {}
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
.foo { color: v-bind(x) }
|
||||||
|
</style>`,
|
||||||
|
{
|
||||||
|
genDefaultAs: '_sfc_'
|
||||||
|
}
|
||||||
|
)
|
||||||
|
expect(content).not.toMatch('export default')
|
||||||
|
expect(content).not.toMatch('__default__')
|
||||||
|
expect(content).toMatch(`const _sfc_ = {}`)
|
||||||
|
assertCode(content)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('<script> + <script setup>', () => {
|
||||||
|
const { content } = compile(
|
||||||
|
`<script>
|
||||||
|
export default {}
|
||||||
|
</script>
|
||||||
|
<script setup>
|
||||||
|
const a = 1
|
||||||
|
</script>`,
|
||||||
|
{
|
||||||
|
genDefaultAs: '_sfc_'
|
||||||
|
}
|
||||||
|
)
|
||||||
|
expect(content).not.toMatch('export default')
|
||||||
|
expect(content).toMatch(
|
||||||
|
`const _sfc_ = /*#__PURE__*/Object.assign(__default__`
|
||||||
|
)
|
||||||
|
assertCode(content)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('<script> + <script setup>', () => {
|
||||||
|
const { content } = compile(
|
||||||
|
`<script>
|
||||||
|
export default {}
|
||||||
|
</script>
|
||||||
|
<script setup>
|
||||||
|
const a = 1
|
||||||
|
</script>`,
|
||||||
|
{
|
||||||
|
genDefaultAs: '_sfc_'
|
||||||
|
}
|
||||||
|
)
|
||||||
|
expect(content).not.toMatch('export default')
|
||||||
|
expect(content).toMatch(
|
||||||
|
`const _sfc_ = /*#__PURE__*/Object.assign(__default__`
|
||||||
|
)
|
||||||
|
assertCode(content)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('<script setup> only', () => {
|
||||||
|
const { content } = compile(
|
||||||
|
`<script setup>
|
||||||
|
const a = 1
|
||||||
|
</script>`,
|
||||||
|
{
|
||||||
|
genDefaultAs: '_sfc_'
|
||||||
|
}
|
||||||
|
)
|
||||||
|
expect(content).not.toMatch('export default')
|
||||||
|
expect(content).toMatch(`const _sfc_ = {\n setup`)
|
||||||
|
assertCode(content)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('<script setup> only w/ ts', () => {
|
||||||
|
const { content } = compile(
|
||||||
|
`<script setup lang="ts">
|
||||||
|
const a = 1
|
||||||
|
</script>`,
|
||||||
|
{
|
||||||
|
genDefaultAs: '_sfc_'
|
||||||
|
}
|
||||||
|
)
|
||||||
|
expect(content).not.toMatch('export default')
|
||||||
|
expect(content).toMatch(`const _sfc_ = /*#__PURE__*/_defineComponent(`)
|
||||||
|
assertCode(content)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('<script> + <script setup> w/ ts', () => {
|
||||||
|
const { content } = compile(
|
||||||
|
`<script lang="ts">
|
||||||
|
export default {}
|
||||||
|
</script>
|
||||||
|
<script setup lang="ts">
|
||||||
|
const a = 1
|
||||||
|
</script>`,
|
||||||
|
{
|
||||||
|
genDefaultAs: '_sfc_'
|
||||||
|
}
|
||||||
|
)
|
||||||
|
expect(content).not.toMatch('export default')
|
||||||
|
expect(content).toMatch(
|
||||||
|
`const _sfc_ = /*#__PURE__*/_defineComponent({\n ...__default__`
|
||||||
|
)
|
||||||
|
assertCode(content)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
|
@ -69,9 +69,6 @@ const DEFINE_EXPOSE = 'defineExpose'
|
||||||
const WITH_DEFAULTS = 'withDefaults'
|
const WITH_DEFAULTS = 'withDefaults'
|
||||||
const DEFINE_OPTIONS = 'defineOptions'
|
const DEFINE_OPTIONS = 'defineOptions'
|
||||||
|
|
||||||
// constants
|
|
||||||
const DEFAULT_VAR = `__default__`
|
|
||||||
|
|
||||||
const isBuiltInDir = makeMap(
|
const isBuiltInDir = makeMap(
|
||||||
`once,memo,if,for,else,else-if,slot,text,html,on,bind,model,show,cloak,is`
|
`once,memo,if,for,else,else-if,slot,text,html,on,bind,model,show,cloak,is`
|
||||||
)
|
)
|
||||||
|
@ -110,6 +107,12 @@ export interface SFCScriptCompileOptions {
|
||||||
* from being hot-reloaded separately from component state.
|
* from being hot-reloaded separately from component state.
|
||||||
*/
|
*/
|
||||||
inlineTemplate?: boolean
|
inlineTemplate?: boolean
|
||||||
|
/**
|
||||||
|
* Generate the final component as a variable instead of default export.
|
||||||
|
* This is useful in e.g. @vitejs/plugin-vue where the script needs to be
|
||||||
|
* placed inside the main module.
|
||||||
|
*/
|
||||||
|
genDefaultAs?: string
|
||||||
/**
|
/**
|
||||||
* Options for template compilation when inlining. Note these are options that
|
* Options for template compilation when inlining. Note these are options that
|
||||||
* would normally be passed to `compiler-sfc`'s own `compileTemplate()`, not
|
* would normally be passed to `compiler-sfc`'s own `compileTemplate()`, not
|
||||||
|
@ -178,6 +181,10 @@ export function compileScript(
|
||||||
const cssVars = sfc.cssVars
|
const cssVars = sfc.cssVars
|
||||||
const scriptLang = script && script.lang
|
const scriptLang = script && script.lang
|
||||||
const scriptSetupLang = scriptSetup && scriptSetup.lang
|
const scriptSetupLang = scriptSetup && scriptSetup.lang
|
||||||
|
const genDefaultAs = options.genDefaultAs
|
||||||
|
? `const ${options.genDefaultAs} =`
|
||||||
|
: `export default`
|
||||||
|
const normalScriptDefaultVar = `__default__`
|
||||||
const isJS =
|
const isJS =
|
||||||
scriptLang === 'js' ||
|
scriptLang === 'js' ||
|
||||||
scriptLang === 'jsx' ||
|
scriptLang === 'jsx' ||
|
||||||
|
@ -216,6 +223,7 @@ export function compileScript(
|
||||||
// do not process non js/ts script blocks
|
// do not process non js/ts script blocks
|
||||||
return script
|
return script
|
||||||
}
|
}
|
||||||
|
// normal <script> only
|
||||||
try {
|
try {
|
||||||
let content = script.content
|
let content = script.content
|
||||||
let map = script.map
|
let map = script.map
|
||||||
|
@ -247,17 +255,23 @@ export function compileScript(
|
||||||
}) as unknown as RawSourceMap
|
}) as unknown as RawSourceMap
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (cssVars.length) {
|
if (cssVars.length || options.genDefaultAs) {
|
||||||
|
const defaultVar = options.genDefaultAs || normalScriptDefaultVar
|
||||||
const s = new MagicString(content)
|
const s = new MagicString(content)
|
||||||
rewriteDefaultAST(scriptAst.body, s, DEFAULT_VAR)
|
rewriteDefaultAST(scriptAst.body, s, defaultVar)
|
||||||
content = s.toString()
|
content = s.toString()
|
||||||
content += genNormalScriptCssVarsCode(
|
if (cssVars.length) {
|
||||||
cssVars,
|
content += genNormalScriptCssVarsCode(
|
||||||
bindings,
|
cssVars,
|
||||||
scopeId,
|
bindings,
|
||||||
isProd
|
scopeId,
|
||||||
)
|
isProd,
|
||||||
content += `\nexport default ${DEFAULT_VAR}`
|
defaultVar
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (!options.genDefaultAs) {
|
||||||
|
content += `\nexport default ${defaultVar}`
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
...script,
|
...script,
|
||||||
|
@ -1189,7 +1203,7 @@ export function compileScript(
|
||||||
// export default { ... } --> const __default__ = { ... }
|
// export default { ... } --> const __default__ = { ... }
|
||||||
const start = node.start! + scriptStartOffset!
|
const start = node.start! + scriptStartOffset!
|
||||||
const end = node.declaration.start! + scriptStartOffset!
|
const end = node.declaration.start! + scriptStartOffset!
|
||||||
s.overwrite(start, end, `const ${DEFAULT_VAR} = `)
|
s.overwrite(start, end, `const ${normalScriptDefaultVar} = `)
|
||||||
} else if (node.type === 'ExportNamedDeclaration') {
|
} else if (node.type === 'ExportNamedDeclaration') {
|
||||||
const defaultSpecifier = node.specifiers.find(
|
const defaultSpecifier = node.specifiers.find(
|
||||||
s => s.exported.type === 'Identifier' && s.exported.name === 'default'
|
s => s.exported.type === 'Identifier' && s.exported.name === 'default'
|
||||||
|
@ -1213,14 +1227,14 @@ export function compileScript(
|
||||||
// rewrite to `import { x as __default__ } from './x'` and
|
// rewrite to `import { x as __default__ } from './x'` and
|
||||||
// add to top
|
// add to top
|
||||||
s.prepend(
|
s.prepend(
|
||||||
`import { ${defaultSpecifier.local.name} as ${DEFAULT_VAR} } from '${node.source.value}'\n`
|
`import { ${defaultSpecifier.local.name} as ${normalScriptDefaultVar} } from '${node.source.value}'\n`
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
// export { x as default }
|
// export { x as default }
|
||||||
// rewrite to `const __default__ = x` and move to end
|
// rewrite to `const __default__ = x` and move to end
|
||||||
s.appendLeft(
|
s.appendLeft(
|
||||||
scriptEndOffset!,
|
scriptEndOffset!,
|
||||||
`\nconst ${DEFAULT_VAR} = ${defaultSpecifier.local.name}\n`
|
`\nconst ${normalScriptDefaultVar} = ${defaultSpecifier.local.name}\n`
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1793,11 +1807,11 @@ export function compileScript(
|
||||||
// user's TS setting should compile it down to proper targets
|
// user's TS setting should compile it down to proper targets
|
||||||
// export default defineComponent({ ...__default__, ... })
|
// export default defineComponent({ ...__default__, ... })
|
||||||
const def =
|
const def =
|
||||||
(defaultExport ? `\n ...${DEFAULT_VAR},` : ``) +
|
(defaultExport ? `\n ...${normalScriptDefaultVar},` : ``) +
|
||||||
(definedOptions ? `\n ...${definedOptions},` : '')
|
(definedOptions ? `\n ...${definedOptions},` : '')
|
||||||
s.prependLeft(
|
s.prependLeft(
|
||||||
startOffset,
|
startOffset,
|
||||||
`\nexport default /*#__PURE__*/${helper(
|
`\n${genDefaultAs} /*#__PURE__*/${helper(
|
||||||
`defineComponent`
|
`defineComponent`
|
||||||
)}({${def}${runtimeOptions}\n ${
|
)}({${def}${runtimeOptions}\n ${
|
||||||
hasAwait ? `async ` : ``
|
hasAwait ? `async ` : ``
|
||||||
|
@ -1810,8 +1824,8 @@ export function compileScript(
|
||||||
// export default Object.assign(__default__, { ... })
|
// export default Object.assign(__default__, { ... })
|
||||||
s.prependLeft(
|
s.prependLeft(
|
||||||
startOffset,
|
startOffset,
|
||||||
`\nexport default /*#__PURE__*/Object.assign(${
|
`\n${genDefaultAs} /*#__PURE__*/Object.assign(${
|
||||||
defaultExport ? `${DEFAULT_VAR}, ` : ''
|
defaultExport ? `${normalScriptDefaultVar}, ` : ''
|
||||||
}${definedOptions ? `${definedOptions}, ` : ''}{${runtimeOptions}\n ` +
|
}${definedOptions ? `${definedOptions}, ` : ''}{${runtimeOptions}\n ` +
|
||||||
`${hasAwait ? `async ` : ``}setup(${args}) {\n${exposeCall}`
|
`${hasAwait ? `async ` : ``}setup(${args}) {\n${exposeCall}`
|
||||||
)
|
)
|
||||||
|
@ -1819,7 +1833,7 @@ export function compileScript(
|
||||||
} else {
|
} else {
|
||||||
s.prependLeft(
|
s.prependLeft(
|
||||||
startOffset,
|
startOffset,
|
||||||
`\nexport default {${runtimeOptions}\n ` +
|
`\n${genDefaultAs} {${runtimeOptions}\n ` +
|
||||||
`${hasAwait ? `async ` : ``}setup(${args}) {\n${exposeCall}`
|
`${hasAwait ? `async ` : ``}setup(${args}) {\n${exposeCall}`
|
||||||
)
|
)
|
||||||
s.appendRight(endOffset, `}`)
|
s.appendRight(endOffset, `}`)
|
||||||
|
@ -1839,7 +1853,6 @@ export function compileScript(
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...scriptSetup,
|
...scriptSetup,
|
||||||
s,
|
|
||||||
bindings: bindingMetadata,
|
bindings: bindingMetadata,
|
||||||
imports: userImports,
|
imports: userImports,
|
||||||
content: s.toString(),
|
content: s.toString(),
|
||||||
|
|
|
@ -184,7 +184,8 @@ export function genNormalScriptCssVarsCode(
|
||||||
cssVars: string[],
|
cssVars: string[],
|
||||||
bindings: BindingMetadata,
|
bindings: BindingMetadata,
|
||||||
id: string,
|
id: string,
|
||||||
isProd: boolean
|
isProd: boolean,
|
||||||
|
defaultVar: string
|
||||||
): string {
|
): string {
|
||||||
return (
|
return (
|
||||||
`\nimport { ${CSS_VARS_HELPER} as _${CSS_VARS_HELPER} } from 'vue'\n` +
|
`\nimport { ${CSS_VARS_HELPER} as _${CSS_VARS_HELPER} } from 'vue'\n` +
|
||||||
|
@ -194,8 +195,8 @@ export function genNormalScriptCssVarsCode(
|
||||||
id,
|
id,
|
||||||
isProd
|
isProd
|
||||||
)}}\n` +
|
)}}\n` +
|
||||||
`const __setup__ = __default__.setup\n` +
|
`const __setup__ = ${defaultVar}.setup\n` +
|
||||||
`__default__.setup = __setup__\n` +
|
`${defaultVar}.setup = __setup__\n` +
|
||||||
` ? (props, ctx) => { __injectCSSVars__();return __setup__(props, ctx) }\n` +
|
` ? (props, ctx) => { __injectCSSVars__();return __setup__(props, ctx) }\n` +
|
||||||
` : __injectCSSVars__\n`
|
` : __injectCSSVars__\n`
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
export const version = __VERSION__
|
||||||
|
|
||||||
// API
|
// API
|
||||||
export { parse } from './parse'
|
export { parse } from './parse'
|
||||||
export { compileTemplate } from './compileTemplate'
|
export { compileTemplate } from './compileTemplate'
|
||||||
|
|
|
@ -12,7 +12,6 @@ import { TemplateCompiler } from './compileTemplate'
|
||||||
import { parseCssVars } from './cssVars'
|
import { parseCssVars } from './cssVars'
|
||||||
import { createCache } from './cache'
|
import { createCache } from './cache'
|
||||||
import { hmrShouldReload, ImportBinding } from './compileScript'
|
import { hmrShouldReload, ImportBinding } from './compileScript'
|
||||||
import MagicString from 'magic-string'
|
|
||||||
|
|
||||||
export const DEFAULT_FILENAME = 'anonymous.vue'
|
export const DEFAULT_FILENAME = 'anonymous.vue'
|
||||||
|
|
||||||
|
@ -42,7 +41,6 @@ export interface SFCTemplateBlock extends SFCBlock {
|
||||||
|
|
||||||
export interface SFCScriptBlock extends SFCBlock {
|
export interface SFCScriptBlock extends SFCBlock {
|
||||||
type: 'script'
|
type: 'script'
|
||||||
s: MagicString
|
|
||||||
setup?: string | boolean
|
setup?: string | boolean
|
||||||
bindings?: BindingMetadata
|
bindings?: BindingMetadata
|
||||||
imports?: Record<string, ImportBinding>
|
imports?: Record<string, ImportBinding>
|
||||||
|
|
Loading…
Reference in New Issue