wip: more consistent compiler-sfc usage + inline mode for ssr
This commit is contained in:
@@ -201,6 +201,40 @@ return (_ctx, _cache) => {
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`SFC compile <script setup> inlineTemplate mode ssr codegen 1`] = `
|
||||
"import { useCssVars as _useCssVars, unref as _unref } from 'vue'
|
||||
import { ssrRenderAttrs as _ssrRenderAttrs, ssrInterpolate as _ssrInterpolate } from \\"@vue/server-renderer\\"
|
||||
|
||||
import { ref } from 'vue'
|
||||
|
||||
export default {
|
||||
expose: [],
|
||||
__ssrInlineRender: true,
|
||||
setup(__props) {
|
||||
|
||||
_useCssVars(_ctx => ({
|
||||
\\"xxxxxxxx-count\\": (count.value)
|
||||
}))
|
||||
|
||||
const count = ref(0)
|
||||
|
||||
return (_ctx, _push, _parent, _attrs) => {
|
||||
const _cssVars = { style: {
|
||||
\\"xxxxxxxx-count\\": (count.value)
|
||||
}}
|
||||
_push(\`<!--[--><div\${
|
||||
_ssrRenderAttrs(_cssVars)
|
||||
}>\${
|
||||
_ssrInterpolate(count.value)
|
||||
}</div><div\${
|
||||
_ssrRenderAttrs(_cssVars)
|
||||
}>static</div><!--]-->\`)
|
||||
}
|
||||
}
|
||||
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`SFC compile <script setup> inlineTemplate mode template assignment expression codegen 1`] = `
|
||||
"import { createVNode as _createVNode, isRef as _isRef, Fragment as _Fragment, openBlock as _openBlock, createBlock as _createBlock } from \\"vue\\"
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { BindingTypes } from '@vue/compiler-dom/src'
|
||||
import { BindingTypes } from '@vue/compiler-dom'
|
||||
import { compileSFCScript as compile, assertCode } from './utils'
|
||||
|
||||
describe('SFC compile <script setup>', () => {
|
||||
@@ -297,6 +297,34 @@ const bar = 1
|
||||
expect(content).toMatch(`{ lett: lett } = val`)
|
||||
assertCode(content)
|
||||
})
|
||||
|
||||
test('ssr codegen', () => {
|
||||
const { content } = compile(
|
||||
`
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
const count = ref(0)
|
||||
</script>
|
||||
<template>
|
||||
<div>{{ count }}</div>
|
||||
<div>static</div>
|
||||
</template>
|
||||
<style>
|
||||
div { color: v-bind(count) }
|
||||
</style>
|
||||
`,
|
||||
{
|
||||
inlineTemplate: true,
|
||||
templateOptions: {
|
||||
ssr: true
|
||||
}
|
||||
}
|
||||
)
|
||||
expect(content).toMatch(`\n __ssrInlineRender: true,\n`)
|
||||
expect(content).toMatch(`return (_ctx, _push`)
|
||||
expect(content).toMatch(`ssrInterpolate`)
|
||||
assertCode(content)
|
||||
})
|
||||
})
|
||||
|
||||
describe('with TypeScript', () => {
|
||||
|
||||
@@ -16,7 +16,7 @@ export function compileScoped(
|
||||
const res = compileStyle({
|
||||
source,
|
||||
filename: 'test.css',
|
||||
id: 'test',
|
||||
id: 'data-v-test',
|
||||
scoped: true,
|
||||
...options
|
||||
})
|
||||
@@ -32,61 +32,61 @@ export function compileScoped(
|
||||
describe('SFC scoped CSS', () => {
|
||||
test('simple selectors', () => {
|
||||
expect(compileScoped(`h1 { color: red; }`)).toMatch(
|
||||
`h1[test] { color: red;`
|
||||
`h1[data-v-test] { color: red;`
|
||||
)
|
||||
expect(compileScoped(`.foo { color: red; }`)).toMatch(
|
||||
`.foo[test] { color: red;`
|
||||
`.foo[data-v-test] { color: red;`
|
||||
)
|
||||
})
|
||||
|
||||
test('descendent selector', () => {
|
||||
expect(compileScoped(`h1 .foo { color: red; }`)).toMatch(
|
||||
`h1 .foo[test] { color: red;`
|
||||
`h1 .foo[data-v-test] { color: red;`
|
||||
)
|
||||
})
|
||||
|
||||
test('multiple selectors', () => {
|
||||
expect(compileScoped(`h1 .foo, .bar, .baz { color: red; }`)).toMatch(
|
||||
`h1 .foo[test], .bar[test], .baz[test] { color: red;`
|
||||
`h1 .foo[data-v-test], .bar[data-v-test], .baz[data-v-test] { color: red;`
|
||||
)
|
||||
})
|
||||
|
||||
test('pseudo class', () => {
|
||||
expect(compileScoped(`.foo:after { color: red; }`)).toMatch(
|
||||
`.foo[test]:after { color: red;`
|
||||
`.foo[data-v-test]:after { color: red;`
|
||||
)
|
||||
})
|
||||
|
||||
test('pseudo element', () => {
|
||||
expect(compileScoped(`::selection { display: none; }`)).toMatch(
|
||||
'[test]::selection {'
|
||||
'[data-v-test]::selection {'
|
||||
)
|
||||
})
|
||||
|
||||
test('spaces before pseudo element', () => {
|
||||
const code = compileScoped(`.abc, ::selection { color: red; }`)
|
||||
expect(code).toMatch('.abc[test],')
|
||||
expect(code).toMatch('[test]::selection {')
|
||||
expect(code).toMatch('.abc[data-v-test],')
|
||||
expect(code).toMatch('[data-v-test]::selection {')
|
||||
})
|
||||
|
||||
test('::v-deep', () => {
|
||||
expect(compileScoped(`:deep(.foo) { color: red; }`)).toMatchInlineSnapshot(`
|
||||
"[test] .foo { color: red;
|
||||
"[data-v-test] .foo { color: red;
|
||||
}"
|
||||
`)
|
||||
expect(compileScoped(`::v-deep(.foo) { color: red; }`))
|
||||
.toMatchInlineSnapshot(`
|
||||
"[test] .foo { color: red;
|
||||
"[data-v-test] .foo { color: red;
|
||||
}"
|
||||
`)
|
||||
expect(compileScoped(`::v-deep(.foo .bar) { color: red; }`))
|
||||
.toMatchInlineSnapshot(`
|
||||
"[test] .foo .bar { color: red;
|
||||
"[data-v-test] .foo .bar { color: red;
|
||||
}"
|
||||
`)
|
||||
expect(compileScoped(`.baz .qux ::v-deep(.foo .bar) { color: red; }`))
|
||||
.toMatchInlineSnapshot(`
|
||||
".baz .qux[test] .foo .bar { color: red;
|
||||
".baz .qux[data-v-test] .foo .bar { color: red;
|
||||
}"
|
||||
`)
|
||||
})
|
||||
@@ -94,22 +94,22 @@ describe('SFC scoped CSS', () => {
|
||||
test('::v-slotted', () => {
|
||||
expect(compileScoped(`:slotted(.foo) { color: red; }`))
|
||||
.toMatchInlineSnapshot(`
|
||||
".foo[test-s] { color: red;
|
||||
".foo[data-v-test-s] { color: red;
|
||||
}"
|
||||
`)
|
||||
expect(compileScoped(`::v-slotted(.foo) { color: red; }`))
|
||||
.toMatchInlineSnapshot(`
|
||||
".foo[test-s] { color: red;
|
||||
".foo[data-v-test-s] { color: red;
|
||||
}"
|
||||
`)
|
||||
expect(compileScoped(`::v-slotted(.foo .bar) { color: red; }`))
|
||||
.toMatchInlineSnapshot(`
|
||||
".foo .bar[test-s] { color: red;
|
||||
".foo .bar[data-v-test-s] { color: red;
|
||||
}"
|
||||
`)
|
||||
expect(compileScoped(`.baz .qux ::v-slotted(.foo .bar) { color: red; }`))
|
||||
.toMatchInlineSnapshot(`
|
||||
".baz .qux .foo .bar[test-s] { color: red;
|
||||
".baz .qux .foo .bar[data-v-test-s] { color: red;
|
||||
}"
|
||||
`)
|
||||
})
|
||||
@@ -142,7 +142,7 @@ describe('SFC scoped CSS', () => {
|
||||
expect(compileScoped(`@media print { .foo { color: red }}`))
|
||||
.toMatchInlineSnapshot(`
|
||||
"@media print {
|
||||
.foo[test] { color: red
|
||||
.foo[data-v-test] { color: red
|
||||
}}"
|
||||
`)
|
||||
})
|
||||
@@ -151,7 +151,7 @@ describe('SFC scoped CSS', () => {
|
||||
expect(compileScoped(`@supports(display: grid) { .foo { display: grid }}`))
|
||||
.toMatchInlineSnapshot(`
|
||||
"@supports(display: grid) {
|
||||
.foo[test] { display: grid
|
||||
.foo[data-v-test] { display: grid
|
||||
}}"
|
||||
`)
|
||||
})
|
||||
@@ -222,7 +222,7 @@ describe('SFC scoped CSS', () => {
|
||||
// vue-loader/#1370
|
||||
test('spaces after selector', () => {
|
||||
expect(compileScoped(`.foo , .bar { color: red; }`)).toMatchInlineSnapshot(`
|
||||
".foo[test], .bar[test] { color: red;
|
||||
".foo[data-v-test], .bar[data-v-test] { color: red;
|
||||
}"
|
||||
`)
|
||||
})
|
||||
@@ -231,12 +231,12 @@ describe('SFC scoped CSS', () => {
|
||||
test('::v-deep as combinator', () => {
|
||||
expect(compileScoped(`::v-deep .foo { color: red; }`))
|
||||
.toMatchInlineSnapshot(`
|
||||
"[test] .foo { color: red;
|
||||
"[data-v-test] .foo { color: red;
|
||||
}"
|
||||
`)
|
||||
expect(compileScoped(`.bar ::v-deep .foo { color: red; }`))
|
||||
.toMatchInlineSnapshot(`
|
||||
".bar[test] .foo { color: red;
|
||||
".bar[data-v-test] .foo { color: red;
|
||||
}"
|
||||
`)
|
||||
expect(
|
||||
@@ -247,7 +247,7 @@ describe('SFC scoped CSS', () => {
|
||||
test('>>> (deprecated syntax)', () => {
|
||||
const code = compileScoped(`>>> .foo { color: red; }`)
|
||||
expect(code).toMatchInlineSnapshot(`
|
||||
"[test] .foo { color: red;
|
||||
"[data-v-test] .foo { color: red;
|
||||
}"
|
||||
`)
|
||||
expect(
|
||||
@@ -258,7 +258,7 @@ describe('SFC scoped CSS', () => {
|
||||
test('/deep/ (deprecated syntax)', () => {
|
||||
const code = compileScoped(`/deep/ .foo { color: red; }`)
|
||||
expect(code).toMatchInlineSnapshot(`
|
||||
"[test] .foo { color: red;
|
||||
"[data-v-test] .foo { color: red;
|
||||
}"
|
||||
`)
|
||||
expect(
|
||||
|
||||
@@ -1,10 +1,20 @@
|
||||
import { compileTemplate } from '../src/compileTemplate'
|
||||
import {
|
||||
compileTemplate,
|
||||
SFCTemplateCompileOptions
|
||||
} from '../src/compileTemplate'
|
||||
import { parse, SFCTemplateBlock } from '../src/parse'
|
||||
|
||||
function compile(opts: Omit<SFCTemplateCompileOptions, 'id'>) {
|
||||
return compileTemplate({
|
||||
...opts,
|
||||
id: ''
|
||||
})
|
||||
}
|
||||
|
||||
test('should work', () => {
|
||||
const source = `<div><p>{{ render }}</p></div>`
|
||||
|
||||
const result = compileTemplate({ filename: 'example.vue', source })
|
||||
const result = compile({ filename: 'example.vue', source })
|
||||
|
||||
expect(result.errors.length).toBe(0)
|
||||
expect(result.source).toBe(source)
|
||||
@@ -25,7 +35,7 @@ body
|
||||
{ filename: 'example.vue', sourceMap: true }
|
||||
).descriptor.template as SFCTemplateBlock
|
||||
|
||||
const result = compileTemplate({
|
||||
const result = compile({
|
||||
filename: 'example.vue',
|
||||
source: template.content,
|
||||
preprocessLang: template.lang
|
||||
@@ -40,7 +50,7 @@ test('warn missing preprocessor', () => {
|
||||
sourceMap: true
|
||||
}).descriptor.template as SFCTemplateBlock
|
||||
|
||||
const result = compileTemplate({
|
||||
const result = compile({
|
||||
filename: 'example.vue',
|
||||
source: template.content,
|
||||
preprocessLang: template.lang
|
||||
@@ -52,7 +62,7 @@ test('warn missing preprocessor', () => {
|
||||
test('transform asset url options', () => {
|
||||
const input = { source: `<foo bar="~baz"/>`, filename: 'example.vue' }
|
||||
// Object option
|
||||
const { code: code1 } = compileTemplate({
|
||||
const { code: code1 } = compile({
|
||||
...input,
|
||||
transformAssetUrls: {
|
||||
tags: { foo: ['bar'] }
|
||||
@@ -61,7 +71,7 @@ test('transform asset url options', () => {
|
||||
expect(code1).toMatch(`import _imports_0 from 'baz'\n`)
|
||||
|
||||
// legacy object option (direct tags config)
|
||||
const { code: code2 } = compileTemplate({
|
||||
const { code: code2 } = compile({
|
||||
...input,
|
||||
transformAssetUrls: {
|
||||
foo: ['bar']
|
||||
@@ -70,7 +80,7 @@ test('transform asset url options', () => {
|
||||
expect(code2).toMatch(`import _imports_0 from 'baz'\n`)
|
||||
|
||||
// false option
|
||||
const { code: code3 } = compileTemplate({
|
||||
const { code: code3 } = compile({
|
||||
...input,
|
||||
transformAssetUrls: false
|
||||
})
|
||||
@@ -87,7 +97,7 @@ test('source map', () => {
|
||||
{ filename: 'example.vue', sourceMap: true }
|
||||
).descriptor.template as SFCTemplateBlock
|
||||
|
||||
const result = compileTemplate({
|
||||
const result = compile({
|
||||
filename: 'example.vue',
|
||||
source: template.content
|
||||
})
|
||||
@@ -96,7 +106,7 @@ test('source map', () => {
|
||||
})
|
||||
|
||||
test('template errors', () => {
|
||||
const result = compileTemplate({
|
||||
const result = compile({
|
||||
filename: 'example.vue',
|
||||
source: `<div :foo
|
||||
:bar="a[" v-model="baz"/>`
|
||||
@@ -114,7 +124,7 @@ test('preprocessor errors', () => {
|
||||
{ filename: 'example.vue', sourceMap: true }
|
||||
).descriptor.template as SFCTemplateBlock
|
||||
|
||||
const result = compileTemplate({
|
||||
const result = compile({
|
||||
filename: 'example.vue',
|
||||
source: template.content,
|
||||
preprocessLang: template.lang
|
||||
|
||||
@@ -167,6 +167,7 @@ export function compileScript(
|
||||
let optionsArg: ObjectExpression | undefined
|
||||
let optionsType: TSTypeLiteral | undefined
|
||||
let hasAwait = false
|
||||
let hasInlinedSsrRenderFn = false
|
||||
// context types to generate
|
||||
let propsType = `{}`
|
||||
let emitType = `(e: string, ...args: any[]) => void`
|
||||
@@ -820,15 +821,24 @@ export function compileScript(
|
||||
// 10. generate return statement
|
||||
let returned
|
||||
if (options.inlineTemplate) {
|
||||
if (sfc.template) {
|
||||
if (sfc.template && !sfc.template.src) {
|
||||
if (options.templateOptions && options.templateOptions.ssr) {
|
||||
hasInlinedSsrRenderFn = true
|
||||
}
|
||||
// inline render function mode - we are going to compile the template and
|
||||
// inline it right here
|
||||
const { code, ast, preamble, tips, errors } = compileTemplate({
|
||||
...options.templateOptions,
|
||||
filename,
|
||||
source: sfc.template.content,
|
||||
inMap: sfc.template.map,
|
||||
...options.templateOptions,
|
||||
id: scopeId,
|
||||
scoped: sfc.styles.some(s => s.scoped),
|
||||
isProd: options.isProd,
|
||||
ssrCssVars: sfc.cssVars,
|
||||
compilerOptions: {
|
||||
...(options.templateOptions &&
|
||||
options.templateOptions.compilerOptions),
|
||||
inline: true,
|
||||
isTS,
|
||||
bindingMetadata
|
||||
@@ -883,6 +893,9 @@ export function compileScript(
|
||||
// 11. finalize default export
|
||||
// expose: [] makes <script setup> components "closed" by default.
|
||||
let runtimeOptions = `\n expose: [],`
|
||||
if (hasInlinedSsrRenderFn) {
|
||||
runtimeOptions += `\n __ssrInlineRender: true,`
|
||||
}
|
||||
if (optionsArg) {
|
||||
runtimeOptions += `\n ${scriptSetup.content
|
||||
.slice(optionsArg.start! + 1, optionsArg.end! - 1)
|
||||
|
||||
@@ -20,15 +20,19 @@ export interface SFCStyleCompileOptions {
|
||||
source: string
|
||||
filename: string
|
||||
id: string
|
||||
map?: RawSourceMap
|
||||
scoped?: boolean
|
||||
trim?: boolean
|
||||
isProd?: boolean
|
||||
inMap?: RawSourceMap
|
||||
preprocessLang?: PreprocessLang
|
||||
preprocessOptions?: any
|
||||
preprocessCustomRequire?: (id: string) => any
|
||||
postcssOptions?: any
|
||||
postcssPlugins?: any[]
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
map?: RawSourceMap
|
||||
}
|
||||
|
||||
export interface SFCAsyncStyleCompileOptions extends SFCStyleCompileOptions {
|
||||
@@ -92,16 +96,21 @@ export function doCompileStyle(
|
||||
} = options
|
||||
const preprocessor = preprocessLang && processors[preprocessLang]
|
||||
const preProcessedSource = preprocessor && preprocess(options, preprocessor)
|
||||
const map = preProcessedSource ? preProcessedSource.map : options.map
|
||||
const map = preProcessedSource
|
||||
? preProcessedSource.map
|
||||
: options.inMap || options.map
|
||||
const source = preProcessedSource ? preProcessedSource.code : options.source
|
||||
|
||||
const shortId = id.replace(/^data-v-/, '')
|
||||
const longId = `data-v-${shortId}`
|
||||
|
||||
const plugins = (postcssPlugins || []).slice()
|
||||
plugins.unshift(cssVarsPlugin({ id, isProd }))
|
||||
plugins.unshift(cssVarsPlugin({ id: shortId, isProd }))
|
||||
if (trim) {
|
||||
plugins.push(trimPlugin())
|
||||
}
|
||||
if (scoped) {
|
||||
plugins.push(scopedPlugin(id))
|
||||
plugins.push(scopedPlugin(longId))
|
||||
}
|
||||
let cssModules: Record<string, string> | undefined
|
||||
if (modules) {
|
||||
|
||||
@@ -23,6 +23,7 @@ import * as CompilerDOM from '@vue/compiler-dom'
|
||||
import * as CompilerSSR from '@vue/compiler-ssr'
|
||||
import consolidate from 'consolidate'
|
||||
import { warnOnce } from './warn'
|
||||
import { genCssVarsFromList } from './cssVars'
|
||||
|
||||
export interface TemplateCompiler {
|
||||
compile(template: string, options: CompilerOptions): CodegenResult
|
||||
@@ -42,7 +43,11 @@ export interface SFCTemplateCompileResults {
|
||||
export interface SFCTemplateCompileOptions {
|
||||
source: string
|
||||
filename: string
|
||||
id: string
|
||||
scoped?: boolean
|
||||
isProd?: boolean
|
||||
ssr?: boolean
|
||||
ssrCssVars?: string[]
|
||||
inMap?: RawSourceMap
|
||||
compiler?: TemplateCompiler
|
||||
compilerOptions?: CompilerOptions
|
||||
@@ -151,9 +156,13 @@ export function compileTemplate(
|
||||
|
||||
function doCompileTemplate({
|
||||
filename,
|
||||
id,
|
||||
scoped,
|
||||
inMap,
|
||||
source,
|
||||
ssr = false,
|
||||
ssrCssVars,
|
||||
isProd = false,
|
||||
compiler = ssr ? (CompilerSSR as TemplateCompiler) : CompilerDOM,
|
||||
compilerOptions = {},
|
||||
transformAssetUrls
|
||||
@@ -171,19 +180,30 @@ function doCompileTemplate({
|
||||
nodeTransforms = [transformAssetUrl, transformSrcset]
|
||||
}
|
||||
|
||||
if (ssr && compilerOptions.ssrCssVars == null) {
|
||||
if (ssr && !ssrCssVars) {
|
||||
warnOnce(
|
||||
`compileTemplate is called with \`ssr: true\` but no ` +
|
||||
`corresponding \`ssrCssVars\` option. The value can be generated by ` +
|
||||
`calling \`generateCssVars(sfcDescriptor, scopeId, isProduction)\`.`
|
||||
`corresponding \`cssVars\` option.\`.`
|
||||
)
|
||||
}
|
||||
if (!id) {
|
||||
warnOnce(`compileTemplate now requires the \`id\` option.\`.`)
|
||||
id = ''
|
||||
}
|
||||
|
||||
const shortId = id.replace(/^data-v-/, '')
|
||||
const longId = `data-v-${shortId}`
|
||||
|
||||
let { code, ast, preamble, map } = compiler.compile(source, {
|
||||
mode: 'module',
|
||||
prefixIdentifiers: true,
|
||||
hoistStatic: true,
|
||||
cacheHandlers: true,
|
||||
ssrCssVars:
|
||||
ssr && ssrCssVars && ssrCssVars.length
|
||||
? genCssVarsFromList(ssrCssVars, shortId, isProd)
|
||||
: '',
|
||||
scopeId: scoped ? longId : undefined,
|
||||
...compilerOptions,
|
||||
nodeTransforms: nodeTransforms.concat(compilerOptions.nodeTransforms || []),
|
||||
filename,
|
||||
|
||||
@@ -16,26 +16,13 @@ import hash from 'hash-sum'
|
||||
export const CSS_VARS_HELPER = `useCssVars`
|
||||
export const cssVarRE = /\bv-bind\(\s*(?:'([^']+)'|"([^"]+)"|([^'"][^)]*))\s*\)/g
|
||||
|
||||
/**
|
||||
* Given an SFC descriptor, generate the CSS variables object string that can be
|
||||
* passed to `compileTemplate` as `compilerOptions.ssrCssVars`.
|
||||
* @public
|
||||
*/
|
||||
export function generateCssVars(
|
||||
sfc: SFCDescriptor,
|
||||
id: string,
|
||||
isProd: boolean
|
||||
): string {
|
||||
return sfc.cssVars.length ? genCssVarsFromList(sfc.cssVars, id, isProd) : ''
|
||||
}
|
||||
|
||||
function genCssVarsFromList(
|
||||
export function genCssVarsFromList(
|
||||
vars: string[],
|
||||
id: string,
|
||||
isProd: boolean
|
||||
): string {
|
||||
return `{\n ${vars
|
||||
.map(v => `"${genVarName(id, v, isProd)}": (${v})`)
|
||||
.map(key => `"${genVarName(id, key, isProd)}": (${key})`)
|
||||
.join(',\n ')}\n}`
|
||||
}
|
||||
|
||||
@@ -68,12 +55,11 @@ export const cssVarsPlugin = postcss.plugin<CssVarsPluginOptions>(
|
||||
'vue-scoped',
|
||||
opts => (root: Root) => {
|
||||
const { id, isProd } = opts!
|
||||
const shortId = id.replace(/^data-v-/, '')
|
||||
root.walkDecls(decl => {
|
||||
// rewrite CSS variables
|
||||
if (cssVarRE.test(decl.value)) {
|
||||
decl.value = decl.value.replace(cssVarRE, (_, $1, $2, $3) => {
|
||||
return `var(--${genVarName(shortId, $1 || $2 || $3, isProd)})`
|
||||
return `var(--${genVarName(id, $1 || $2 || $3, isProd)})`
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
@@ -5,7 +5,6 @@ export { compileStyle, compileStyleAsync } from './compileStyle'
|
||||
export { compileScript } from './compileScript'
|
||||
export { rewriteDefault } from './rewriteDefault'
|
||||
export { generateCodeFrame } from '@vue/compiler-core'
|
||||
export { generateCssVars } from './cssVars'
|
||||
|
||||
// Types
|
||||
export {
|
||||
|
||||
Reference in New Issue
Block a user