Skip to content

Commit

Permalink
feat(compiler-sfc): support generating variable instead of default ex…
Browse files Browse the repository at this point in the history
…port in compileScript
  • Loading branch information
yyx990803 committed Mar 30, 2023
1 parent 6bda4b6 commit 71635be
Show file tree
Hide file tree
Showing 6 changed files with 258 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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__
"
`;
119 changes: 119 additions & 0 deletions packages/compiler-sfc/__tests__/compileScript.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
})
})
55 changes: 34 additions & 21 deletions packages/compiler-sfc/src/compileScript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,6 @@ const DEFINE_EXPOSE = 'defineExpose'
const WITH_DEFAULTS = 'withDefaults'
const DEFINE_OPTIONS = 'defineOptions'

// constants
const DEFAULT_VAR = `__default__`

const isBuiltInDir = makeMap(
`once,memo,if,for,else,else-if,slot,text,html,on,bind,model,show,cloak,is`
)
Expand Down Expand Up @@ -110,6 +107,12 @@ export interface SFCScriptCompileOptions {
* from being hot-reloaded separately from component state.
*/
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
* would normally be passed to `compiler-sfc`'s own `compileTemplate()`, not
Expand Down Expand Up @@ -178,6 +181,10 @@ export function compileScript(
const cssVars = sfc.cssVars
const scriptLang = script && script.lang
const scriptSetupLang = scriptSetup && scriptSetup.lang
const genDefaultAs = options.genDefaultAs
? `const ${options.genDefaultAs} =`
: `export default`
const normalScriptDefaultVar = `__default__`
const isJS =
scriptLang === 'js' ||
scriptLang === 'jsx' ||
Expand Down Expand Up @@ -216,6 +223,7 @@ export function compileScript(
// do not process non js/ts script blocks
return script
}
// normal <script> only
try {
let content = script.content
let map = script.map
Expand Down Expand Up @@ -247,17 +255,23 @@ export function compileScript(
}) as unknown as RawSourceMap
}
}
if (cssVars.length) {
if (cssVars.length || options.genDefaultAs) {
const defaultVar = options.genDefaultAs || normalScriptDefaultVar
const s = new MagicString(content)
rewriteDefaultAST(scriptAst.body, s, DEFAULT_VAR)
rewriteDefaultAST(scriptAst.body, s, defaultVar)
content = s.toString()
content += genNormalScriptCssVarsCode(
cssVars,
bindings,
scopeId,
isProd
)
content += `\nexport default ${DEFAULT_VAR}`
if (cssVars.length) {
content += genNormalScriptCssVarsCode(
cssVars,
bindings,
scopeId,
isProd,
defaultVar
)
}
if (!options.genDefaultAs) {
content += `\nexport default ${defaultVar}`
}
}
return {
...script,
Expand Down Expand Up @@ -1189,7 +1203,7 @@ export function compileScript(
// export default { ... } --> const __default__ = { ... }
const start = node.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') {
const defaultSpecifier = node.specifiers.find(
s => s.exported.type === 'Identifier' && s.exported.name === 'default'
Expand All @@ -1213,14 +1227,14 @@ export function compileScript(
// rewrite to `import { x as __default__ } from './x'` and
// add to top
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 {
// export { x as default }
// rewrite to `const __default__ = x` and move to end
s.appendLeft(
scriptEndOffset!,
`\nconst ${DEFAULT_VAR} = ${defaultSpecifier.local.name}\n`
`\nconst ${normalScriptDefaultVar} = ${defaultSpecifier.local.name}\n`
)
}
}
Expand Down Expand Up @@ -1793,11 +1807,11 @@ export function compileScript(
// user's TS setting should compile it down to proper targets
// export default defineComponent({ ...__default__, ... })
const def =
(defaultExport ? `\n ...${DEFAULT_VAR},` : ``) +
(defaultExport ? `\n ...${normalScriptDefaultVar},` : ``) +
(definedOptions ? `\n ...${definedOptions},` : '')
s.prependLeft(
startOffset,
`\nexport default /*#__PURE__*/${helper(
`\n${genDefaultAs} /*#__PURE__*/${helper(
`defineComponent`
)}({${def}${runtimeOptions}\n ${
hasAwait ? `async ` : ``
Expand All @@ -1810,16 +1824,16 @@ export function compileScript(
// export default Object.assign(__default__, { ... })
s.prependLeft(
startOffset,
`\nexport default /*#__PURE__*/Object.assign(${
defaultExport ? `${DEFAULT_VAR}, ` : ''
`\n${genDefaultAs} /*#__PURE__*/Object.assign(${
defaultExport ? `${normalScriptDefaultVar}, ` : ''
}${definedOptions ? `${definedOptions}, ` : ''}{${runtimeOptions}\n ` +
`${hasAwait ? `async ` : ``}setup(${args}) {\n${exposeCall}`
)
s.appendRight(endOffset, `})`)
} else {
s.prependLeft(
startOffset,
`\nexport default {${runtimeOptions}\n ` +
`\n${genDefaultAs} {${runtimeOptions}\n ` +
`${hasAwait ? `async ` : ``}setup(${args}) {\n${exposeCall}`
)
s.appendRight(endOffset, `}`)
Expand All @@ -1839,7 +1853,6 @@ export function compileScript(

return {
...scriptSetup,
s,
bindings: bindingMetadata,
imports: userImports,
content: s.toString(),
Expand Down
7 changes: 4 additions & 3 deletions packages/compiler-sfc/src/cssVars.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,8 @@ export function genNormalScriptCssVarsCode(
cssVars: string[],
bindings: BindingMetadata,
id: string,
isProd: boolean
isProd: boolean,
defaultVar: string
): string {
return (
`\nimport { ${CSS_VARS_HELPER} as _${CSS_VARS_HELPER} } from 'vue'\n` +
Expand All @@ -194,8 +195,8 @@ export function genNormalScriptCssVarsCode(
id,
isProd
)}}\n` +
`const __setup__ = __default__.setup\n` +
`__default__.setup = __setup__\n` +
`const __setup__ = ${defaultVar}.setup\n` +
`${defaultVar}.setup = __setup__\n` +
` ? (props, ctx) => { __injectCSSVars__();return __setup__(props, ctx) }\n` +
` : __injectCSSVars__\n`
)
Expand Down
2 changes: 2 additions & 0 deletions packages/compiler-sfc/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export const version = __VERSION__

// API
export { parse } from './parse'
export { compileTemplate } from './compileTemplate'
Expand Down
Loading

0 comments on commit 71635be

Please sign in to comment.