const _hoisted_2 = /*#__PURE__*/_createVNode(\\"div\\", null, \\"world\\", -1 /* HOISTED */)
_popScopeId()
-export const render = /*#__PURE__*/_withId(function render(_ctx, _cache) {
+export const render = /*#__PURE__*/_withId((_ctx, _cache) => {
return (_openBlock(), _createBlock(\\"div\\", null, [
_hoisted_1,
_createTextVNode(_toDisplayString(_ctx.foo), 1 /* TEXT */),
"import { createVNode as _createVNode, resolveComponent as _resolveComponent, withCtx as _withCtx, openBlock as _openBlock, createBlock as _createBlock, withScopeId as _withScopeId } from \\"vue\\"
const _withId = /*#__PURE__*/_withScopeId(\\"test\\")
-export const render = /*#__PURE__*/_withId(function render(_ctx, _cache) {
+export const render = /*#__PURE__*/_withId((_ctx, _cache) => {
const _component_Child = _resolveComponent(\\"Child\\")
return (_openBlock(), _createBlock(_component_Child, null, {
"import { createVNode as _createVNode, resolveComponent as _resolveComponent, withCtx as _withCtx, renderList as _renderList, createSlots as _createSlots, openBlock as _openBlock, createBlock as _createBlock, withScopeId as _withScopeId } from \\"vue\\"
const _withId = /*#__PURE__*/_withScopeId(\\"test\\")
-export const render = /*#__PURE__*/_withId(function render(_ctx, _cache) {
+export const render = /*#__PURE__*/_withId((_ctx, _cache) => {
const _component_Child = _resolveComponent(\\"Child\\")
return (_openBlock(), _createBlock(_component_Child, null, _createSlots({ _: 2 }, [
"import { toDisplayString as _toDisplayString, createTextVNode as _createTextVNode, createVNode as _createVNode, resolveComponent as _resolveComponent, withCtx as _withCtx, openBlock as _openBlock, createBlock as _createBlock, withScopeId as _withScopeId } from \\"vue\\"
const _withId = /*#__PURE__*/_withScopeId(\\"test\\")
-export const render = /*#__PURE__*/_withId(function render(_ctx, _cache) {
+export const render = /*#__PURE__*/_withId((_ctx, _cache) => {
const _component_Child = _resolveComponent(\\"Child\\")
return (_openBlock(), _createBlock(_component_Child, null, {
"import { createVNode as _createVNode, openBlock as _openBlock, createBlock as _createBlock, withScopeId as _withScopeId } from \\"vue\\"
const _withId = /*#__PURE__*/_withScopeId(\\"test\\")
-export const render = /*#__PURE__*/_withId(function render(_ctx, _cache) {
+export const render = /*#__PURE__*/_withId((_ctx, _cache) => {
return (_openBlock(), _createBlock(\\"div\\"))
})"
`;
expect(ast.helpers).toContain(WITH_SCOPE_ID)
expect(code).toMatch(`const _withId = /*#__PURE__*/_withScopeId("test")`)
expect(code).toMatch(
- `export const render = /*#__PURE__*/_withId(function render(`
+ `export const render = /*#__PURE__*/_withId((_ctx, _cache) => {`
)
expect(code).toMatchSnapshot()
})
const hasHelpers = ast.helpers.length > 0
const useWithBlock = !prefixIdentifiers && mode !== 'module'
const genScopeId = !__BROWSER__ && scopeId != null && mode === 'module'
- const isSetupInlined = !!options.inline
+ const isSetupInlined = !__BROWSER__ && !!options.inline
// preambles
// in setup() inline mode, the preamble is generated in a sub context
genFunctionPreamble(ast, preambleContext)
}
+ // enter render function
+ const functionName = ssr ? `ssrRender` : `render`
const args = ssr ? ['_ctx', '_push', '_parent', '_attrs'] : ['_ctx', '_cache']
if (!__BROWSER__ && options.bindingMetadata && !options.inline) {
// binding optimization args
!__BROWSER__ && options.isTS
? args.map(arg => `${arg}: any`).join(',')
: args.join(', ')
- // enter render function
- if (!ssr) {
+
+ if (genScopeId) {
if (isSetupInlined) {
- if (genScopeId) {
- push(`${PURE_ANNOTATION}_withId(`)
- }
- push(`(${signature}) => {`)
+ push(`${PURE_ANNOTATION}_withId(`)
} else {
- if (genScopeId) {
- push(`const render = ${PURE_ANNOTATION}_withId(`)
- }
- push(`function render(${signature}) {`)
+ push(`const ${functionName} = ${PURE_ANNOTATION}_withId(`)
}
+ }
+ if (isSetupInlined || genScopeId) {
+ push(`(${signature}) => {`)
} else {
- if (genScopeId) {
- push(`const ssrRender = ${PURE_ANNOTATION}_withId(`)
- }
- push(`function ssrRender(${signature}) {`)
+ push(`function ${functionName}(${signature}) {`)
}
indent()
}"
`;
+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\\"
-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>', () => {
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', () => {
const res = compileStyle({
source,
filename: 'test.css',
- id: 'test',
+ id: 'data-v-test',
scoped: true,
...options
})
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;
}"
`)
})
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;
}"
`)
})
expect(compileScoped(`@media print { .foo { color: red }}`))
.toMatchInlineSnapshot(`
"@media print {
- .foo[test] { color: red
+ .foo[data-v-test] { color: red
}}"
`)
})
expect(compileScoped(`@supports(display: grid) { .foo { display: grid }}`))
.toMatchInlineSnapshot(`
"@supports(display: grid) {
- .foo[test] { display: grid
+ .foo[data-v-test] { display: grid
}}"
`)
})
// 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;
}"
`)
})
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(
test('>>> (deprecated syntax)', () => {
const code = compileScoped(`>>> .foo { color: red; }`)
expect(code).toMatchInlineSnapshot(`
- "[test] .foo { color: red;
+ "[data-v-test] .foo { color: red;
}"
`)
expect(
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(
-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)
{ filename: 'example.vue', sourceMap: true }
).descriptor.template as SFCTemplateBlock
- const result = compileTemplate({
+ const result = compile({
filename: 'example.vue',
source: template.content,
preprocessLang: template.lang
sourceMap: true
}).descriptor.template as SFCTemplateBlock
- const result = compileTemplate({
+ const result = compile({
filename: 'example.vue',
source: template.content,
preprocessLang: template.lang
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'] }
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']
expect(code2).toMatch(`import _imports_0 from 'baz'\n`)
// false option
- const { code: code3 } = compileTemplate({
+ const { code: code3 } = compile({
...input,
transformAssetUrls: false
})
{ filename: 'example.vue', sourceMap: true }
).descriptor.template as SFCTemplateBlock
- const result = compileTemplate({
+ const result = compile({
filename: 'example.vue',
source: template.content
})
})
test('template errors', () => {
- const result = compileTemplate({
+ const result = compile({
filename: 'example.vue',
source: `<div :foo
:bar="a[" v-model="baz"/>`
{ filename: 'example.vue', sourceMap: true }
).descriptor.template as SFCTemplateBlock
- const result = compileTemplate({
+ const result = compile({
filename: 'example.vue',
source: template.content,
preprocessLang: template.lang
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`
// 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
// 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)
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 {
} = 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) {
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
export interface SFCTemplateCompileOptions {
source: string
filename: string
+ id: string
+ scoped?: boolean
+ isProd?: boolean
ssr?: boolean
+ ssrCssVars?: string[]
inMap?: RawSourceMap
compiler?: TemplateCompiler
compilerOptions?: CompilerOptions
function doCompileTemplate({
filename,
+ id,
+ scoped,
inMap,
source,
ssr = false,
+ ssrCssVars,
+ isProd = false,
compiler = ssr ? (CompilerSSR as TemplateCompiler) : CompilerDOM,
compilerOptions = {},
transformAssetUrls
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,
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}`
}
'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)})`
})
}
})
export { compileScript } from './compileScript'
export { rewriteDefault } from './rewriteDefault'
export { generateCodeFrame } from '@vue/compiler-core'
-export { generateCssVars } from './cssVars'
// Types
export {
import { ssrRenderAttrs as _ssrRenderAttrs } from \\"@vue/server-renderer\\"
const _withId = /*#__PURE__*/_withScopeId(\\"data-v-xxxxxxx\\")
- export const ssrRender = /*#__PURE__*/_withId(function ssrRender(_ctx, _push, _parent, _attrs) {
+ export const ssrRender = /*#__PURE__*/_withId((_ctx, _push, _parent, _attrs) => {
_push(\`<div\${_ssrRenderAttrs(_attrs)} data-v-xxxxxxx><span data-v-xxxxxxx>hello</span></div>\`)
})"
`)
import { ssrRenderComponent as _ssrRenderComponent } from \\"@vue/server-renderer\\"
const _withId = /*#__PURE__*/_withScopeId(\\"data-v-xxxxxxx\\")
- export const ssrRender = /*#__PURE__*/_withId(function ssrRender(_ctx, _push, _parent, _attrs) {
+ export const ssrRender = /*#__PURE__*/_withId((_ctx, _push, _parent, _attrs) => {
const _component_foo = _resolveComponent(\\"foo\\")
_push(_ssrRenderComponent(_component_foo, _attrs, {
import { ssrRenderComponent as _ssrRenderComponent } from \\"@vue/server-renderer\\"
const _withId = /*#__PURE__*/_withScopeId(\\"data-v-xxxxxxx\\")
- export const ssrRender = /*#__PURE__*/_withId(function ssrRender(_ctx, _push, _parent, _attrs) {
+ export const ssrRender = /*#__PURE__*/_withId((_ctx, _push, _parent, _attrs) => {
const _component_foo = _resolveComponent(\\"foo\\")
_push(_ssrRenderComponent(_component_foo, _attrs, {
import { ssrRenderComponent as _ssrRenderComponent } from \\"@vue/server-renderer\\"
const _withId = /*#__PURE__*/_withScopeId(\\"data-v-xxxxxxx\\")
- export const ssrRender = /*#__PURE__*/_withId(function ssrRender(_ctx, _push, _parent, _attrs) {
+ export const ssrRender = /*#__PURE__*/_withId((_ctx, _push, _parent, _attrs) => {
const _component_foo = _resolveComponent(\\"foo\\")
const _component_bar = _resolveComponent(\\"bar\\")
* @internal
*/
render: InternalRenderFunction | null
+ /**
+ * SSR render function
+ * @internal
+ */
+ ssrRender?: Function | null
/**
* Object containing values this component provides for its descendents
* @internal
) {
if (isFunction(setupResult)) {
// setup returned an inline render function
- instance.render = setupResult as InternalRenderFunction
+ if (!__BROWSER__ && (instance.type as ComponentOptions).__ssrInlineRender) {
+ // when the function's name is `ssrRender` (compiled by SFC inline mode),
+ // set it as ssrRender instead.
+ instance.ssrRender = setupResult
+ } else {
+ instance.render = setupResult as InternalRenderFunction
+ }
} else if (isObject(setupResult)) {
if (__DEV__ && isVNode(setupResult)) {
warn(
/**
* SSR only. This is produced by compiler-ssr and attached in compiler-sfc
* not user facing, so the typing is lax and for test only.
- *
* @internal
*/
ssrRender?: (
$options: ComponentInternalInstance['ctx']
) => void
+ /**
+ * Only generated by compiler-sfc to mark a ssr render function inlined and
+ * returned from setup()
+ * @internal
+ */
+ __ssrInlineRender?: boolean
+
/**
* marker for AsyncComponentWrapper
* @internal
* @private
*/
export function useCssVars(getter: (ctx: any) => Record<string, string>) {
+ if (!__BROWSER__ && !__TEST__) return
+
const instance = getCurrentInstance()
/* istanbul ignore next */
if (!instance) {
instance
)
} else {
- if (!instance.render && !comp.ssrRender && isString(comp.template)) {
+ if (
+ !instance.render &&
+ !instance.ssrRender &&
+ !comp.ssrRender &&
+ isString(comp.template)
+ ) {
comp.ssrRender = ssrCompile(comp.template, instance)
}
- if (comp.ssrRender) {
+ const ssrRender = instance.ssrRender || comp.ssrRender
+ if (ssrRender) {
// optimized
// resolve fallthrough attrs
let attrs =
// set current rendering instance for asset resolution
setCurrentRenderingInstance(instance)
- comp.ssrRender(
+ ssrRender(
instance.proxy,
push,
instance,
[
...Object.keys(pkg.dependencies || {}),
...Object.keys(pkg.peerDependencies || {}),
- ...['path', 'url'] // for @vue/compiler-sfc
+ ...['path', 'url', 'stream'] // for @vue/compiler-sfc / server-renderer
]
// the browser builds of @vue/compiler-sfc requires postcss to be available