diff --git a/packages/compiler-core/__tests__/__snapshots__/scopeId.spec.ts.snap b/packages/compiler-core/__tests__/__snapshots__/scopeId.spec.ts.snap
index 8d7613ee..e1408a7a 100644
--- a/packages/compiler-core/__tests__/__snapshots__/scopeId.spec.ts.snap
+++ b/packages/compiler-core/__tests__/__snapshots__/scopeId.spec.ts.snap
@@ -9,7 +9,7 @@ const _hoisted_1 = /*#__PURE__*/_createVNode(\\"div\\", null, \\"hello\\", -1 /*
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 */),
@@ -22,7 +22,7 @@ exports[`scopeId compiler support should wrap default slot 1`] = `
"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, {
@@ -38,7 +38,7 @@ exports[`scopeId compiler support should wrap dynamic slots 1`] = `
"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 }, [
@@ -66,7 +66,7 @@ exports[`scopeId compiler support should wrap named slots 1`] = `
"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, {
@@ -85,7 +85,7 @@ exports[`scopeId compiler support should wrap render function 1`] = `
"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\\"))
})"
`;
diff --git a/packages/compiler-core/__tests__/scopeId.spec.ts b/packages/compiler-core/__tests__/scopeId.spec.ts
index 4ca5a585..710c65bf 100644
--- a/packages/compiler-core/__tests__/scopeId.spec.ts
+++ b/packages/compiler-core/__tests__/scopeId.spec.ts
@@ -22,7 +22,7 @@ describe('scopeId compiler support', () => {
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()
})
diff --git a/packages/compiler-core/src/codegen.ts b/packages/compiler-core/src/codegen.ts
index a92f2597..20f7e33e 100644
--- a/packages/compiler-core/src/codegen.ts
+++ b/packages/compiler-core/src/codegen.ts
@@ -203,7 +203,7 @@ export function generate(
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
@@ -217,6 +217,8 @@ export function generate(
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
@@ -226,24 +228,18 @@ export function generate(
!__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()
diff --git a/packages/compiler-sfc/__tests__/__snapshots__/compileScript.spec.ts.snap b/packages/compiler-sfc/__tests__/__snapshots__/compileScript.spec.ts.snap
index c2407f8a..80a3bfa6 100644
--- a/packages/compiler-sfc/__tests__/__snapshots__/compileScript.spec.ts.snap
+++ b/packages/compiler-sfc/__tests__/__snapshots__/compileScript.spec.ts.snap
@@ -201,6 +201,40 @@ return (_ctx, _cache) => {
}"
`;
+exports[`SFC compile
+
+ {{ count }}
+ static
+
+
+ `,
+ {
+ 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', () => {
diff --git a/packages/compiler-sfc/__tests__/compileStyle.spec.ts b/packages/compiler-sfc/__tests__/compileStyle.spec.ts
index a1b3b21e..8e5db070 100644
--- a/packages/compiler-sfc/__tests__/compileStyle.spec.ts
+++ b/packages/compiler-sfc/__tests__/compileStyle.spec.ts
@@ -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(
diff --git a/packages/compiler-sfc/__tests__/compileTemplate.spec.ts b/packages/compiler-sfc/__tests__/compileTemplate.spec.ts
index 2a456d8e..576240b5 100644
--- a/packages/compiler-sfc/__tests__/compileTemplate.spec.ts
+++ b/packages/compiler-sfc/__tests__/compileTemplate.spec.ts
@@ -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) {
+ return compileTemplate({
+ ...opts,
+ id: ''
+ })
+}
+
test('should work', () => {
const source = ``
- 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: ``, 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: ``
@@ -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
diff --git a/packages/compiler-sfc/src/compileScript.ts b/packages/compiler-sfc/src/compileScript.ts
index f0f2b511..2e06b5fd 100644
--- a/packages/compiler-sfc/src/compileScript.ts
+++ b/packages/compiler-sfc/src/compileScript.ts
@@ -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