Skip to content

Commit 71635be

Browse files
committed
feat(compiler-sfc): support generating variable instead of default export in compileScript
1 parent 6bda4b6 commit 71635be

File tree

6 files changed

+258
-26
lines changed

6 files changed

+258
-26
lines changed

packages/compiler-sfc/__tests__/__snapshots__/compileScript.spec.ts.snap

+99
Original file line numberDiff line numberDiff line change
@@ -1963,3 +1963,102 @@ return { props }
19631963

19641964
})"
19651965
`;
1966+
1967+
exports[`SFC genDefaultAs > <script setup> only 1`] = `
1968+
"const a = 1
1969+
1970+
const _sfc_ = {
1971+
setup(__props, { expose: __expose }) {
1972+
__expose();
1973+
1974+
1975+
return { a }
1976+
}
1977+
1978+
}"
1979+
`;
1980+
1981+
exports[`SFC genDefaultAs > <script setup> only w/ ts 1`] = `
1982+
"import { defineComponent as _defineComponent } from 'vue'
1983+
const a = 1
1984+
1985+
const _sfc_ = /*#__PURE__*/_defineComponent({
1986+
setup(__props, { expose: __expose }) {
1987+
__expose();
1988+
1989+
1990+
return { a }
1991+
}
1992+
1993+
})"
1994+
`;
1995+
1996+
exports[`SFC genDefaultAs > <script> + <script setup> 1`] = `
1997+
"const __default__ = {}
1998+
1999+
const _sfc_ = /*#__PURE__*/Object.assign(__default__, {
2000+
setup(__props, { expose: __expose }) {
2001+
__expose();
2002+
2003+
const a = 1
2004+
2005+
return { a }
2006+
}
2007+
2008+
})"
2009+
`;
2010+
2011+
exports[`SFC genDefaultAs > <script> + <script setup> 2`] = `
2012+
"const __default__ = {}
2013+
2014+
const _sfc_ = /*#__PURE__*/Object.assign(__default__, {
2015+
setup(__props, { expose: __expose }) {
2016+
__expose();
2017+
2018+
const a = 1
2019+
2020+
return { a }
2021+
}
2022+
2023+
})"
2024+
`;
2025+
2026+
exports[`SFC genDefaultAs > <script> + <script setup> w/ ts 1`] = `
2027+
"import { defineComponent as _defineComponent } from 'vue'
2028+
2029+
const __default__ = {}
2030+
2031+
const _sfc_ = /*#__PURE__*/_defineComponent({
2032+
...__default__,
2033+
setup(__props, { expose: __expose }) {
2034+
__expose();
2035+
2036+
const a = 1
2037+
2038+
return { a }
2039+
}
2040+
2041+
})"
2042+
`;
2043+
2044+
exports[`SFC genDefaultAs > normal <script> only 1`] = `
2045+
"
2046+
const _sfc_ = {}
2047+
"
2048+
`;
2049+
2050+
exports[`SFC genDefaultAs > normal <script> w/ cssVars 1`] = `
2051+
"
2052+
const _sfc_ = {}
2053+
2054+
import { useCssVars as _useCssVars } from 'vue'
2055+
const __injectCSSVars__ = () => {
2056+
_useCssVars(_ctx => ({
2057+
\\"xxxxxxxx-x\\": (_ctx.x)
2058+
}))}
2059+
const __setup__ = _sfc_.setup
2060+
_sfc_.setup = __setup__
2061+
? (props, ctx) => { __injectCSSVars__();return __setup__(props, ctx) }
2062+
: __injectCSSVars__
2063+
"
2064+
`;

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

+119
Original file line numberDiff line numberDiff line change
@@ -2190,3 +2190,122 @@ describe('SFC analyze <script> bindings', () => {
21902190
})
21912191
})
21922192
})
2193+
2194+
describe('SFC genDefaultAs', () => {
2195+
test('normal <script> only', () => {
2196+
const { content } = compile(
2197+
`<script>
2198+
export default {}
2199+
</script>`,
2200+
{
2201+
genDefaultAs: '_sfc_'
2202+
}
2203+
)
2204+
expect(content).not.toMatch('export default')
2205+
expect(content).toMatch(`const _sfc_ = {}`)
2206+
assertCode(content)
2207+
})
2208+
2209+
test('normal <script> w/ cssVars', () => {
2210+
const { content } = compile(
2211+
`<script>
2212+
export default {}
2213+
</script>
2214+
<style>
2215+
.foo { color: v-bind(x) }
2216+
</style>`,
2217+
{
2218+
genDefaultAs: '_sfc_'
2219+
}
2220+
)
2221+
expect(content).not.toMatch('export default')
2222+
expect(content).not.toMatch('__default__')
2223+
expect(content).toMatch(`const _sfc_ = {}`)
2224+
assertCode(content)
2225+
})
2226+
2227+
test('<script> + <script setup>', () => {
2228+
const { content } = compile(
2229+
`<script>
2230+
export default {}
2231+
</script>
2232+
<script setup>
2233+
const a = 1
2234+
</script>`,
2235+
{
2236+
genDefaultAs: '_sfc_'
2237+
}
2238+
)
2239+
expect(content).not.toMatch('export default')
2240+
expect(content).toMatch(
2241+
`const _sfc_ = /*#__PURE__*/Object.assign(__default__`
2242+
)
2243+
assertCode(content)
2244+
})
2245+
2246+
test('<script> + <script setup>', () => {
2247+
const { content } = compile(
2248+
`<script>
2249+
export default {}
2250+
</script>
2251+
<script setup>
2252+
const a = 1
2253+
</script>`,
2254+
{
2255+
genDefaultAs: '_sfc_'
2256+
}
2257+
)
2258+
expect(content).not.toMatch('export default')
2259+
expect(content).toMatch(
2260+
`const _sfc_ = /*#__PURE__*/Object.assign(__default__`
2261+
)
2262+
assertCode(content)
2263+
})
2264+
2265+
test('<script setup> only', () => {
2266+
const { content } = compile(
2267+
`<script setup>
2268+
const a = 1
2269+
</script>`,
2270+
{
2271+
genDefaultAs: '_sfc_'
2272+
}
2273+
)
2274+
expect(content).not.toMatch('export default')
2275+
expect(content).toMatch(`const _sfc_ = {\n setup`)
2276+
assertCode(content)
2277+
})
2278+
2279+
test('<script setup> only w/ ts', () => {
2280+
const { content } = compile(
2281+
`<script setup lang="ts">
2282+
const a = 1
2283+
</script>`,
2284+
{
2285+
genDefaultAs: '_sfc_'
2286+
}
2287+
)
2288+
expect(content).not.toMatch('export default')
2289+
expect(content).toMatch(`const _sfc_ = /*#__PURE__*/_defineComponent(`)
2290+
assertCode(content)
2291+
})
2292+
2293+
test('<script> + <script setup> w/ ts', () => {
2294+
const { content } = compile(
2295+
`<script lang="ts">
2296+
export default {}
2297+
</script>
2298+
<script setup lang="ts">
2299+
const a = 1
2300+
</script>`,
2301+
{
2302+
genDefaultAs: '_sfc_'
2303+
}
2304+
)
2305+
expect(content).not.toMatch('export default')
2306+
expect(content).toMatch(
2307+
`const _sfc_ = /*#__PURE__*/_defineComponent({\n ...__default__`
2308+
)
2309+
assertCode(content)
2310+
})
2311+
})

packages/compiler-sfc/src/compileScript.ts

+34-21
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,6 @@ const DEFINE_EXPOSE = 'defineExpose'
6969
const WITH_DEFAULTS = 'withDefaults'
7070
const DEFINE_OPTIONS = 'defineOptions'
7171

72-
// constants
73-
const DEFAULT_VAR = `__default__`
74-
7572
const isBuiltInDir = makeMap(
7673
`once,memo,if,for,else,else-if,slot,text,html,on,bind,model,show,cloak,is`
7774
)
@@ -110,6 +107,12 @@ export interface SFCScriptCompileOptions {
110107
* from being hot-reloaded separately from component state.
111108
*/
112109
inlineTemplate?: boolean
110+
/**
111+
* Generate the final component as a variable instead of default export.
112+
* This is useful in e.g. @vitejs/plugin-vue where the script needs to be
113+
* placed inside the main module.
114+
*/
115+
genDefaultAs?: string
113116
/**
114117
* Options for template compilation when inlining. Note these are options that
115118
* would normally be passed to `compiler-sfc`'s own `compileTemplate()`, not
@@ -178,6 +181,10 @@ export function compileScript(
178181
const cssVars = sfc.cssVars
179182
const scriptLang = script && script.lang
180183
const scriptSetupLang = scriptSetup && scriptSetup.lang
184+
const genDefaultAs = options.genDefaultAs
185+
? `const ${options.genDefaultAs} =`
186+
: `export default`
187+
const normalScriptDefaultVar = `__default__`
181188
const isJS =
182189
scriptLang === 'js' ||
183190
scriptLang === 'jsx' ||
@@ -216,6 +223,7 @@ export function compileScript(
216223
// do not process non js/ts script blocks
217224
return script
218225
}
226+
// normal <script> only
219227
try {
220228
let content = script.content
221229
let map = script.map
@@ -247,17 +255,23 @@ export function compileScript(
247255
}) as unknown as RawSourceMap
248256
}
249257
}
250-
if (cssVars.length) {
258+
if (cssVars.length || options.genDefaultAs) {
259+
const defaultVar = options.genDefaultAs || normalScriptDefaultVar
251260
const s = new MagicString(content)
252-
rewriteDefaultAST(scriptAst.body, s, DEFAULT_VAR)
261+
rewriteDefaultAST(scriptAst.body, s, defaultVar)
253262
content = s.toString()
254-
content += genNormalScriptCssVarsCode(
255-
cssVars,
256-
bindings,
257-
scopeId,
258-
isProd
259-
)
260-
content += `\nexport default ${DEFAULT_VAR}`
263+
if (cssVars.length) {
264+
content += genNormalScriptCssVarsCode(
265+
cssVars,
266+
bindings,
267+
scopeId,
268+
isProd,
269+
defaultVar
270+
)
271+
}
272+
if (!options.genDefaultAs) {
273+
content += `\nexport default ${defaultVar}`
274+
}
261275
}
262276
return {
263277
...script,
@@ -1189,7 +1203,7 @@ export function compileScript(
11891203
// export default { ... } --> const __default__ = { ... }
11901204
const start = node.start! + scriptStartOffset!
11911205
const end = node.declaration.start! + scriptStartOffset!
1192-
s.overwrite(start, end, `const ${DEFAULT_VAR} = `)
1206+
s.overwrite(start, end, `const ${normalScriptDefaultVar} = `)
11931207
} else if (node.type === 'ExportNamedDeclaration') {
11941208
const defaultSpecifier = node.specifiers.find(
11951209
s => s.exported.type === 'Identifier' && s.exported.name === 'default'
@@ -1213,14 +1227,14 @@ export function compileScript(
12131227
// rewrite to `import { x as __default__ } from './x'` and
12141228
// add to top
12151229
s.prepend(
1216-
`import { ${defaultSpecifier.local.name} as ${DEFAULT_VAR} } from '${node.source.value}'\n`
1230+
`import { ${defaultSpecifier.local.name} as ${normalScriptDefaultVar} } from '${node.source.value}'\n`
12171231
)
12181232
} else {
12191233
// export { x as default }
12201234
// rewrite to `const __default__ = x` and move to end
12211235
s.appendLeft(
12221236
scriptEndOffset!,
1223-
`\nconst ${DEFAULT_VAR} = ${defaultSpecifier.local.name}\n`
1237+
`\nconst ${normalScriptDefaultVar} = ${defaultSpecifier.local.name}\n`
12241238
)
12251239
}
12261240
}
@@ -1793,11 +1807,11 @@ export function compileScript(
17931807
// user's TS setting should compile it down to proper targets
17941808
// export default defineComponent({ ...__default__, ... })
17951809
const def =
1796-
(defaultExport ? `\n ...${DEFAULT_VAR},` : ``) +
1810+
(defaultExport ? `\n ...${normalScriptDefaultVar},` : ``) +
17971811
(definedOptions ? `\n ...${definedOptions},` : '')
17981812
s.prependLeft(
17991813
startOffset,
1800-
`\nexport default /*#__PURE__*/${helper(
1814+
`\n${genDefaultAs} /*#__PURE__*/${helper(
18011815
`defineComponent`
18021816
)}({${def}${runtimeOptions}\n ${
18031817
hasAwait ? `async ` : ``
@@ -1810,16 +1824,16 @@ export function compileScript(
18101824
// export default Object.assign(__default__, { ... })
18111825
s.prependLeft(
18121826
startOffset,
1813-
`\nexport default /*#__PURE__*/Object.assign(${
1814-
defaultExport ? `${DEFAULT_VAR}, ` : ''
1827+
`\n${genDefaultAs} /*#__PURE__*/Object.assign(${
1828+
defaultExport ? `${normalScriptDefaultVar}, ` : ''
18151829
}${definedOptions ? `${definedOptions}, ` : ''}{${runtimeOptions}\n ` +
18161830
`${hasAwait ? `async ` : ``}setup(${args}) {\n${exposeCall}`
18171831
)
18181832
s.appendRight(endOffset, `})`)
18191833
} else {
18201834
s.prependLeft(
18211835
startOffset,
1822-
`\nexport default {${runtimeOptions}\n ` +
1836+
`\n${genDefaultAs} {${runtimeOptions}\n ` +
18231837
`${hasAwait ? `async ` : ``}setup(${args}) {\n${exposeCall}`
18241838
)
18251839
s.appendRight(endOffset, `}`)
@@ -1839,7 +1853,6 @@ export function compileScript(
18391853

18401854
return {
18411855
...scriptSetup,
1842-
s,
18431856
bindings: bindingMetadata,
18441857
imports: userImports,
18451858
content: s.toString(),

packages/compiler-sfc/src/cssVars.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,8 @@ export function genNormalScriptCssVarsCode(
184184
cssVars: string[],
185185
bindings: BindingMetadata,
186186
id: string,
187-
isProd: boolean
187+
isProd: boolean,
188+
defaultVar: string
188189
): string {
189190
return (
190191
`\nimport { ${CSS_VARS_HELPER} as _${CSS_VARS_HELPER} } from 'vue'\n` +
@@ -194,8 +195,8 @@ export function genNormalScriptCssVarsCode(
194195
id,
195196
isProd
196197
)}}\n` +
197-
`const __setup__ = __default__.setup\n` +
198-
`__default__.setup = __setup__\n` +
198+
`const __setup__ = ${defaultVar}.setup\n` +
199+
`${defaultVar}.setup = __setup__\n` +
199200
` ? (props, ctx) => { __injectCSSVars__();return __setup__(props, ctx) }\n` +
200201
` : __injectCSSVars__\n`
201202
)

packages/compiler-sfc/src/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
export const version = __VERSION__
2+
13
// API
24
export { parse } from './parse'
35
export { compileTemplate } from './compileTemplate'

0 commit comments

Comments
 (0)