parent
cc975c1292
commit
aea88c3280
@ -1,51 +1,48 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`scopeId compiler support should push scopeId for hoisted nodes 1`] = `
|
exports[`scopeId compiler support should push scopeId for hoisted nodes 1`] = `
|
||||||
"import { createVNode as _createVNode, toDisplayString as _toDisplayString, createTextVNode as _createTextVNode, openBlock as _openBlock, createBlock as _createBlock, withScopeId as _withScopeId, pushScopeId as _pushScopeId, popScopeId as _popScopeId } from \\"vue\\"
|
"import { createVNode as _createVNode, toDisplayString as _toDisplayString, createTextVNode as _createTextVNode, openBlock as _openBlock, createBlock as _createBlock, setScopeId as _setScopeId } from \\"vue\\"
|
||||||
const _withId = /*#__PURE__*/_withScopeId(\\"test\\")
|
|
||||||
|
|
||||||
_pushScopeId(\\"test\\")
|
_setScopeId(\\"test\\")
|
||||||
const _hoisted_1 = /*#__PURE__*/_createVNode(\\"div\\", null, \\"hello\\", -1 /* HOISTED */)
|
const _hoisted_1 = /*#__PURE__*/_createVNode(\\"div\\", null, \\"hello\\", -1 /* HOISTED */)
|
||||||
const _hoisted_2 = /*#__PURE__*/_createVNode(\\"div\\", null, \\"world\\", -1 /* HOISTED */)
|
const _hoisted_2 = /*#__PURE__*/_createVNode(\\"div\\", null, \\"world\\", -1 /* HOISTED */)
|
||||||
_popScopeId()
|
_setScopeId(null)
|
||||||
|
|
||||||
export const render = /*#__PURE__*/_withId((_ctx, _cache) => {
|
export function render(_ctx, _cache) {
|
||||||
return (_openBlock(), _createBlock(\\"div\\", null, [
|
return (_openBlock(), _createBlock(\\"div\\", null, [
|
||||||
_hoisted_1,
|
_hoisted_1,
|
||||||
_createTextVNode(_toDisplayString(_ctx.foo), 1 /* TEXT */),
|
_createTextVNode(_toDisplayString(_ctx.foo), 1 /* TEXT */),
|
||||||
_hoisted_2
|
_hoisted_2
|
||||||
]))
|
]))
|
||||||
})"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`scopeId compiler support should wrap default slot 1`] = `
|
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\\"
|
"import { createVNode as _createVNode, resolveComponent as _resolveComponent, withCtx as _withCtx, openBlock as _openBlock, createBlock as _createBlock } from \\"vue\\"
|
||||||
const _withId = /*#__PURE__*/_withScopeId(\\"test\\")
|
|
||||||
|
|
||||||
export const render = /*#__PURE__*/_withId((_ctx, _cache) => {
|
export function render(_ctx, _cache) {
|
||||||
const _component_Child = _resolveComponent(\\"Child\\")
|
const _component_Child = _resolveComponent(\\"Child\\")
|
||||||
|
|
||||||
return (_openBlock(), _createBlock(_component_Child, null, {
|
return (_openBlock(), _createBlock(_component_Child, null, {
|
||||||
default: _withId(() => [
|
default: _withCtx(() => [
|
||||||
_createVNode(\\"div\\")
|
_createVNode(\\"div\\")
|
||||||
]),
|
]),
|
||||||
_: 1 /* STABLE */
|
_: 1 /* STABLE */
|
||||||
}))
|
}))
|
||||||
})"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`scopeId compiler support should wrap dynamic slots 1`] = `
|
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\\"
|
"import { createVNode as _createVNode, resolveComponent as _resolveComponent, withCtx as _withCtx, renderList as _renderList, createSlots as _createSlots, openBlock as _openBlock, createBlock as _createBlock } from \\"vue\\"
|
||||||
const _withId = /*#__PURE__*/_withScopeId(\\"test\\")
|
|
||||||
|
|
||||||
export const render = /*#__PURE__*/_withId((_ctx, _cache) => {
|
export function render(_ctx, _cache) {
|
||||||
const _component_Child = _resolveComponent(\\"Child\\")
|
const _component_Child = _resolveComponent(\\"Child\\")
|
||||||
|
|
||||||
return (_openBlock(), _createBlock(_component_Child, null, _createSlots({ _: 2 /* DYNAMIC */ }, [
|
return (_openBlock(), _createBlock(_component_Child, null, _createSlots({ _: 2 /* DYNAMIC */ }, [
|
||||||
(_ctx.ok)
|
(_ctx.ok)
|
||||||
? {
|
? {
|
||||||
name: \\"foo\\",
|
name: \\"foo\\",
|
||||||
fn: _withId(() => [
|
fn: _withCtx(() => [
|
||||||
_createVNode(\\"div\\")
|
_createVNode(\\"div\\")
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
@ -53,39 +50,29 @@ export const render = /*#__PURE__*/_withId((_ctx, _cache) => {
|
|||||||
_renderList(_ctx.list, (i) => {
|
_renderList(_ctx.list, (i) => {
|
||||||
return {
|
return {
|
||||||
name: i,
|
name: i,
|
||||||
fn: _withId(() => [
|
fn: _withCtx(() => [
|
||||||
_createVNode(\\"div\\")
|
_createVNode(\\"div\\")
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
]), 1024 /* DYNAMIC_SLOTS */))
|
]), 1024 /* DYNAMIC_SLOTS */))
|
||||||
})"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`scopeId compiler support should wrap named slots 1`] = `
|
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\\"
|
"import { toDisplayString as _toDisplayString, createTextVNode as _createTextVNode, createVNode as _createVNode, resolveComponent as _resolveComponent, withCtx as _withCtx, openBlock as _openBlock, createBlock as _createBlock } from \\"vue\\"
|
||||||
const _withId = /*#__PURE__*/_withScopeId(\\"test\\")
|
|
||||||
|
|
||||||
export const render = /*#__PURE__*/_withId((_ctx, _cache) => {
|
export function render(_ctx, _cache) {
|
||||||
const _component_Child = _resolveComponent(\\"Child\\")
|
const _component_Child = _resolveComponent(\\"Child\\")
|
||||||
|
|
||||||
return (_openBlock(), _createBlock(_component_Child, null, {
|
return (_openBlock(), _createBlock(_component_Child, null, {
|
||||||
foo: _withId(({ msg }) => [
|
foo: _withCtx(({ msg }) => [
|
||||||
_createTextVNode(_toDisplayString(msg), 1 /* TEXT */)
|
_createTextVNode(_toDisplayString(msg), 1 /* TEXT */)
|
||||||
]),
|
]),
|
||||||
bar: _withId(() => [
|
bar: _withCtx(() => [
|
||||||
_createVNode(\\"div\\")
|
_createVNode(\\"div\\")
|
||||||
]),
|
]),
|
||||||
_: 1 /* STABLE */
|
_: 1 /* STABLE */
|
||||||
}))
|
}))
|
||||||
})"
|
}"
|
||||||
`;
|
|
||||||
|
|
||||||
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((_ctx, _cache) => {
|
|
||||||
return (_openBlock(), _createBlock(\\"div\\"))
|
|
||||||
})"
|
|
||||||
`;
|
`;
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
import { baseCompile } from '../src/compile'
|
import { baseCompile } from '../src/compile'
|
||||||
import {
|
import { SET_SCOPE_ID } from '../src/runtimeHelpers'
|
||||||
WITH_SCOPE_ID,
|
|
||||||
PUSH_SCOPE_ID,
|
|
||||||
POP_SCOPE_ID
|
|
||||||
} from '../src/runtimeHelpers'
|
|
||||||
import { PatchFlags } from '@vue/shared'
|
import { PatchFlags } from '@vue/shared'
|
||||||
import { genFlagText } from './testUtils'
|
import { genFlagText } from './testUtils'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensure all slot functions are wrapped with _withCtx
|
||||||
|
* which sets the currentRenderingInstance and currentScopeId when rendering
|
||||||
|
* the slot.
|
||||||
|
*/
|
||||||
describe('scopeId compiler support', () => {
|
describe('scopeId compiler support', () => {
|
||||||
test('should only work in module mode', () => {
|
test('should only work in module mode', () => {
|
||||||
expect(() => {
|
expect(() => {
|
||||||
@ -14,25 +15,12 @@ describe('scopeId compiler support', () => {
|
|||||||
}).toThrow(`"scopeId" option is only supported in module mode`)
|
}).toThrow(`"scopeId" option is only supported in module mode`)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('should wrap render function', () => {
|
|
||||||
const { ast, code } = baseCompile(`<div/>`, {
|
|
||||||
mode: 'module',
|
|
||||||
scopeId: 'test'
|
|
||||||
})
|
|
||||||
expect(ast.helpers).toContain(WITH_SCOPE_ID)
|
|
||||||
expect(code).toMatch(`const _withId = /*#__PURE__*/_withScopeId("test")`)
|
|
||||||
expect(code).toMatch(
|
|
||||||
`export const render = /*#__PURE__*/_withId((_ctx, _cache) => {`
|
|
||||||
)
|
|
||||||
expect(code).toMatchSnapshot()
|
|
||||||
})
|
|
||||||
|
|
||||||
test('should wrap default slot', () => {
|
test('should wrap default slot', () => {
|
||||||
const { code } = baseCompile(`<Child><div/></Child>`, {
|
const { code } = baseCompile(`<Child><div/></Child>`, {
|
||||||
mode: 'module',
|
mode: 'module',
|
||||||
scopeId: 'test'
|
scopeId: 'test'
|
||||||
})
|
})
|
||||||
expect(code).toMatch(`default: _withId(() => [`)
|
expect(code).toMatch(`default: _withCtx(() => [`)
|
||||||
expect(code).toMatchSnapshot()
|
expect(code).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -48,8 +36,8 @@ describe('scopeId compiler support', () => {
|
|||||||
scopeId: 'test'
|
scopeId: 'test'
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
expect(code).toMatch(`foo: _withId(({ msg }) => [`)
|
expect(code).toMatch(`foo: _withCtx(({ msg }) => [`)
|
||||||
expect(code).toMatch(`bar: _withId(() => [`)
|
expect(code).toMatch(`bar: _withCtx(() => [`)
|
||||||
expect(code).toMatchSnapshot()
|
expect(code).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -65,8 +53,8 @@ describe('scopeId compiler support', () => {
|
|||||||
scopeId: 'test'
|
scopeId: 'test'
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
expect(code).toMatch(/name: "foo",\s+fn: _withId\(/)
|
expect(code).toMatch(/name: "foo",\s+fn: _withCtx\(/)
|
||||||
expect(code).toMatch(/name: i,\s+fn: _withId\(/)
|
expect(code).toMatch(/name: i,\s+fn: _withCtx\(/)
|
||||||
expect(code).toMatchSnapshot()
|
expect(code).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -79,19 +67,18 @@ describe('scopeId compiler support', () => {
|
|||||||
hoistStatic: true
|
hoistStatic: true
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
expect(ast.helpers).toContain(PUSH_SCOPE_ID)
|
expect(ast.helpers).toContain(SET_SCOPE_ID)
|
||||||
expect(ast.helpers).toContain(POP_SCOPE_ID)
|
|
||||||
expect(ast.hoists.length).toBe(2)
|
expect(ast.hoists.length).toBe(2)
|
||||||
expect(code).toMatch(
|
expect(code).toMatch(
|
||||||
[
|
[
|
||||||
`_pushScopeId("test")`,
|
`_setScopeId("test")`,
|
||||||
`const _hoisted_1 = /*#__PURE__*/_createVNode("div", null, "hello", ${genFlagText(
|
`const _hoisted_1 = /*#__PURE__*/_createVNode("div", null, "hello", ${genFlagText(
|
||||||
PatchFlags.HOISTED
|
PatchFlags.HOISTED
|
||||||
)})`,
|
)})`,
|
||||||
`const _hoisted_2 = /*#__PURE__*/_createVNode("div", null, "world", ${genFlagText(
|
`const _hoisted_2 = /*#__PURE__*/_createVNode("div", null, "world", ${genFlagText(
|
||||||
PatchFlags.HOISTED
|
PatchFlags.HOISTED
|
||||||
)})`,
|
)})`,
|
||||||
`_popScopeId()`
|
`_setScopeId(null)`
|
||||||
].join('\n')
|
].join('\n')
|
||||||
)
|
)
|
||||||
expect(code).toMatchSnapshot()
|
expect(code).toMatchSnapshot()
|
||||||
|
@ -43,9 +43,7 @@ import {
|
|||||||
SET_BLOCK_TRACKING,
|
SET_BLOCK_TRACKING,
|
||||||
CREATE_COMMENT,
|
CREATE_COMMENT,
|
||||||
CREATE_TEXT,
|
CREATE_TEXT,
|
||||||
PUSH_SCOPE_ID,
|
SET_SCOPE_ID,
|
||||||
POP_SCOPE_ID,
|
|
||||||
WITH_SCOPE_ID,
|
|
||||||
WITH_DIRECTIVES,
|
WITH_DIRECTIVES,
|
||||||
CREATE_BLOCK,
|
CREATE_BLOCK,
|
||||||
OPEN_BLOCK,
|
OPEN_BLOCK,
|
||||||
@ -197,12 +195,11 @@ export function generate(
|
|||||||
indent,
|
indent,
|
||||||
deindent,
|
deindent,
|
||||||
newline,
|
newline,
|
||||||
scopeId,
|
|
||||||
ssr
|
ssr
|
||||||
} = context
|
} = context
|
||||||
|
|
||||||
const hasHelpers = ast.helpers.length > 0
|
const hasHelpers = ast.helpers.length > 0
|
||||||
const useWithBlock = !prefixIdentifiers && mode !== 'module'
|
const useWithBlock = !prefixIdentifiers && mode !== 'module'
|
||||||
const genScopeId = !__BROWSER__ && scopeId != null && mode === 'module'
|
|
||||||
const isSetupInlined = !__BROWSER__ && !!options.inline
|
const isSetupInlined = !__BROWSER__ && !!options.inline
|
||||||
|
|
||||||
// preambles
|
// preambles
|
||||||
@ -212,7 +209,7 @@ export function generate(
|
|||||||
? createCodegenContext(ast, options)
|
? createCodegenContext(ast, options)
|
||||||
: context
|
: context
|
||||||
if (!__BROWSER__ && mode === 'module') {
|
if (!__BROWSER__ && mode === 'module') {
|
||||||
genModulePreamble(ast, preambleContext, genScopeId, isSetupInlined)
|
genModulePreamble(ast, preambleContext, isSetupInlined)
|
||||||
} else {
|
} else {
|
||||||
genFunctionPreamble(ast, preambleContext)
|
genFunctionPreamble(ast, preambleContext)
|
||||||
}
|
}
|
||||||
@ -229,14 +226,7 @@ export function generate(
|
|||||||
? args.map(arg => `${arg}: any`).join(',')
|
? args.map(arg => `${arg}: any`).join(',')
|
||||||
: args.join(', ')
|
: args.join(', ')
|
||||||
|
|
||||||
if (genScopeId) {
|
if (isSetupInlined) {
|
||||||
if (isSetupInlined) {
|
|
||||||
push(`${PURE_ANNOTATION}_withId(`)
|
|
||||||
} else {
|
|
||||||
push(`const ${functionName} = ${PURE_ANNOTATION}_withId(`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (isSetupInlined || genScopeId) {
|
|
||||||
push(`(${signature}) => {`)
|
push(`(${signature}) => {`)
|
||||||
} else {
|
} else {
|
||||||
push(`function ${functionName}(${signature}) {`)
|
push(`function ${functionName}(${signature}) {`)
|
||||||
@ -301,10 +291,6 @@ export function generate(
|
|||||||
deindent()
|
deindent()
|
||||||
push(`}`)
|
push(`}`)
|
||||||
|
|
||||||
if (genScopeId) {
|
|
||||||
push(`)`)
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
ast,
|
ast,
|
||||||
code: context.code,
|
code: context.code,
|
||||||
@ -375,23 +361,20 @@ function genFunctionPreamble(ast: RootNode, context: CodegenContext) {
|
|||||||
function genModulePreamble(
|
function genModulePreamble(
|
||||||
ast: RootNode,
|
ast: RootNode,
|
||||||
context: CodegenContext,
|
context: CodegenContext,
|
||||||
genScopeId: boolean,
|
|
||||||
inline?: boolean
|
inline?: boolean
|
||||||
) {
|
) {
|
||||||
const {
|
const {
|
||||||
push,
|
push,
|
||||||
helper,
|
|
||||||
newline,
|
newline,
|
||||||
scopeId,
|
|
||||||
optimizeImports,
|
optimizeImports,
|
||||||
runtimeModuleName
|
runtimeModuleName,
|
||||||
|
scopeId,
|
||||||
|
mode
|
||||||
} = context
|
} = context
|
||||||
|
|
||||||
if (genScopeId) {
|
const genScopeId = !__BROWSER__ && scopeId != null && mode === 'module'
|
||||||
ast.helpers.push(WITH_SCOPE_ID)
|
if (genScopeId && ast.hoists.length) {
|
||||||
if (ast.hoists.length) {
|
ast.helpers.push(SET_SCOPE_ID)
|
||||||
ast.helpers.push(PUSH_SCOPE_ID, POP_SCOPE_ID)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// generate import statements for helpers
|
// generate import statements for helpers
|
||||||
@ -434,13 +417,6 @@ function genModulePreamble(
|
|||||||
newline()
|
newline()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (genScopeId) {
|
|
||||||
push(
|
|
||||||
`const _withId = ${PURE_ANNOTATION}${helper(WITH_SCOPE_ID)}("${scopeId}")`
|
|
||||||
)
|
|
||||||
newline()
|
|
||||||
}
|
|
||||||
|
|
||||||
genHoists(ast.hoists, context)
|
genHoists(ast.hoists, context)
|
||||||
newline()
|
newline()
|
||||||
|
|
||||||
@ -480,7 +456,7 @@ function genHoists(hoists: (JSChildNode | null)[], context: CodegenContext) {
|
|||||||
// push scope Id before initializing hoisted vnodes so that these vnodes
|
// push scope Id before initializing hoisted vnodes so that these vnodes
|
||||||
// get the proper scopeId as well.
|
// get the proper scopeId as well.
|
||||||
if (genScopeId) {
|
if (genScopeId) {
|
||||||
push(`${helper(PUSH_SCOPE_ID)}("${scopeId}")`)
|
push(`${helper(SET_SCOPE_ID)}("${scopeId}")`)
|
||||||
newline()
|
newline()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -493,7 +469,7 @@ function genHoists(hoists: (JSChildNode | null)[], context: CodegenContext) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
if (genScopeId) {
|
if (genScopeId) {
|
||||||
push(`${helper(POP_SCOPE_ID)}()`)
|
push(`${helper(SET_SCOPE_ID)}(null)`)
|
||||||
newline()
|
newline()
|
||||||
}
|
}
|
||||||
context.pure = false
|
context.pure = false
|
||||||
@ -817,15 +793,11 @@ function genFunctionExpression(
|
|||||||
node: FunctionExpression,
|
node: FunctionExpression,
|
||||||
context: CodegenContext
|
context: CodegenContext
|
||||||
) {
|
) {
|
||||||
const { push, indent, deindent, scopeId, mode } = context
|
const { push, indent, deindent } = context
|
||||||
const { params, returns, body, newline, isSlot } = node
|
const { params, returns, body, newline, isSlot } = node
|
||||||
// slot functions also need to push scopeId before rendering its content
|
|
||||||
const genScopeId =
|
|
||||||
!__BROWSER__ && isSlot && scopeId != null && mode !== 'function'
|
|
||||||
|
|
||||||
if (genScopeId) {
|
if (isSlot) {
|
||||||
push(`_withId(`)
|
// wrap slot functions with owner context
|
||||||
} else if (isSlot) {
|
|
||||||
push(`_${helperNameMap[WITH_CTX]}(`)
|
push(`_${helperNameMap[WITH_CTX]}(`)
|
||||||
}
|
}
|
||||||
push(`(`, node)
|
push(`(`, node)
|
||||||
@ -855,7 +827,7 @@ function genFunctionExpression(
|
|||||||
deindent()
|
deindent()
|
||||||
push(`}`)
|
push(`}`)
|
||||||
}
|
}
|
||||||
if (genScopeId || isSlot) {
|
if (isSlot) {
|
||||||
push(`)`)
|
push(`)`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,9 +25,7 @@ export const CAMELIZE = Symbol(__DEV__ ? `camelize` : ``)
|
|||||||
export const CAPITALIZE = Symbol(__DEV__ ? `capitalize` : ``)
|
export const CAPITALIZE = Symbol(__DEV__ ? `capitalize` : ``)
|
||||||
export const TO_HANDLER_KEY = Symbol(__DEV__ ? `toHandlerKey` : ``)
|
export const TO_HANDLER_KEY = Symbol(__DEV__ ? `toHandlerKey` : ``)
|
||||||
export const SET_BLOCK_TRACKING = Symbol(__DEV__ ? `setBlockTracking` : ``)
|
export const SET_BLOCK_TRACKING = Symbol(__DEV__ ? `setBlockTracking` : ``)
|
||||||
export const PUSH_SCOPE_ID = Symbol(__DEV__ ? `pushScopeId` : ``)
|
export const SET_SCOPE_ID = Symbol(__DEV__ ? `setScopeId` : ``)
|
||||||
export const POP_SCOPE_ID = Symbol(__DEV__ ? `popScopeId` : ``)
|
|
||||||
export const WITH_SCOPE_ID = Symbol(__DEV__ ? `withScopeId` : ``)
|
|
||||||
export const WITH_CTX = Symbol(__DEV__ ? `withCtx` : ``)
|
export const WITH_CTX = Symbol(__DEV__ ? `withCtx` : ``)
|
||||||
export const UNREF = Symbol(__DEV__ ? `unref` : ``)
|
export const UNREF = Symbol(__DEV__ ? `unref` : ``)
|
||||||
export const IS_REF = Symbol(__DEV__ ? `isRef` : ``)
|
export const IS_REF = Symbol(__DEV__ ? `isRef` : ``)
|
||||||
@ -61,9 +59,7 @@ export const helperNameMap: any = {
|
|||||||
[CAPITALIZE]: `capitalize`,
|
[CAPITALIZE]: `capitalize`,
|
||||||
[TO_HANDLER_KEY]: `toHandlerKey`,
|
[TO_HANDLER_KEY]: `toHandlerKey`,
|
||||||
[SET_BLOCK_TRACKING]: `setBlockTracking`,
|
[SET_BLOCK_TRACKING]: `setBlockTracking`,
|
||||||
[PUSH_SCOPE_ID]: `pushScopeId`,
|
[SET_SCOPE_ID]: `setScopeId`,
|
||||||
[POP_SCOPE_ID]: `popScopeId`,
|
|
||||||
[WITH_SCOPE_ID]: `withScopeId`,
|
|
||||||
[WITH_CTX]: `withCtx`,
|
[WITH_CTX]: `withCtx`,
|
||||||
[UNREF]: `unref`,
|
[UNREF]: `unref`,
|
||||||
[IS_REF]: `isRef`
|
[IS_REF]: `isRef`
|
||||||
|
@ -10,13 +10,11 @@ describe('ssr: scopeId', () => {
|
|||||||
mode: 'module'
|
mode: 'module'
|
||||||
}).code
|
}).code
|
||||||
).toMatchInlineSnapshot(`
|
).toMatchInlineSnapshot(`
|
||||||
"import { withScopeId as _withScopeId } from \\"vue\\"
|
"import { ssrRenderAttrs as _ssrRenderAttrs } from \\"@vue/server-renderer\\"
|
||||||
import { ssrRenderAttrs as _ssrRenderAttrs } from \\"@vue/server-renderer\\"
|
|
||||||
const _withId = /*#__PURE__*/_withScopeId(\\"data-v-xxxxxxx\\")
|
|
||||||
|
|
||||||
export const ssrRender = /*#__PURE__*/_withId((_ctx, _push, _parent, _attrs) => {
|
export function ssrRender(_ctx, _push, _parent, _attrs) {
|
||||||
_push(\`<div\${_ssrRenderAttrs(_attrs)} data-v-xxxxxxx><span data-v-xxxxxxx>hello</span></div>\`)
|
_push(\`<div\${_ssrRenderAttrs(_attrs)} data-v-xxxxxxx><span data-v-xxxxxxx>hello</span></div>\`)
|
||||||
})"
|
}"
|
||||||
`)
|
`)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -28,15 +26,14 @@ describe('ssr: scopeId', () => {
|
|||||||
mode: 'module'
|
mode: 'module'
|
||||||
}).code
|
}).code
|
||||||
).toMatchInlineSnapshot(`
|
).toMatchInlineSnapshot(`
|
||||||
"import { resolveComponent as _resolveComponent, withCtx as _withCtx, createTextVNode as _createTextVNode, withScopeId as _withScopeId } from \\"vue\\"
|
"import { resolveComponent as _resolveComponent, withCtx as _withCtx, createTextVNode as _createTextVNode } from \\"vue\\"
|
||||||
import { ssrRenderComponent as _ssrRenderComponent } from \\"@vue/server-renderer\\"
|
import { ssrRenderComponent as _ssrRenderComponent } from \\"@vue/server-renderer\\"
|
||||||
const _withId = /*#__PURE__*/_withScopeId(\\"data-v-xxxxxxx\\")
|
|
||||||
|
|
||||||
export const ssrRender = /*#__PURE__*/_withId((_ctx, _push, _parent, _attrs) => {
|
export function ssrRender(_ctx, _push, _parent, _attrs) {
|
||||||
const _component_foo = _resolveComponent(\\"foo\\")
|
const _component_foo = _resolveComponent(\\"foo\\")
|
||||||
|
|
||||||
_push(_ssrRenderComponent(_component_foo, _attrs, {
|
_push(_ssrRenderComponent(_component_foo, _attrs, {
|
||||||
default: _withId((_, _push, _parent, _scopeId) => {
|
default: _withCtx((_, _push, _parent, _scopeId) => {
|
||||||
if (_push) {
|
if (_push) {
|
||||||
_push(\`foo\`)
|
_push(\`foo\`)
|
||||||
} else {
|
} else {
|
||||||
@ -47,7 +44,7 @@ describe('ssr: scopeId', () => {
|
|||||||
}),
|
}),
|
||||||
_: 1 /* STABLE */
|
_: 1 /* STABLE */
|
||||||
}, _parent))
|
}, _parent))
|
||||||
})"
|
}"
|
||||||
`)
|
`)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -58,15 +55,14 @@ describe('ssr: scopeId', () => {
|
|||||||
mode: 'module'
|
mode: 'module'
|
||||||
}).code
|
}).code
|
||||||
).toMatchInlineSnapshot(`
|
).toMatchInlineSnapshot(`
|
||||||
"import { resolveComponent as _resolveComponent, withCtx as _withCtx, createVNode as _createVNode, withScopeId as _withScopeId } from \\"vue\\"
|
"import { resolveComponent as _resolveComponent, withCtx as _withCtx, createVNode as _createVNode } from \\"vue\\"
|
||||||
import { ssrRenderComponent as _ssrRenderComponent } from \\"@vue/server-renderer\\"
|
import { ssrRenderComponent as _ssrRenderComponent } from \\"@vue/server-renderer\\"
|
||||||
const _withId = /*#__PURE__*/_withScopeId(\\"data-v-xxxxxxx\\")
|
|
||||||
|
|
||||||
export const ssrRender = /*#__PURE__*/_withId((_ctx, _push, _parent, _attrs) => {
|
export function ssrRender(_ctx, _push, _parent, _attrs) {
|
||||||
const _component_foo = _resolveComponent(\\"foo\\")
|
const _component_foo = _resolveComponent(\\"foo\\")
|
||||||
|
|
||||||
_push(_ssrRenderComponent(_component_foo, _attrs, {
|
_push(_ssrRenderComponent(_component_foo, _attrs, {
|
||||||
default: _withId((_, _push, _parent, _scopeId) => {
|
default: _withCtx((_, _push, _parent, _scopeId) => {
|
||||||
if (_push) {
|
if (_push) {
|
||||||
_push(\`<span data-v-xxxxxxx\${_scopeId}>hello</span>\`)
|
_push(\`<span data-v-xxxxxxx\${_scopeId}>hello</span>\`)
|
||||||
} else {
|
} else {
|
||||||
@ -77,7 +73,7 @@ describe('ssr: scopeId', () => {
|
|||||||
}),
|
}),
|
||||||
_: 1 /* STABLE */
|
_: 1 /* STABLE */
|
||||||
}, _parent))
|
}, _parent))
|
||||||
})"
|
}"
|
||||||
`)
|
`)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -88,20 +84,19 @@ describe('ssr: scopeId', () => {
|
|||||||
mode: 'module'
|
mode: 'module'
|
||||||
}).code
|
}).code
|
||||||
).toMatchInlineSnapshot(`
|
).toMatchInlineSnapshot(`
|
||||||
"import { resolveComponent as _resolveComponent, withCtx as _withCtx, createVNode as _createVNode, withScopeId as _withScopeId } from \\"vue\\"
|
"import { resolveComponent as _resolveComponent, withCtx as _withCtx, createVNode as _createVNode } from \\"vue\\"
|
||||||
import { ssrRenderComponent as _ssrRenderComponent } from \\"@vue/server-renderer\\"
|
import { ssrRenderComponent as _ssrRenderComponent } from \\"@vue/server-renderer\\"
|
||||||
const _withId = /*#__PURE__*/_withScopeId(\\"data-v-xxxxxxx\\")
|
|
||||||
|
|
||||||
export const ssrRender = /*#__PURE__*/_withId((_ctx, _push, _parent, _attrs) => {
|
export function ssrRender(_ctx, _push, _parent, _attrs) {
|
||||||
const _component_foo = _resolveComponent(\\"foo\\")
|
const _component_foo = _resolveComponent(\\"foo\\")
|
||||||
const _component_bar = _resolveComponent(\\"bar\\")
|
const _component_bar = _resolveComponent(\\"bar\\")
|
||||||
|
|
||||||
_push(_ssrRenderComponent(_component_foo, _attrs, {
|
_push(_ssrRenderComponent(_component_foo, _attrs, {
|
||||||
default: _withId((_, _push, _parent, _scopeId) => {
|
default: _withCtx((_, _push, _parent, _scopeId) => {
|
||||||
if (_push) {
|
if (_push) {
|
||||||
_push(\`<span data-v-xxxxxxx\${_scopeId}>hello</span>\`)
|
_push(\`<span data-v-xxxxxxx\${_scopeId}>hello</span>\`)
|
||||||
_push(_ssrRenderComponent(_component_bar, null, {
|
_push(_ssrRenderComponent(_component_bar, null, {
|
||||||
default: _withId((_, _push, _parent, _scopeId) => {
|
default: _withCtx((_, _push, _parent, _scopeId) => {
|
||||||
if (_push) {
|
if (_push) {
|
||||||
_push(\`<span data-v-xxxxxxx\${_scopeId}></span>\`)
|
_push(\`<span data-v-xxxxxxx\${_scopeId}></span>\`)
|
||||||
} else {
|
} else {
|
||||||
@ -111,12 +106,12 @@ describe('ssr: scopeId', () => {
|
|||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
_: 1 /* STABLE */
|
_: 1 /* STABLE */
|
||||||
}, _parent))
|
}, _parent, _scopeId))
|
||||||
} else {
|
} else {
|
||||||
return [
|
return [
|
||||||
_createVNode(\\"span\\", null, \\"hello\\"),
|
_createVNode(\\"span\\", null, \\"hello\\"),
|
||||||
_createVNode(_component_bar, null, {
|
_createVNode(_component_bar, null, {
|
||||||
default: _withId(() => [
|
default: _withCtx(() => [
|
||||||
_createVNode(\\"span\\")
|
_createVNode(\\"span\\")
|
||||||
]),
|
]),
|
||||||
_: 1 /* STABLE */
|
_: 1 /* STABLE */
|
||||||
@ -126,7 +121,7 @@ describe('ssr: scopeId', () => {
|
|||||||
}),
|
}),
|
||||||
_: 1 /* STABLE */
|
_: 1 /* STABLE */
|
||||||
}, _parent))
|
}, _parent))
|
||||||
})"
|
}"
|
||||||
`)
|
`)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -6,7 +6,7 @@ describe('ssr: <slot>', () => {
|
|||||||
"const { ssrRenderSlot: _ssrRenderSlot } = require(\\"@vue/server-renderer\\")
|
"const { ssrRenderSlot: _ssrRenderSlot } = require(\\"@vue/server-renderer\\")
|
||||||
|
|
||||||
return function ssrRender(_ctx, _push, _parent, _attrs) {
|
return function ssrRender(_ctx, _push, _parent, _attrs) {
|
||||||
_ssrRenderSlot(_ctx.$slots, \\"default\\", {}, null, _push, _parent)
|
_ssrRenderSlot(_ctx.$slots, \\"default\\", {}, null, _push, _parent, null)
|
||||||
}"
|
}"
|
||||||
`)
|
`)
|
||||||
})
|
})
|
||||||
@ -16,7 +16,7 @@ describe('ssr: <slot>', () => {
|
|||||||
"const { ssrRenderSlot: _ssrRenderSlot } = require(\\"@vue/server-renderer\\")
|
"const { ssrRenderSlot: _ssrRenderSlot } = require(\\"@vue/server-renderer\\")
|
||||||
|
|
||||||
return function ssrRender(_ctx, _push, _parent, _attrs) {
|
return function ssrRender(_ctx, _push, _parent, _attrs) {
|
||||||
_ssrRenderSlot(_ctx.$slots, \\"foo\\", {}, null, _push, _parent)
|
_ssrRenderSlot(_ctx.$slots, \\"foo\\", {}, null, _push, _parent, null)
|
||||||
}"
|
}"
|
||||||
`)
|
`)
|
||||||
})
|
})
|
||||||
@ -26,7 +26,7 @@ describe('ssr: <slot>', () => {
|
|||||||
"const { ssrRenderSlot: _ssrRenderSlot } = require(\\"@vue/server-renderer\\")
|
"const { ssrRenderSlot: _ssrRenderSlot } = require(\\"@vue/server-renderer\\")
|
||||||
|
|
||||||
return function ssrRender(_ctx, _push, _parent, _attrs) {
|
return function ssrRender(_ctx, _push, _parent, _attrs) {
|
||||||
_ssrRenderSlot(_ctx.$slots, _ctx.bar.baz, {}, null, _push, _parent)
|
_ssrRenderSlot(_ctx.$slots, _ctx.bar.baz, {}, null, _push, _parent, null)
|
||||||
}"
|
}"
|
||||||
`)
|
`)
|
||||||
})
|
})
|
||||||
@ -40,7 +40,7 @@ describe('ssr: <slot>', () => {
|
|||||||
_ssrRenderSlot(_ctx.$slots, \\"foo\\", {
|
_ssrRenderSlot(_ctx.$slots, \\"foo\\", {
|
||||||
p: 1,
|
p: 1,
|
||||||
bar: \\"2\\"
|
bar: \\"2\\"
|
||||||
}, null, _push, _parent)
|
}, null, _push, _parent, null)
|
||||||
}"
|
}"
|
||||||
`)
|
`)
|
||||||
})
|
})
|
||||||
@ -53,7 +53,49 @@ describe('ssr: <slot>', () => {
|
|||||||
return function ssrRender(_ctx, _push, _parent, _attrs) {
|
return function ssrRender(_ctx, _push, _parent, _attrs) {
|
||||||
_ssrRenderSlot(_ctx.$slots, \\"default\\", {}, () => {
|
_ssrRenderSlot(_ctx.$slots, \\"default\\", {}, () => {
|
||||||
_push(\`some \${_ssrInterpolate(_ctx.fallback)} content\`)
|
_push(\`some \${_ssrInterpolate(_ctx.fallback)} content\`)
|
||||||
}, _push, _parent)
|
}, _push, _parent, null)
|
||||||
|
}"
|
||||||
|
`)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('with scopeId', async () => {
|
||||||
|
expect(
|
||||||
|
compile(`<slot/>`, {
|
||||||
|
scopeId: 'hello'
|
||||||
|
}).code
|
||||||
|
).toMatchInlineSnapshot(`
|
||||||
|
"const { ssrRenderSlot: _ssrRenderSlot } = require(\\"@vue/server-renderer\\")
|
||||||
|
|
||||||
|
return function ssrRender(_ctx, _push, _parent, _attrs) {
|
||||||
|
_ssrRenderSlot(_ctx.$slots, \\"default\\", {}, null, _push, _parent, \\"hello-s\\")
|
||||||
|
}"
|
||||||
|
`)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('with forwarded scopeId', async () => {
|
||||||
|
expect(
|
||||||
|
compile(`<Comp><slot/></Comp>`, {
|
||||||
|
scopeId: 'hello'
|
||||||
|
}).code
|
||||||
|
).toMatchInlineSnapshot(`
|
||||||
|
"const { resolveComponent: _resolveComponent, withCtx: _withCtx, renderSlot: _renderSlot } = require(\\"vue\\")
|
||||||
|
const { ssrRenderSlot: _ssrRenderSlot, ssrRenderComponent: _ssrRenderComponent } = require(\\"@vue/server-renderer\\")
|
||||||
|
|
||||||
|
return function ssrRender(_ctx, _push, _parent, _attrs) {
|
||||||
|
const _component_Comp = _resolveComponent(\\"Comp\\")
|
||||||
|
|
||||||
|
_push(_ssrRenderComponent(_component_Comp, _attrs, {
|
||||||
|
default: _withCtx((_, _push, _parent, _scopeId) => {
|
||||||
|
if (_push) {
|
||||||
|
_ssrRenderSlot(_ctx.$slots, \\"default\\", {}, null, _push, _parent, \\"hello-s\\" + _scopeId)
|
||||||
|
} else {
|
||||||
|
return [
|
||||||
|
_renderSlot(_ctx.$slots, \\"default\\")
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
_: 3 /* FORWARDED */
|
||||||
|
}, _parent))
|
||||||
}"
|
}"
|
||||||
`)
|
`)
|
||||||
})
|
})
|
||||||
|
@ -203,6 +203,12 @@ export function ssrProcessComponent(
|
|||||||
vnodeBranch
|
vnodeBranch
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// component is inside a slot, inherit slot scope Id
|
||||||
|
if (context.withSlotScopeId) {
|
||||||
|
node.ssrCodegenNode!.arguments.push(`_scopeId`)
|
||||||
|
}
|
||||||
|
|
||||||
if (typeof component === 'string') {
|
if (typeof component === 'string') {
|
||||||
// static component
|
// static component
|
||||||
context.pushStatement(
|
context.pushStatement(
|
||||||
|
@ -21,9 +21,11 @@ export const ssrTransformSlotOutlet: NodeTransform = (node, context) => {
|
|||||||
`_ctx.$slots`,
|
`_ctx.$slots`,
|
||||||
slotName,
|
slotName,
|
||||||
slotProps || `{}`,
|
slotProps || `{}`,
|
||||||
`null`, // fallback content placeholder.
|
// fallback content placeholder. will be replaced in the process phase
|
||||||
|
`null`,
|
||||||
`_push`,
|
`_push`,
|
||||||
`_parent`
|
`_parent`,
|
||||||
|
context.scopeId ? `"${context.scopeId}-s"` : `null`
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -34,6 +36,7 @@ export function ssrProcessSlotOutlet(
|
|||||||
context: SSRTransformContext
|
context: SSRTransformContext
|
||||||
) {
|
) {
|
||||||
const renderCall = node.ssrCodegenNode!
|
const renderCall = node.ssrCodegenNode!
|
||||||
|
|
||||||
// has fallback content
|
// has fallback content
|
||||||
if (node.children.length) {
|
if (node.children.length) {
|
||||||
const fallbackRenderFn = createFunctionExpression([])
|
const fallbackRenderFn = createFunctionExpression([])
|
||||||
@ -41,5 +44,13 @@ export function ssrProcessSlotOutlet(
|
|||||||
// _renderSlot(slots, name, props, fallback, ...)
|
// _renderSlot(slots, name, props, fallback, ...)
|
||||||
renderCall.arguments[3] = fallbackRenderFn
|
renderCall.arguments[3] = fallbackRenderFn
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Forwarded <slot/>. Add slot scope id
|
||||||
|
if (context.withSlotScopeId) {
|
||||||
|
const scopeId = renderCall.arguments[6] as string
|
||||||
|
renderCall.arguments[6] =
|
||||||
|
scopeId === `null` ? `_scopeId` : `${scopeId} + _scopeId`
|
||||||
|
}
|
||||||
|
|
||||||
context.pushStatement(node.ssrCodegenNode!)
|
context.pushStatement(node.ssrCodegenNode!)
|
||||||
}
|
}
|
||||||
|
@ -14,8 +14,7 @@ import {
|
|||||||
ComponentPublicInstance,
|
ComponentPublicInstance,
|
||||||
Ref,
|
Ref,
|
||||||
cloneVNode,
|
cloneVNode,
|
||||||
provide,
|
provide
|
||||||
withScopeId
|
|
||||||
} from '@vue/runtime-test'
|
} from '@vue/runtime-test'
|
||||||
import { KeepAliveProps } from '../../src/components/KeepAlive'
|
import { KeepAliveProps } from '../../src/components/KeepAlive'
|
||||||
|
|
||||||
@ -804,14 +803,13 @@ describe('KeepAlive', () => {
|
|||||||
test('should work with cloned root due to scopeId / fallthrough attrs', async () => {
|
test('should work with cloned root due to scopeId / fallthrough attrs', async () => {
|
||||||
const viewRef = ref('one')
|
const viewRef = ref('one')
|
||||||
const instanceRef = ref<any>(null)
|
const instanceRef = ref<any>(null)
|
||||||
const withId = withScopeId('foo')
|
|
||||||
const App = {
|
const App = {
|
||||||
__scopeId: 'foo',
|
__scopeId: 'foo',
|
||||||
render: withId(() => {
|
render: () => {
|
||||||
return h(KeepAlive, null, {
|
return h(KeepAlive, null, {
|
||||||
default: () => h(views[viewRef.value], { ref: instanceRef })
|
default: () => h(views[viewRef.value], { ref: instanceRef })
|
||||||
})
|
})
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
render(h(App), root)
|
render(h(App), root)
|
||||||
expect(serializeInner(root)).toBe(`<div foo>one</div>`)
|
expect(serializeInner(root)).toBe(`<div foo>one</div>`)
|
||||||
|
@ -8,7 +8,7 @@ import {
|
|||||||
Fragment,
|
Fragment,
|
||||||
createCommentVNode
|
createCommentVNode
|
||||||
} from '../../src'
|
} from '../../src'
|
||||||
import { PatchFlags } from '@vue/shared/src'
|
import { PatchFlags } from '@vue/shared'
|
||||||
|
|
||||||
describe('renderSlot', () => {
|
describe('renderSlot', () => {
|
||||||
it('should render slot', () => {
|
it('should render slot', () => {
|
||||||
@ -37,7 +37,7 @@ describe('renderSlot', () => {
|
|||||||
return [createVNode('div', null, 'foo', PatchFlags.TEXT)]
|
return [createVNode('div', null, 'foo', PatchFlags.TEXT)]
|
||||||
},
|
},
|
||||||
// mock instance
|
// mock instance
|
||||||
{} as any
|
{ type: {} } as any
|
||||||
)
|
)
|
||||||
|
|
||||||
// manual invocation should not track
|
// manual invocation should not track
|
||||||
|
@ -1,105 +0,0 @@
|
|||||||
import { withScopeId } from '../../src/helpers/scopeId'
|
|
||||||
import { h, render, nodeOps, serializeInner } from '@vue/runtime-test'
|
|
||||||
|
|
||||||
describe('scopeId runtime support', () => {
|
|
||||||
const withParentId = withScopeId('parent')
|
|
||||||
const withChildId = withScopeId('child')
|
|
||||||
|
|
||||||
test('should attach scopeId', () => {
|
|
||||||
const App = {
|
|
||||||
__scopeId: 'parent',
|
|
||||||
render: withParentId(() => {
|
|
||||||
return h('div', [h('div')])
|
|
||||||
})
|
|
||||||
}
|
|
||||||
const root = nodeOps.createElement('div')
|
|
||||||
render(h(App), root)
|
|
||||||
expect(serializeInner(root)).toBe(`<div parent><div parent></div></div>`)
|
|
||||||
})
|
|
||||||
|
|
||||||
test('should attach scopeId to components in parent component', () => {
|
|
||||||
const Child = {
|
|
||||||
__scopeId: 'child',
|
|
||||||
render: withChildId(() => {
|
|
||||||
return h('div')
|
|
||||||
})
|
|
||||||
}
|
|
||||||
const App = {
|
|
||||||
__scopeId: 'parent',
|
|
||||||
render: withParentId(() => {
|
|
||||||
return h('div', [h(Child)])
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const root = nodeOps.createElement('div')
|
|
||||||
render(h(App), root)
|
|
||||||
expect(serializeInner(root)).toBe(
|
|
||||||
`<div parent><div child parent></div></div>`
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
test('should work on slots', () => {
|
|
||||||
const Child = {
|
|
||||||
__scopeId: 'child',
|
|
||||||
render: withChildId(function(this: any) {
|
|
||||||
return h('div', this.$slots.default())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
const withChild2Id = withScopeId('child2')
|
|
||||||
const Child2 = {
|
|
||||||
__scopeId: 'child2',
|
|
||||||
render: withChild2Id(() => h('span'))
|
|
||||||
}
|
|
||||||
const App = {
|
|
||||||
__scopeId: 'parent',
|
|
||||||
render: withParentId(() => {
|
|
||||||
return h(
|
|
||||||
Child,
|
|
||||||
withParentId(() => {
|
|
||||||
return [h('div'), h(Child2)]
|
|
||||||
})
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
const root = nodeOps.createElement('div')
|
|
||||||
render(h(App), root)
|
|
||||||
// slot content should have:
|
|
||||||
// - scopeId from parent
|
|
||||||
// - slotted scopeId (with `-s` postfix) from child (the tree owner)
|
|
||||||
expect(serializeInner(root)).toBe(
|
|
||||||
`<div child parent>` +
|
|
||||||
`<div parent child-s></div>` +
|
|
||||||
// component inside slot should have:
|
|
||||||
// - scopeId from template context
|
|
||||||
// - slotted scopeId from slot owner
|
|
||||||
// - its own scopeId
|
|
||||||
`<span child2 parent child-s></span>` +
|
|
||||||
`</div>`
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
// #1988
|
|
||||||
test('should inherit scopeId through nested HOCs with inheritAttrs: false', () => {
|
|
||||||
const withParentId = withScopeId('parent')
|
|
||||||
const App = {
|
|
||||||
__scopeId: 'parent',
|
|
||||||
render: withParentId(() => {
|
|
||||||
return h(Child)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function Child() {
|
|
||||||
return h(Child2, { class: 'foo' })
|
|
||||||
}
|
|
||||||
|
|
||||||
function Child2() {
|
|
||||||
return h('div')
|
|
||||||
}
|
|
||||||
Child2.inheritAttrs = false
|
|
||||||
|
|
||||||
const root = nodeOps.createElement('div')
|
|
||||||
render(h(App), root)
|
|
||||||
|
|
||||||
expect(serializeInner(root)).toBe(`<div parent></div>`)
|
|
||||||
})
|
|
||||||
})
|
|
178
packages/runtime-core/__tests__/scopeId.spec.ts
Normal file
178
packages/runtime-core/__tests__/scopeId.spec.ts
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
import {
|
||||||
|
h,
|
||||||
|
render,
|
||||||
|
nodeOps,
|
||||||
|
serializeInner,
|
||||||
|
renderSlot
|
||||||
|
} from '@vue/runtime-test'
|
||||||
|
import { setScopeId, withCtx } from '../src/componentRenderContext'
|
||||||
|
|
||||||
|
describe('scopeId runtime support', () => {
|
||||||
|
test('should attach scopeId', () => {
|
||||||
|
const App = {
|
||||||
|
__scopeId: 'parent',
|
||||||
|
render: () => h('div', [h('div')])
|
||||||
|
}
|
||||||
|
const root = nodeOps.createElement('div')
|
||||||
|
render(h(App), root)
|
||||||
|
expect(serializeInner(root)).toBe(`<div parent><div parent></div></div>`)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('should attach scopeId to components in parent component', () => {
|
||||||
|
const Child = {
|
||||||
|
__scopeId: 'child',
|
||||||
|
render: () => h('div')
|
||||||
|
}
|
||||||
|
const App = {
|
||||||
|
__scopeId: 'parent',
|
||||||
|
render: () => h('div', [h(Child)])
|
||||||
|
}
|
||||||
|
|
||||||
|
const root = nodeOps.createElement('div')
|
||||||
|
render(h(App), root)
|
||||||
|
expect(serializeInner(root)).toBe(
|
||||||
|
`<div parent><div child parent></div></div>`
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
// :slotted basic
|
||||||
|
test('should work on slots', () => {
|
||||||
|
const Child = {
|
||||||
|
__scopeId: 'child',
|
||||||
|
render(this: any) {
|
||||||
|
return h('div', renderSlot(this.$slots, 'default'))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const Child2 = {
|
||||||
|
__scopeId: 'child2',
|
||||||
|
render: () => h('span')
|
||||||
|
}
|
||||||
|
const App = {
|
||||||
|
__scopeId: 'parent',
|
||||||
|
render: () => {
|
||||||
|
return h(
|
||||||
|
Child,
|
||||||
|
withCtx(() => {
|
||||||
|
return [h('div'), h(Child2)]
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const root = nodeOps.createElement('div')
|
||||||
|
render(h(App), root)
|
||||||
|
// slot content should have:
|
||||||
|
// - scopeId from parent
|
||||||
|
// - slotted scopeId (with `-s` postfix) from child (the tree owner)
|
||||||
|
expect(serializeInner(root)).toBe(
|
||||||
|
`<div child parent>` +
|
||||||
|
`<div parent child-s></div>` +
|
||||||
|
// component inside slot should have:
|
||||||
|
// - scopeId from template context
|
||||||
|
// - slotted scopeId from slot owner
|
||||||
|
// - its own scopeId
|
||||||
|
`<span child2 parent child-s></span>` +
|
||||||
|
`</div>`
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
// #2892
|
||||||
|
test(':slotted on forwarded slots', async () => {
|
||||||
|
const Wrapper = {
|
||||||
|
__scopeId: 'wrapper',
|
||||||
|
render(this: any) {
|
||||||
|
// <div class="wrapper"><slot/></div>
|
||||||
|
return h('div', { class: 'wrapper' }, [
|
||||||
|
renderSlot(this.$slots, 'default')
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const Slotted = {
|
||||||
|
__scopeId: 'slotted',
|
||||||
|
render(this: any) {
|
||||||
|
// <Wrapper><slot/></Wrapper>
|
||||||
|
return h(Wrapper, null, {
|
||||||
|
default: withCtx(() => [renderSlot(this.$slots, 'default')])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// simulate hoisted node
|
||||||
|
setScopeId('root')
|
||||||
|
const hoisted = h('div', 'hoisted')
|
||||||
|
setScopeId(null)
|
||||||
|
|
||||||
|
const Root = {
|
||||||
|
__scopeId: 'root',
|
||||||
|
render(this: any) {
|
||||||
|
// <Slotted><div>hoisted</div><div>{{ dynamic }}</div></Slotted>
|
||||||
|
return h(Slotted, null, {
|
||||||
|
default: withCtx(() => {
|
||||||
|
return [hoisted, h('div', 'dynamic')]
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const root = nodeOps.createElement('div')
|
||||||
|
render(h(Root), root)
|
||||||
|
expect(serializeInner(root)).toBe(
|
||||||
|
`<div class="wrapper" wrapper slotted root>` +
|
||||||
|
`<div root wrapper-s slotted-s>hoisted</div>` +
|
||||||
|
`<div root wrapper-s slotted-s>dynamic</div>` +
|
||||||
|
`</div>`
|
||||||
|
)
|
||||||
|
|
||||||
|
const Root2 = {
|
||||||
|
__scopeId: 'root',
|
||||||
|
render(this: any) {
|
||||||
|
// <Slotted>
|
||||||
|
// <Wrapper>
|
||||||
|
// <div>hoisted</div><div>{{ dynamic }}</div>
|
||||||
|
// </Wrapper>
|
||||||
|
// </Slotted>
|
||||||
|
return h(Slotted, null, {
|
||||||
|
default: withCtx(() => [
|
||||||
|
h(Wrapper, null, {
|
||||||
|
default: withCtx(() => [hoisted, h('div', 'dynamic')])
|
||||||
|
})
|
||||||
|
])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const root2 = nodeOps.createElement('div')
|
||||||
|
render(h(Root2), root2)
|
||||||
|
expect(serializeInner(root2)).toBe(
|
||||||
|
`<div class="wrapper" wrapper slotted root>` +
|
||||||
|
`<div class="wrapper" wrapper root wrapper-s slotted-s>` +
|
||||||
|
`<div root wrapper-s>hoisted</div>` +
|
||||||
|
`<div root wrapper-s>dynamic</div>` +
|
||||||
|
`</div>` +
|
||||||
|
`</div>`
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
// #1988
|
||||||
|
test('should inherit scopeId through nested HOCs with inheritAttrs: false', () => {
|
||||||
|
const App = {
|
||||||
|
__scopeId: 'parent',
|
||||||
|
render: () => {
|
||||||
|
return h(Child)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Child() {
|
||||||
|
return h(Child2, { class: 'foo' })
|
||||||
|
}
|
||||||
|
|
||||||
|
function Child2() {
|
||||||
|
return h('div')
|
||||||
|
}
|
||||||
|
Child2.inheritAttrs = false
|
||||||
|
|
||||||
|
const root = nodeOps.createElement('div')
|
||||||
|
render(h(App), root)
|
||||||
|
|
||||||
|
expect(serializeInner(root)).toBe(`<div parent></div>`)
|
||||||
|
})
|
||||||
|
})
|
@ -14,7 +14,7 @@ import { Data } from '../src/component'
|
|||||||
import { ShapeFlags, PatchFlags } from '@vue/shared'
|
import { ShapeFlags, PatchFlags } from '@vue/shared'
|
||||||
import { h, reactive, isReactive, setBlockTracking } from '../src'
|
import { h, reactive, isReactive, setBlockTracking } from '../src'
|
||||||
import { createApp, nodeOps, serializeInner } from '@vue/runtime-test'
|
import { createApp, nodeOps, serializeInner } from '@vue/runtime-test'
|
||||||
import { setCurrentRenderingInstance } from '../src/componentRenderUtils'
|
import { setCurrentRenderingInstance } from '../src/componentRenderContext'
|
||||||
|
|
||||||
describe('vnode', () => {
|
describe('vnode', () => {
|
||||||
test('create with just tag', () => {
|
test('create with just tag', () => {
|
||||||
@ -231,8 +231,8 @@ describe('vnode', () => {
|
|||||||
|
|
||||||
// ref normalizes to [currentRenderingInstance, ref]
|
// ref normalizes to [currentRenderingInstance, ref]
|
||||||
test('cloneVNode ref normalization', () => {
|
test('cloneVNode ref normalization', () => {
|
||||||
const mockInstance1 = {} as any
|
const mockInstance1 = { type: {} } as any
|
||||||
const mockInstance2 = {} as any
|
const mockInstance2 = { type: {} } as any
|
||||||
|
|
||||||
setCurrentRenderingInstance(mockInstance1)
|
setCurrentRenderingInstance(mockInstance1)
|
||||||
const original = createVNode('div', { ref: 'foo' })
|
const original = createVNode('div', { ref: 'foo' })
|
||||||
@ -272,8 +272,8 @@ describe('vnode', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
test('cloneVNode ref merging', () => {
|
test('cloneVNode ref merging', () => {
|
||||||
const mockInstance1 = {} as any
|
const mockInstance1 = { type: {} } as any
|
||||||
const mockInstance2 = {} as any
|
const mockInstance2 = { type: {} } as any
|
||||||
|
|
||||||
setCurrentRenderingInstance(mockInstance1)
|
setCurrentRenderingInstance(mockInstance1)
|
||||||
const original = createVNode('div', { ref: 'foo' })
|
const original = createVNode('div', { ref: 'foo' })
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { isFunction } from '@vue/shared'
|
import { isFunction } from '@vue/shared'
|
||||||
import { currentInstance } from './component'
|
import { currentInstance } from './component'
|
||||||
import { currentRenderingInstance } from './componentRenderUtils'
|
import { currentRenderingInstance } from './componentRenderContext'
|
||||||
import { warn } from './warning'
|
import { warn } from './warning'
|
||||||
|
|
||||||
export interface InjectionKey<T> extends Symbol {}
|
export interface InjectionKey<T> extends Symbol {}
|
||||||
|
@ -51,10 +51,8 @@ import {
|
|||||||
} from '@vue/shared'
|
} from '@vue/shared'
|
||||||
import { SuspenseBoundary } from './components/Suspense'
|
import { SuspenseBoundary } from './components/Suspense'
|
||||||
import { CompilerOptions } from '@vue/compiler-core'
|
import { CompilerOptions } from '@vue/compiler-core'
|
||||||
import {
|
import { markAttrsAccessed } from './componentRenderUtils'
|
||||||
currentRenderingInstance,
|
import { currentRenderingInstance } from './componentRenderContext'
|
||||||
markAttrsAccessed
|
|
||||||
} from './componentRenderUtils'
|
|
||||||
import { startMeasure, endMeasure } from './profiling'
|
import { startMeasure, endMeasure } from './profiling'
|
||||||
|
|
||||||
export type Data = Record<string, unknown>
|
export type Data = Record<string, unknown>
|
||||||
|
@ -35,10 +35,8 @@ import {
|
|||||||
} from './componentOptions'
|
} from './componentOptions'
|
||||||
import { EmitsOptions, EmitFn } from './componentEmits'
|
import { EmitsOptions, EmitFn } from './componentEmits'
|
||||||
import { Slots } from './componentSlots'
|
import { Slots } from './componentSlots'
|
||||||
import {
|
import { markAttrsAccessed } from './componentRenderUtils'
|
||||||
currentRenderingInstance,
|
import { currentRenderingInstance } from './componentRenderContext'
|
||||||
markAttrsAccessed
|
|
||||||
} from './componentRenderUtils'
|
|
||||||
import { warn } from './warning'
|
import { warn } from './warning'
|
||||||
import { UnionToIntersection } from './helpers/typeUtils'
|
import { UnionToIntersection } from './helpers/typeUtils'
|
||||||
|
|
||||||
|
57
packages/runtime-core/src/componentRenderContext.ts
Normal file
57
packages/runtime-core/src/componentRenderContext.ts
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import { ComponentInternalInstance } from './component'
|
||||||
|
import { isRenderingCompiledSlot } from './helpers/renderSlot'
|
||||||
|
import { closeBlock, openBlock } from './vnode'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mark the current rendering instance for asset resolution (e.g.
|
||||||
|
* resolveComponent, resolveDirective) during render
|
||||||
|
*/
|
||||||
|
export let currentRenderingInstance: ComponentInternalInstance | null = null
|
||||||
|
export let currentScopeId: string | null = null
|
||||||
|
|
||||||
|
export function setCurrentRenderingInstance(
|
||||||
|
instance: ComponentInternalInstance | null
|
||||||
|
) {
|
||||||
|
currentRenderingInstance = instance
|
||||||
|
currentScopeId = (instance && instance.type.__scopeId) || null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set scope id when creating hoisted vnodes.
|
||||||
|
* @private compiler helper
|
||||||
|
*/
|
||||||
|
export function setScopeId(id: string | null) {
|
||||||
|
currentScopeId = id
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrap a slot function to memoize current rendering instance
|
||||||
|
* @private compiler helper
|
||||||
|
*/
|
||||||
|
export function withCtx(
|
||||||
|
fn: Function,
|
||||||
|
ctx: ComponentInternalInstance | null = currentRenderingInstance
|
||||||
|
) {
|
||||||
|
if (!ctx) return fn
|
||||||
|
const renderFnWithContext = (...args: any[]) => {
|
||||||
|
// If a user calls a compiled slot inside a template expression (#1745), it
|
||||||
|
// can mess up block tracking, so by default we need to push a null block to
|
||||||
|
// avoid that. This isn't necessary if rendering a compiled `<slot>`.
|
||||||
|
if (!isRenderingCompiledSlot) {
|
||||||
|
openBlock(true /* null block that disables tracking */)
|
||||||
|
}
|
||||||
|
const prevInstance = currentRenderingInstance
|
||||||
|
setCurrentRenderingInstance(ctx)
|
||||||
|
const res = fn(...args)
|
||||||
|
setCurrentRenderingInstance(prevInstance)
|
||||||
|
if (!isRenderingCompiledSlot) {
|
||||||
|
closeBlock()
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
// mark this as a compiled slot function.
|
||||||
|
// this is used in vnode.ts -> normalizeChildren() to set the slot
|
||||||
|
// rendering flag.
|
||||||
|
renderFnWithContext._c = true
|
||||||
|
return renderFnWithContext
|
||||||
|
}
|
@ -18,18 +18,7 @@ import { warn } from './warning'
|
|||||||
import { isHmrUpdating } from './hmr'
|
import { isHmrUpdating } from './hmr'
|
||||||
import { NormalizedProps } from './componentProps'
|
import { NormalizedProps } from './componentProps'
|
||||||
import { isEmitListener } from './componentEmits'
|
import { isEmitListener } from './componentEmits'
|
||||||
|
import { setCurrentRenderingInstance } from './componentRenderContext'
|
||||||
/**
|
|
||||||
* mark the current rendering instance for asset resolution (e.g.
|
|
||||||
* resolveComponent, resolveDirective) during render
|
|
||||||
*/
|
|
||||||
export let currentRenderingInstance: ComponentInternalInstance | null = null
|
|
||||||
|
|
||||||
export function setCurrentRenderingInstance(
|
|
||||||
instance: ComponentInternalInstance | null
|
|
||||||
) {
|
|
||||||
currentRenderingInstance = instance
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* dev only flag to track whether $attrs was used during render.
|
* dev only flag to track whether $attrs was used during render.
|
||||||
@ -63,7 +52,7 @@ export function renderComponentRoot(
|
|||||||
} = instance
|
} = instance
|
||||||
|
|
||||||
let result
|
let result
|
||||||
currentRenderingInstance = instance
|
setCurrentRenderingInstance(instance)
|
||||||
if (__DEV__) {
|
if (__DEV__) {
|
||||||
accessedAttrs = false
|
accessedAttrs = false
|
||||||
}
|
}
|
||||||
@ -215,8 +204,8 @@ export function renderComponentRoot(
|
|||||||
handleError(err, instance, ErrorCodes.RENDER_FUNCTION)
|
handleError(err, instance, ErrorCodes.RENDER_FUNCTION)
|
||||||
result = createVNode(Comment)
|
result = createVNode(Comment)
|
||||||
}
|
}
|
||||||
currentRenderingInstance = null
|
|
||||||
|
|
||||||
|
setCurrentRenderingInstance(null)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ import {
|
|||||||
} from '@vue/shared'
|
} from '@vue/shared'
|
||||||
import { warn } from './warning'
|
import { warn } from './warning'
|
||||||
import { isKeepAlive } from './components/KeepAlive'
|
import { isKeepAlive } from './components/KeepAlive'
|
||||||
import { withCtx } from './helpers/withRenderContext'
|
import { withCtx } from './componentRenderContext'
|
||||||
import { isHmrUpdating } from './hmr'
|
import { isHmrUpdating } from './hmr'
|
||||||
|
|
||||||
export type Slot = (...args: any[]) => VNode[]
|
export type Slot = (...args: any[]) => VNode[]
|
||||||
|
@ -112,6 +112,7 @@ const KeepAliveImpl = {
|
|||||||
instance,
|
instance,
|
||||||
parentSuspense,
|
parentSuspense,
|
||||||
isSVG,
|
isSVG,
|
||||||
|
vnode.slotScopeIds,
|
||||||
optimized
|
optimized
|
||||||
)
|
)
|
||||||
queuePostRenderEffect(() => {
|
queuePostRenderEffect(() => {
|
||||||
|
@ -46,6 +46,7 @@ export const SuspenseImpl = {
|
|||||||
parentComponent: ComponentInternalInstance | null,
|
parentComponent: ComponentInternalInstance | null,
|
||||||
parentSuspense: SuspenseBoundary | null,
|
parentSuspense: SuspenseBoundary | null,
|
||||||
isSVG: boolean,
|
isSVG: boolean,
|
||||||
|
slotScopeIds: string[] | null,
|
||||||
optimized: boolean,
|
optimized: boolean,
|
||||||
// platform-specific impl passed from renderer
|
// platform-specific impl passed from renderer
|
||||||
rendererInternals: RendererInternals
|
rendererInternals: RendererInternals
|
||||||
@ -58,6 +59,7 @@ export const SuspenseImpl = {
|
|||||||
parentComponent,
|
parentComponent,
|
||||||
parentSuspense,
|
parentSuspense,
|
||||||
isSVG,
|
isSVG,
|
||||||
|
slotScopeIds,
|
||||||
optimized,
|
optimized,
|
||||||
rendererInternals
|
rendererInternals
|
||||||
)
|
)
|
||||||
@ -69,6 +71,8 @@ export const SuspenseImpl = {
|
|||||||
anchor,
|
anchor,
|
||||||
parentComponent,
|
parentComponent,
|
||||||
isSVG,
|
isSVG,
|
||||||
|
slotScopeIds,
|
||||||
|
optimized,
|
||||||
rendererInternals
|
rendererInternals
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -92,6 +96,7 @@ function mountSuspense(
|
|||||||
parentComponent: ComponentInternalInstance | null,
|
parentComponent: ComponentInternalInstance | null,
|
||||||
parentSuspense: SuspenseBoundary | null,
|
parentSuspense: SuspenseBoundary | null,
|
||||||
isSVG: boolean,
|
isSVG: boolean,
|
||||||
|
slotScopeIds: string[] | null,
|
||||||
optimized: boolean,
|
optimized: boolean,
|
||||||
rendererInternals: RendererInternals
|
rendererInternals: RendererInternals
|
||||||
) {
|
) {
|
||||||
@ -108,6 +113,7 @@ function mountSuspense(
|
|||||||
hiddenContainer,
|
hiddenContainer,
|
||||||
anchor,
|
anchor,
|
||||||
isSVG,
|
isSVG,
|
||||||
|
slotScopeIds,
|
||||||
optimized,
|
optimized,
|
||||||
rendererInternals
|
rendererInternals
|
||||||
))
|
))
|
||||||
@ -120,7 +126,8 @@ function mountSuspense(
|
|||||||
null,
|
null,
|
||||||
parentComponent,
|
parentComponent,
|
||||||
suspense,
|
suspense,
|
||||||
isSVG
|
isSVG,
|
||||||
|
slotScopeIds
|
||||||
)
|
)
|
||||||
// now check if we have encountered any async deps
|
// now check if we have encountered any async deps
|
||||||
if (suspense.deps > 0) {
|
if (suspense.deps > 0) {
|
||||||
@ -133,7 +140,8 @@ function mountSuspense(
|
|||||||
anchor,
|
anchor,
|
||||||
parentComponent,
|
parentComponent,
|
||||||
null, // fallback tree will not have suspense context
|
null, // fallback tree will not have suspense context
|
||||||
isSVG
|
isSVG,
|
||||||
|
slotScopeIds
|
||||||
)
|
)
|
||||||
setActiveBranch(suspense, vnode.ssFallback!)
|
setActiveBranch(suspense, vnode.ssFallback!)
|
||||||
} else {
|
} else {
|
||||||
@ -149,6 +157,8 @@ function patchSuspense(
|
|||||||
anchor: RendererNode | null,
|
anchor: RendererNode | null,
|
||||||
parentComponent: ComponentInternalInstance | null,
|
parentComponent: ComponentInternalInstance | null,
|
||||||
isSVG: boolean,
|
isSVG: boolean,
|
||||||
|
slotScopeIds: string[] | null,
|
||||||
|
optimized: boolean,
|
||||||
{ p: patch, um: unmount, o: { createElement } }: RendererInternals
|
{ p: patch, um: unmount, o: { createElement } }: RendererInternals
|
||||||
) {
|
) {
|
||||||
const suspense = (n2.suspense = n1.suspense)!
|
const suspense = (n2.suspense = n1.suspense)!
|
||||||
@ -169,7 +179,9 @@ function patchSuspense(
|
|||||||
null,
|
null,
|
||||||
parentComponent,
|
parentComponent,
|
||||||
suspense,
|
suspense,
|
||||||
isSVG
|
isSVG,
|
||||||
|
slotScopeIds,
|
||||||
|
optimized
|
||||||
)
|
)
|
||||||
if (suspense.deps <= 0) {
|
if (suspense.deps <= 0) {
|
||||||
suspense.resolve()
|
suspense.resolve()
|
||||||
@ -181,7 +193,9 @@ function patchSuspense(
|
|||||||
anchor,
|
anchor,
|
||||||
parentComponent,
|
parentComponent,
|
||||||
null, // fallback tree will not have suspense context
|
null, // fallback tree will not have suspense context
|
||||||
isSVG
|
isSVG,
|
||||||
|
slotScopeIds,
|
||||||
|
optimized
|
||||||
)
|
)
|
||||||
setActiveBranch(suspense, newFallback)
|
setActiveBranch(suspense, newFallback)
|
||||||
}
|
}
|
||||||
@ -214,7 +228,9 @@ function patchSuspense(
|
|||||||
null,
|
null,
|
||||||
parentComponent,
|
parentComponent,
|
||||||
suspense,
|
suspense,
|
||||||
isSVG
|
isSVG,
|
||||||
|
slotScopeIds,
|
||||||
|
optimized
|
||||||
)
|
)
|
||||||
if (suspense.deps <= 0) {
|
if (suspense.deps <= 0) {
|
||||||
suspense.resolve()
|
suspense.resolve()
|
||||||
@ -226,7 +242,9 @@ function patchSuspense(
|
|||||||
anchor,
|
anchor,
|
||||||
parentComponent,
|
parentComponent,
|
||||||
null, // fallback tree will not have suspense context
|
null, // fallback tree will not have suspense context
|
||||||
isSVG
|
isSVG,
|
||||||
|
slotScopeIds,
|
||||||
|
optimized
|
||||||
)
|
)
|
||||||
setActiveBranch(suspense, newFallback)
|
setActiveBranch(suspense, newFallback)
|
||||||
}
|
}
|
||||||
@ -239,7 +257,9 @@ function patchSuspense(
|
|||||||
anchor,
|
anchor,
|
||||||
parentComponent,
|
parentComponent,
|
||||||
suspense,
|
suspense,
|
||||||
isSVG
|
isSVG,
|
||||||
|
slotScopeIds,
|
||||||
|
optimized
|
||||||
)
|
)
|
||||||
// force resolve
|
// force resolve
|
||||||
suspense.resolve(true)
|
suspense.resolve(true)
|
||||||
@ -252,7 +272,9 @@ function patchSuspense(
|
|||||||
null,
|
null,
|
||||||
parentComponent,
|
parentComponent,
|
||||||
suspense,
|
suspense,
|
||||||
isSVG
|
isSVG,
|
||||||
|
slotScopeIds,
|
||||||
|
optimized
|
||||||
)
|
)
|
||||||
if (suspense.deps <= 0) {
|
if (suspense.deps <= 0) {
|
||||||
suspense.resolve()
|
suspense.resolve()
|
||||||
@ -269,7 +291,9 @@ function patchSuspense(
|
|||||||
anchor,
|
anchor,
|
||||||
parentComponent,
|
parentComponent,
|
||||||
suspense,
|
suspense,
|
||||||
isSVG
|
isSVG,
|
||||||
|
slotScopeIds,
|
||||||
|
optimized
|
||||||
)
|
)
|
||||||
setActiveBranch(suspense, newBranch)
|
setActiveBranch(suspense, newBranch)
|
||||||
} else {
|
} else {
|
||||||
@ -289,7 +313,9 @@ function patchSuspense(
|
|||||||
null,
|
null,
|
||||||
parentComponent,
|
parentComponent,
|
||||||
suspense,
|
suspense,
|
||||||
isSVG
|
isSVG,
|
||||||
|
slotScopeIds,
|
||||||
|
optimized
|
||||||
)
|
)
|
||||||
if (suspense.deps <= 0) {
|
if (suspense.deps <= 0) {
|
||||||
// incoming branch has no async deps, resolve now.
|
// incoming branch has no async deps, resolve now.
|
||||||
@ -352,6 +378,7 @@ function createSuspenseBoundary(
|
|||||||
hiddenContainer: RendererElement,
|
hiddenContainer: RendererElement,
|
||||||
anchor: RendererNode | null,
|
anchor: RendererNode | null,
|
||||||
isSVG: boolean,
|
isSVG: boolean,
|
||||||
|
slotScopeIds: string[] | null,
|
||||||
optimized: boolean,
|
optimized: boolean,
|
||||||
rendererInternals: RendererInternals,
|
rendererInternals: RendererInternals,
|
||||||
isHydrating = false
|
isHydrating = false
|
||||||
@ -507,7 +534,9 @@ function createSuspenseBoundary(
|
|||||||
anchor,
|
anchor,
|
||||||
parentComponent,
|
parentComponent,
|
||||||
null, // fallback tree will not have suspense context
|
null, // fallback tree will not have suspense context
|
||||||
isSVG
|
isSVG,
|
||||||
|
slotScopeIds,
|
||||||
|
optimized
|
||||||
)
|
)
|
||||||
setActiveBranch(suspense, fallbackVNode)
|
setActiveBranch(suspense, fallbackVNode)
|
||||||
}
|
}
|
||||||
@ -632,6 +661,7 @@ function hydrateSuspense(
|
|||||||
parentComponent: ComponentInternalInstance | null,
|
parentComponent: ComponentInternalInstance | null,
|
||||||
parentSuspense: SuspenseBoundary | null,
|
parentSuspense: SuspenseBoundary | null,
|
||||||
isSVG: boolean,
|
isSVG: boolean,
|
||||||
|
slotScopeIds: string[] | null,
|
||||||
optimized: boolean,
|
optimized: boolean,
|
||||||
rendererInternals: RendererInternals,
|
rendererInternals: RendererInternals,
|
||||||
hydrateNode: (
|
hydrateNode: (
|
||||||
@ -639,6 +669,7 @@ function hydrateSuspense(
|
|||||||
vnode: VNode,
|
vnode: VNode,
|
||||||
parentComponent: ComponentInternalInstance | null,
|
parentComponent: ComponentInternalInstance | null,
|
||||||
parentSuspense: SuspenseBoundary | null,
|
parentSuspense: SuspenseBoundary | null,
|
||||||
|
slotScopeIds: string[] | null,
|
||||||
optimized: boolean
|
optimized: boolean
|
||||||
) => Node | null
|
) => Node | null
|
||||||
): Node | null {
|
): Node | null {
|
||||||
@ -651,6 +682,7 @@ function hydrateSuspense(
|
|||||||
document.createElement('div'),
|
document.createElement('div'),
|
||||||
null,
|
null,
|
||||||
isSVG,
|
isSVG,
|
||||||
|
slotScopeIds,
|
||||||
optimized,
|
optimized,
|
||||||
rendererInternals,
|
rendererInternals,
|
||||||
true /* hydrating */
|
true /* hydrating */
|
||||||
@ -666,6 +698,7 @@ function hydrateSuspense(
|
|||||||
(suspense.pendingBranch = vnode.ssContent!),
|
(suspense.pendingBranch = vnode.ssContent!),
|
||||||
parentComponent,
|
parentComponent,
|
||||||
suspense,
|
suspense,
|
||||||
|
slotScopeIds,
|
||||||
optimized
|
optimized
|
||||||
)
|
)
|
||||||
if (suspense.deps === 0) {
|
if (suspense.deps === 0) {
|
||||||
|
@ -71,6 +71,7 @@ export const TeleportImpl = {
|
|||||||
parentComponent: ComponentInternalInstance | null,
|
parentComponent: ComponentInternalInstance | null,
|
||||||
parentSuspense: SuspenseBoundary | null,
|
parentSuspense: SuspenseBoundary | null,
|
||||||
isSVG: boolean,
|
isSVG: boolean,
|
||||||
|
slotScopeIds: string[] | null,
|
||||||
optimized: boolean,
|
optimized: boolean,
|
||||||
internals: RendererInternals
|
internals: RendererInternals
|
||||||
) {
|
) {
|
||||||
@ -115,6 +116,7 @@ export const TeleportImpl = {
|
|||||||
parentComponent,
|
parentComponent,
|
||||||
parentSuspense,
|
parentSuspense,
|
||||||
isSVG,
|
isSVG,
|
||||||
|
slotScopeIds,
|
||||||
optimized
|
optimized
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -144,7 +146,8 @@ export const TeleportImpl = {
|
|||||||
currentContainer,
|
currentContainer,
|
||||||
parentComponent,
|
parentComponent,
|
||||||
parentSuspense,
|
parentSuspense,
|
||||||
isSVG
|
isSVG,
|
||||||
|
slotScopeIds
|
||||||
)
|
)
|
||||||
// even in block tree mode we need to make sure all root-level nodes
|
// even in block tree mode we need to make sure all root-level nodes
|
||||||
// in the teleport inherit previous DOM references so that they can
|
// in the teleport inherit previous DOM references so that they can
|
||||||
@ -158,7 +161,9 @@ export const TeleportImpl = {
|
|||||||
currentAnchor,
|
currentAnchor,
|
||||||
parentComponent,
|
parentComponent,
|
||||||
parentSuspense,
|
parentSuspense,
|
||||||
isSVG
|
isSVG,
|
||||||
|
slotScopeIds,
|
||||||
|
false
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -283,6 +288,7 @@ function hydrateTeleport(
|
|||||||
vnode: TeleportVNode,
|
vnode: TeleportVNode,
|
||||||
parentComponent: ComponentInternalInstance | null,
|
parentComponent: ComponentInternalInstance | null,
|
||||||
parentSuspense: SuspenseBoundary | null,
|
parentSuspense: SuspenseBoundary | null,
|
||||||
|
slotScopeIds: string[] | null,
|
||||||
optimized: boolean,
|
optimized: boolean,
|
||||||
{
|
{
|
||||||
o: { nextSibling, parentNode, querySelector }
|
o: { nextSibling, parentNode, querySelector }
|
||||||
@ -293,6 +299,7 @@ function hydrateTeleport(
|
|||||||
container: Element,
|
container: Element,
|
||||||
parentComponent: ComponentInternalInstance | null,
|
parentComponent: ComponentInternalInstance | null,
|
||||||
parentSuspense: SuspenseBoundary | null,
|
parentSuspense: SuspenseBoundary | null,
|
||||||
|
slotScopeIds: string[] | null,
|
||||||
optimized: boolean
|
optimized: boolean
|
||||||
) => Node | null
|
) => Node | null
|
||||||
): Node | null {
|
): Node | null {
|
||||||
@ -313,6 +320,7 @@ function hydrateTeleport(
|
|||||||
parentNode(node)!,
|
parentNode(node)!,
|
||||||
parentComponent,
|
parentComponent,
|
||||||
parentSuspense,
|
parentSuspense,
|
||||||
|
slotScopeIds,
|
||||||
optimized
|
optimized
|
||||||
)
|
)
|
||||||
vnode.targetAnchor = targetNode
|
vnode.targetAnchor = targetNode
|
||||||
@ -324,6 +332,7 @@ function hydrateTeleport(
|
|||||||
target,
|
target,
|
||||||
parentComponent,
|
parentComponent,
|
||||||
parentSuspense,
|
parentSuspense,
|
||||||
|
slotScopeIds,
|
||||||
optimized
|
optimized
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ import { VNode } from './vnode'
|
|||||||
import { isFunction, EMPTY_OBJ, makeMap } from '@vue/shared'
|
import { isFunction, EMPTY_OBJ, makeMap } from '@vue/shared'
|
||||||
import { warn } from './warning'
|
import { warn } from './warning'
|
||||||
import { ComponentInternalInstance, Data } from './component'
|
import { ComponentInternalInstance, Data } from './component'
|
||||||
import { currentRenderingInstance } from './componentRenderUtils'
|
import { currentRenderingInstance } from './componentRenderContext'
|
||||||
import { callWithAsyncErrorHandling, ErrorCodes } from './errorHandling'
|
import { callWithAsyncErrorHandling, ErrorCodes } from './errorHandling'
|
||||||
import { ComponentPublicInstance } from './componentPublicInstance'
|
import { ComponentPublicInstance } from './componentPublicInstance'
|
||||||
|
|
||||||
|
@ -53,6 +53,10 @@ export function renderSlot(
|
|||||||
? PatchFlags.STABLE_FRAGMENT
|
? PatchFlags.STABLE_FRAGMENT
|
||||||
: PatchFlags.BAIL
|
: PatchFlags.BAIL
|
||||||
)
|
)
|
||||||
|
// TODO (optimization) only add slot scope id if :slotted is used
|
||||||
|
if (rendered.scopeId) {
|
||||||
|
rendered.slotScopeIds = [rendered.scopeId + '-s']
|
||||||
|
}
|
||||||
isRenderingCompiledSlot--
|
isRenderingCompiledSlot--
|
||||||
return rendered
|
return rendered
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import { currentRenderingInstance } from '../componentRenderUtils'
|
|
||||||
import {
|
import {
|
||||||
currentInstance,
|
currentInstance,
|
||||||
ConcreteComponent,
|
ConcreteComponent,
|
||||||
ComponentOptions,
|
ComponentOptions,
|
||||||
getComponentName
|
getComponentName
|
||||||
} from '../component'
|
} from '../component'
|
||||||
|
import { currentRenderingInstance } from '../componentRenderContext'
|
||||||
import { Directive } from '../directives'
|
import { Directive } from '../directives'
|
||||||
import { camelize, capitalize, isString } from '@vue/shared'
|
import { camelize, capitalize, isString } from '@vue/shared'
|
||||||
import { warn } from '../warning'
|
import { warn } from '../warning'
|
||||||
|
@ -1,36 +0,0 @@
|
|||||||
// SFC scoped style ID management.
|
|
||||||
// These are only used in esm-bundler builds, but since exports cannot be
|
|
||||||
// conditional, we can only drop inner implementations in non-bundler builds.
|
|
||||||
|
|
||||||
import { withCtx } from './withRenderContext'
|
|
||||||
|
|
||||||
export let currentScopeId: string | null = null
|
|
||||||
const scopeIdStack: string[] = []
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
export function pushScopeId(id: string) {
|
|
||||||
scopeIdStack.push((currentScopeId = id))
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
export function popScopeId() {
|
|
||||||
scopeIdStack.pop()
|
|
||||||
currentScopeId = scopeIdStack[scopeIdStack.length - 1] || null
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
export function withScopeId(id: string): <T extends Function>(fn: T) => T {
|
|
||||||
return ((fn: Function) =>
|
|
||||||
withCtx(function(this: any) {
|
|
||||||
pushScopeId(id)
|
|
||||||
const res = fn.apply(this, arguments)
|
|
||||||
popScopeId()
|
|
||||||
return res
|
|
||||||
})) as any
|
|
||||||
}
|
|
@ -1,37 +0,0 @@
|
|||||||
import { Slot } from '../componentSlots'
|
|
||||||
import {
|
|
||||||
setCurrentRenderingInstance,
|
|
||||||
currentRenderingInstance
|
|
||||||
} from '../componentRenderUtils'
|
|
||||||
import { ComponentInternalInstance } from '../component'
|
|
||||||
import { isRenderingCompiledSlot } from './renderSlot'
|
|
||||||
import { closeBlock, openBlock } from '../vnode'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wrap a slot function to memoize current rendering instance
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
export function withCtx(
|
|
||||||
fn: Slot,
|
|
||||||
ctx: ComponentInternalInstance | null = currentRenderingInstance
|
|
||||||
) {
|
|
||||||
if (!ctx) return fn
|
|
||||||
const renderFnWithContext = (...args: any[]) => {
|
|
||||||
// If a user calls a compiled slot inside a template expression (#1745), it
|
|
||||||
// can mess up block tracking, so by default we need to push a null block to
|
|
||||||
// avoid that. This isn't necessary if rendering a compiled `<slot>`.
|
|
||||||
if (!isRenderingCompiledSlot) {
|
|
||||||
openBlock(true /* null block that disables tracking */)
|
|
||||||
}
|
|
||||||
const owner = currentRenderingInstance
|
|
||||||
setCurrentRenderingInstance(ctx)
|
|
||||||
const res = fn(...args)
|
|
||||||
setCurrentRenderingInstance(owner)
|
|
||||||
if (!isRenderingCompiledSlot) {
|
|
||||||
closeBlock()
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
renderFnWithContext._c = true
|
|
||||||
return renderFnWithContext
|
|
||||||
}
|
|
@ -63,7 +63,7 @@ export function createHydrationFunctions(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
hasMismatch = false
|
hasMismatch = false
|
||||||
hydrateNode(container.firstChild!, vnode, null, null)
|
hydrateNode(container.firstChild!, vnode, null, null, null)
|
||||||
flushPostFlushCbs()
|
flushPostFlushCbs()
|
||||||
if (hasMismatch && !__TEST__) {
|
if (hasMismatch && !__TEST__) {
|
||||||
// this error should show up in production
|
// this error should show up in production
|
||||||
@ -76,6 +76,7 @@ export function createHydrationFunctions(
|
|||||||
vnode: VNode,
|
vnode: VNode,
|
||||||
parentComponent: ComponentInternalInstance | null,
|
parentComponent: ComponentInternalInstance | null,
|
||||||
parentSuspense: SuspenseBoundary | null,
|
parentSuspense: SuspenseBoundary | null,
|
||||||
|
slotScopeIds: string[] | null,
|
||||||
optimized = false
|
optimized = false
|
||||||
): Node | null => {
|
): Node | null => {
|
||||||
const isFragmentStart = isComment(node) && node.data === '['
|
const isFragmentStart = isComment(node) && node.data === '['
|
||||||
@ -85,6 +86,7 @@ export function createHydrationFunctions(
|
|||||||
vnode,
|
vnode,
|
||||||
parentComponent,
|
parentComponent,
|
||||||
parentSuspense,
|
parentSuspense,
|
||||||
|
slotScopeIds,
|
||||||
isFragmentStart
|
isFragmentStart
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -147,6 +149,7 @@ export function createHydrationFunctions(
|
|||||||
vnode,
|
vnode,
|
||||||
parentComponent,
|
parentComponent,
|
||||||
parentSuspense,
|
parentSuspense,
|
||||||
|
slotScopeIds,
|
||||||
optimized
|
optimized
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -164,6 +167,7 @@ export function createHydrationFunctions(
|
|||||||
vnode,
|
vnode,
|
||||||
parentComponent,
|
parentComponent,
|
||||||
parentSuspense,
|
parentSuspense,
|
||||||
|
slotScopeIds,
|
||||||
optimized
|
optimized
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -171,6 +175,7 @@ export function createHydrationFunctions(
|
|||||||
// when setting up the render effect, if the initial vnode already
|
// when setting up the render effect, if the initial vnode already
|
||||||
// has .el set, the component will perform hydration instead of mount
|
// has .el set, the component will perform hydration instead of mount
|
||||||
// on its sub-tree.
|
// on its sub-tree.
|
||||||
|
vnode.slotScopeIds = slotScopeIds
|
||||||
const container = parentNode(node)!
|
const container = parentNode(node)!
|
||||||
const hydrateComponent = () => {
|
const hydrateComponent = () => {
|
||||||
mountComponent(
|
mountComponent(
|
||||||
@ -205,6 +210,7 @@ export function createHydrationFunctions(
|
|||||||
vnode as TeleportVNode,
|
vnode as TeleportVNode,
|
||||||
parentComponent,
|
parentComponent,
|
||||||
parentSuspense,
|
parentSuspense,
|
||||||
|
slotScopeIds,
|
||||||
optimized,
|
optimized,
|
||||||
rendererInternals,
|
rendererInternals,
|
||||||
hydrateChildren
|
hydrateChildren
|
||||||
@ -217,6 +223,7 @@ export function createHydrationFunctions(
|
|||||||
parentComponent,
|
parentComponent,
|
||||||
parentSuspense,
|
parentSuspense,
|
||||||
isSVGContainer(parentNode(node)!),
|
isSVGContainer(parentNode(node)!),
|
||||||
|
slotScopeIds,
|
||||||
optimized,
|
optimized,
|
||||||
rendererInternals,
|
rendererInternals,
|
||||||
hydrateNode
|
hydrateNode
|
||||||
@ -238,6 +245,7 @@ export function createHydrationFunctions(
|
|||||||
vnode: VNode,
|
vnode: VNode,
|
||||||
parentComponent: ComponentInternalInstance | null,
|
parentComponent: ComponentInternalInstance | null,
|
||||||
parentSuspense: SuspenseBoundary | null,
|
parentSuspense: SuspenseBoundary | null,
|
||||||
|
slotScopeIds: string[] | null,
|
||||||
optimized: boolean
|
optimized: boolean
|
||||||
) => {
|
) => {
|
||||||
optimized = optimized || !!vnode.dynamicChildren
|
optimized = optimized || !!vnode.dynamicChildren
|
||||||
@ -291,6 +299,7 @@ export function createHydrationFunctions(
|
|||||||
el,
|
el,
|
||||||
parentComponent,
|
parentComponent,
|
||||||
parentSuspense,
|
parentSuspense,
|
||||||
|
slotScopeIds,
|
||||||
optimized
|
optimized
|
||||||
)
|
)
|
||||||
let hasWarned = false
|
let hasWarned = false
|
||||||
@ -330,6 +339,7 @@ export function createHydrationFunctions(
|
|||||||
container: Element,
|
container: Element,
|
||||||
parentComponent: ComponentInternalInstance | null,
|
parentComponent: ComponentInternalInstance | null,
|
||||||
parentSuspense: SuspenseBoundary | null,
|
parentSuspense: SuspenseBoundary | null,
|
||||||
|
slotScopeIds: string[] | null,
|
||||||
optimized: boolean
|
optimized: boolean
|
||||||
): Node | null => {
|
): Node | null => {
|
||||||
optimized = optimized || !!parentVNode.dynamicChildren
|
optimized = optimized || !!parentVNode.dynamicChildren
|
||||||
@ -346,6 +356,7 @@ export function createHydrationFunctions(
|
|||||||
vnode,
|
vnode,
|
||||||
parentComponent,
|
parentComponent,
|
||||||
parentSuspense,
|
parentSuspense,
|
||||||
|
slotScopeIds,
|
||||||
optimized
|
optimized
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
@ -365,7 +376,8 @@ export function createHydrationFunctions(
|
|||||||
null,
|
null,
|
||||||
parentComponent,
|
parentComponent,
|
||||||
parentSuspense,
|
parentSuspense,
|
||||||
isSVGContainer(container)
|
isSVGContainer(container),
|
||||||
|
slotScopeIds
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -377,8 +389,16 @@ export function createHydrationFunctions(
|
|||||||
vnode: VNode,
|
vnode: VNode,
|
||||||
parentComponent: ComponentInternalInstance | null,
|
parentComponent: ComponentInternalInstance | null,
|
||||||
parentSuspense: SuspenseBoundary | null,
|
parentSuspense: SuspenseBoundary | null,
|
||||||
|
slotScopeIds: string[] | null,
|
||||||
optimized: boolean
|
optimized: boolean
|
||||||
) => {
|
) => {
|
||||||
|
const { slotScopeIds: fragmentSlotScopeIds } = vnode
|
||||||
|
if (fragmentSlotScopeIds) {
|
||||||
|
slotScopeIds = slotScopeIds
|
||||||
|
? slotScopeIds.concat(fragmentSlotScopeIds)
|
||||||
|
: fragmentSlotScopeIds
|
||||||
|
}
|
||||||
|
|
||||||
const container = parentNode(node)!
|
const container = parentNode(node)!
|
||||||
const next = hydrateChildren(
|
const next = hydrateChildren(
|
||||||
nextSibling(node)!,
|
nextSibling(node)!,
|
||||||
@ -386,6 +406,7 @@ export function createHydrationFunctions(
|
|||||||
container,
|
container,
|
||||||
parentComponent,
|
parentComponent,
|
||||||
parentSuspense,
|
parentSuspense,
|
||||||
|
slotScopeIds,
|
||||||
optimized
|
optimized
|
||||||
)
|
)
|
||||||
if (next && isComment(next) && next.data === ']') {
|
if (next && isComment(next) && next.data === ']') {
|
||||||
@ -405,6 +426,7 @@ export function createHydrationFunctions(
|
|||||||
vnode: VNode,
|
vnode: VNode,
|
||||||
parentComponent: ComponentInternalInstance | null,
|
parentComponent: ComponentInternalInstance | null,
|
||||||
parentSuspense: SuspenseBoundary | null,
|
parentSuspense: SuspenseBoundary | null,
|
||||||
|
slotScopeIds: string[] | null,
|
||||||
isFragment: boolean
|
isFragment: boolean
|
||||||
): Node | null => {
|
): Node | null => {
|
||||||
hasMismatch = true
|
hasMismatch = true
|
||||||
@ -446,7 +468,8 @@ export function createHydrationFunctions(
|
|||||||
next,
|
next,
|
||||||
parentComponent,
|
parentComponent,
|
||||||
parentSuspense,
|
parentSuspense,
|
||||||
isSVGContainer(container)
|
isSVGContainer(container),
|
||||||
|
slotScopeIds
|
||||||
)
|
)
|
||||||
return next
|
return next
|
||||||
}
|
}
|
||||||
|
@ -227,12 +227,11 @@ export { HMRRuntime } from './hmr'
|
|||||||
|
|
||||||
// For compiler generated code
|
// For compiler generated code
|
||||||
// should sync with '@vue/compiler-core/src/runtimeConstants.ts'
|
// should sync with '@vue/compiler-core/src/runtimeConstants.ts'
|
||||||
export { withCtx } from './helpers/withRenderContext'
|
export { withCtx, setScopeId } from './componentRenderContext'
|
||||||
export { renderList } from './helpers/renderList'
|
export { renderList } from './helpers/renderList'
|
||||||
export { toHandlers } from './helpers/toHandlers'
|
export { toHandlers } from './helpers/toHandlers'
|
||||||
export { renderSlot } from './helpers/renderSlot'
|
export { renderSlot } from './helpers/renderSlot'
|
||||||
export { createSlots } from './helpers/createSlots'
|
export { createSlots } from './helpers/createSlots'
|
||||||
export { pushScopeId, popScopeId, withScopeId } from './helpers/scopeId'
|
|
||||||
export {
|
export {
|
||||||
openBlock,
|
openBlock,
|
||||||
createBlock,
|
createBlock,
|
||||||
@ -257,10 +256,8 @@ export { transformVNodeArgs } from './vnode'
|
|||||||
// change without notice between versions. User code should never rely on them.
|
// change without notice between versions. User code should never rely on them.
|
||||||
|
|
||||||
import { createComponentInstance, setupComponent } from './component'
|
import { createComponentInstance, setupComponent } from './component'
|
||||||
import {
|
import { renderComponentRoot } from './componentRenderUtils'
|
||||||
renderComponentRoot,
|
import { setCurrentRenderingInstance } from './componentRenderContext'
|
||||||
setCurrentRenderingInstance
|
|
||||||
} from './componentRenderUtils'
|
|
||||||
import { isVNode, normalizeVNode } from './vnode'
|
import { isVNode, normalizeVNode } from './vnode'
|
||||||
|
|
||||||
const _ssrUtils = {
|
const _ssrUtils = {
|
||||||
|
@ -177,6 +177,7 @@ type PatchFn = (
|
|||||||
parentComponent?: ComponentInternalInstance | null,
|
parentComponent?: ComponentInternalInstance | null,
|
||||||
parentSuspense?: SuspenseBoundary | null,
|
parentSuspense?: SuspenseBoundary | null,
|
||||||
isSVG?: boolean,
|
isSVG?: boolean,
|
||||||
|
slotScopeIds?: string[] | null,
|
||||||
optimized?: boolean
|
optimized?: boolean
|
||||||
) => void
|
) => void
|
||||||
|
|
||||||
@ -187,6 +188,7 @@ type MountChildrenFn = (
|
|||||||
parentComponent: ComponentInternalInstance | null,
|
parentComponent: ComponentInternalInstance | null,
|
||||||
parentSuspense: SuspenseBoundary | null,
|
parentSuspense: SuspenseBoundary | null,
|
||||||
isSVG: boolean,
|
isSVG: boolean,
|
||||||
|
slotScopeIds: string[] | null,
|
||||||
optimized: boolean,
|
optimized: boolean,
|
||||||
start?: number
|
start?: number
|
||||||
) => void
|
) => void
|
||||||
@ -199,7 +201,8 @@ type PatchChildrenFn = (
|
|||||||
parentComponent: ComponentInternalInstance | null,
|
parentComponent: ComponentInternalInstance | null,
|
||||||
parentSuspense: SuspenseBoundary | null,
|
parentSuspense: SuspenseBoundary | null,
|
||||||
isSVG: boolean,
|
isSVG: boolean,
|
||||||
optimized?: boolean
|
slotScopeIds: string[] | null,
|
||||||
|
optimized: boolean
|
||||||
) => void
|
) => void
|
||||||
|
|
||||||
type PatchBlockChildrenFn = (
|
type PatchBlockChildrenFn = (
|
||||||
@ -208,7 +211,8 @@ type PatchBlockChildrenFn = (
|
|||||||
fallbackContainer: RendererElement,
|
fallbackContainer: RendererElement,
|
||||||
parentComponent: ComponentInternalInstance | null,
|
parentComponent: ComponentInternalInstance | null,
|
||||||
parentSuspense: SuspenseBoundary | null,
|
parentSuspense: SuspenseBoundary | null,
|
||||||
isSVG: boolean
|
isSVG: boolean,
|
||||||
|
slotScopeIds: string[] | null
|
||||||
) => void
|
) => void
|
||||||
|
|
||||||
type MoveFn = (
|
type MoveFn = (
|
||||||
@ -469,6 +473,7 @@ function baseCreateRenderer(
|
|||||||
parentComponent = null,
|
parentComponent = null,
|
||||||
parentSuspense = null,
|
parentSuspense = null,
|
||||||
isSVG = false,
|
isSVG = false,
|
||||||
|
slotScopeIds = null,
|
||||||
optimized = false
|
optimized = false
|
||||||
) => {
|
) => {
|
||||||
// patching & not same type, unmount old tree
|
// patching & not same type, unmount old tree
|
||||||
@ -507,6 +512,7 @@ function baseCreateRenderer(
|
|||||||
parentComponent,
|
parentComponent,
|
||||||
parentSuspense,
|
parentSuspense,
|
||||||
isSVG,
|
isSVG,
|
||||||
|
slotScopeIds,
|
||||||
optimized
|
optimized
|
||||||
)
|
)
|
||||||
break
|
break
|
||||||
@ -520,6 +526,7 @@ function baseCreateRenderer(
|
|||||||
parentComponent,
|
parentComponent,
|
||||||
parentSuspense,
|
parentSuspense,
|
||||||
isSVG,
|
isSVG,
|
||||||
|
slotScopeIds,
|
||||||
optimized
|
optimized
|
||||||
)
|
)
|
||||||
} else if (shapeFlag & ShapeFlags.COMPONENT) {
|
} else if (shapeFlag & ShapeFlags.COMPONENT) {
|
||||||
@ -531,6 +538,7 @@ function baseCreateRenderer(
|
|||||||
parentComponent,
|
parentComponent,
|
||||||
parentSuspense,
|
parentSuspense,
|
||||||
isSVG,
|
isSVG,
|
||||||
|
slotScopeIds,
|
||||||
optimized
|
optimized
|
||||||
)
|
)
|
||||||
} else if (shapeFlag & ShapeFlags.TELEPORT) {
|
} else if (shapeFlag & ShapeFlags.TELEPORT) {
|
||||||
@ -542,6 +550,7 @@ function baseCreateRenderer(
|
|||||||
parentComponent,
|
parentComponent,
|
||||||
parentSuspense,
|
parentSuspense,
|
||||||
isSVG,
|
isSVG,
|
||||||
|
slotScopeIds,
|
||||||
optimized,
|
optimized,
|
||||||
internals
|
internals
|
||||||
)
|
)
|
||||||
@ -554,6 +563,7 @@ function baseCreateRenderer(
|
|||||||
parentComponent,
|
parentComponent,
|
||||||
parentSuspense,
|
parentSuspense,
|
||||||
isSVG,
|
isSVG,
|
||||||
|
slotScopeIds,
|
||||||
optimized,
|
optimized,
|
||||||
internals
|
internals
|
||||||
)
|
)
|
||||||
@ -676,6 +686,7 @@ function baseCreateRenderer(
|
|||||||
parentComponent: ComponentInternalInstance | null,
|
parentComponent: ComponentInternalInstance | null,
|
||||||
parentSuspense: SuspenseBoundary | null,
|
parentSuspense: SuspenseBoundary | null,
|
||||||
isSVG: boolean,
|
isSVG: boolean,
|
||||||
|
slotScopeIds: string[] | null,
|
||||||
optimized: boolean
|
optimized: boolean
|
||||||
) => {
|
) => {
|
||||||
isSVG = isSVG || (n2.type as string) === 'svg'
|
isSVG = isSVG || (n2.type as string) === 'svg'
|
||||||
@ -687,10 +698,19 @@ function baseCreateRenderer(
|
|||||||
parentComponent,
|
parentComponent,
|
||||||
parentSuspense,
|
parentSuspense,
|
||||||
isSVG,
|
isSVG,
|
||||||
|
slotScopeIds,
|
||||||
optimized
|
optimized
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
patchElement(n1, n2, parentComponent, parentSuspense, isSVG, optimized)
|
patchElement(
|
||||||
|
n1,
|
||||||
|
n2,
|
||||||
|
parentComponent,
|
||||||
|
parentSuspense,
|
||||||
|
isSVG,
|
||||||
|
slotScopeIds,
|
||||||
|
optimized
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -701,19 +721,12 @@ function baseCreateRenderer(
|
|||||||
parentComponent: ComponentInternalInstance | null,
|
parentComponent: ComponentInternalInstance | null,
|
||||||
parentSuspense: SuspenseBoundary | null,
|
parentSuspense: SuspenseBoundary | null,
|
||||||
isSVG: boolean,
|
isSVG: boolean,
|
||||||
|
slotScopeIds: string[] | null,
|
||||||
optimized: boolean
|
optimized: boolean
|
||||||
) => {
|
) => {
|
||||||
let el: RendererElement
|
let el: RendererElement
|
||||||
let vnodeHook: VNodeHook | undefined | null
|
let vnodeHook: VNodeHook | undefined | null
|
||||||
const {
|
const { type, props, shapeFlag, transition, patchFlag, dirs } = vnode
|
||||||
type,
|
|
||||||
props,
|
|
||||||
shapeFlag,
|
|
||||||
transition,
|
|
||||||
scopeId,
|
|
||||||
patchFlag,
|
|
||||||
dirs
|
|
||||||
} = vnode
|
|
||||||
if (
|
if (
|
||||||
!__DEV__ &&
|
!__DEV__ &&
|
||||||
vnode.el &&
|
vnode.el &&
|
||||||
@ -744,6 +757,7 @@ function baseCreateRenderer(
|
|||||||
parentComponent,
|
parentComponent,
|
||||||
parentSuspense,
|
parentSuspense,
|
||||||
isSVG && type !== 'foreignObject',
|
isSVG && type !== 'foreignObject',
|
||||||
|
slotScopeIds,
|
||||||
optimized || !!vnode.dynamicChildren
|
optimized || !!vnode.dynamicChildren
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -773,7 +787,7 @@ function baseCreateRenderer(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// scopeId
|
// scopeId
|
||||||
setScopeId(el, scopeId, vnode, parentComponent)
|
setScopeId(el, vnode, vnode.scopeId, slotScopeIds, parentComponent)
|
||||||
}
|
}
|
||||||
if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {
|
if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {
|
||||||
Object.defineProperty(el, '__vnode', {
|
Object.defineProperty(el, '__vnode', {
|
||||||
@ -813,30 +827,32 @@ function baseCreateRenderer(
|
|||||||
|
|
||||||
const setScopeId = (
|
const setScopeId = (
|
||||||
el: RendererElement,
|
el: RendererElement,
|
||||||
scopeId: string | false | null,
|
|
||||||
vnode: VNode,
|
vnode: VNode,
|
||||||
|
scopeId: string | null,
|
||||||
|
slotScopeIds: string[] | null,
|
||||||
parentComponent: ComponentInternalInstance | null
|
parentComponent: ComponentInternalInstance | null
|
||||||
) => {
|
) => {
|
||||||
if (scopeId) {
|
if (scopeId) {
|
||||||
hostSetScopeId(el, scopeId)
|
hostSetScopeId(el, scopeId)
|
||||||
}
|
}
|
||||||
if (parentComponent) {
|
if (slotScopeIds) {
|
||||||
const treeOwnerId = parentComponent.type.__scopeId
|
for (let i = 0; i < slotScopeIds.length; i++) {
|
||||||
// vnode's own scopeId and the current patched component's scopeId is
|
hostSetScopeId(el, slotScopeIds[i])
|
||||||
// different - this is a slot content node.
|
|
||||||
if (treeOwnerId && treeOwnerId !== scopeId) {
|
|
||||||
hostSetScopeId(el, treeOwnerId + '-s')
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (parentComponent) {
|
||||||
let subTree = parentComponent.subTree
|
let subTree = parentComponent.subTree
|
||||||
if (__DEV__ && subTree.type === Fragment) {
|
if (__DEV__ && subTree.patchFlag & PatchFlags.DEV_ROOT_FRAGMENT) {
|
||||||
subTree =
|
subTree =
|
||||||
filterSingleRoot(subTree.children as VNodeArrayChildren) || subTree
|
filterSingleRoot(subTree.children as VNodeArrayChildren) || subTree
|
||||||
}
|
}
|
||||||
if (vnode === subTree) {
|
if (vnode === subTree) {
|
||||||
|
const parentVNode = parentComponent.vnode
|
||||||
setScopeId(
|
setScopeId(
|
||||||
el,
|
el,
|
||||||
parentComponent.vnode.scopeId,
|
parentVNode,
|
||||||
parentComponent.vnode,
|
parentVNode.scopeId,
|
||||||
|
parentVNode.slotScopeIds,
|
||||||
parentComponent.parent
|
parentComponent.parent
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -851,6 +867,7 @@ function baseCreateRenderer(
|
|||||||
parentSuspense,
|
parentSuspense,
|
||||||
isSVG,
|
isSVG,
|
||||||
optimized,
|
optimized,
|
||||||
|
slotScopeIds,
|
||||||
start = 0
|
start = 0
|
||||||
) => {
|
) => {
|
||||||
for (let i = start; i < children.length; i++) {
|
for (let i = start; i < children.length; i++) {
|
||||||
@ -865,7 +882,8 @@ function baseCreateRenderer(
|
|||||||
parentComponent,
|
parentComponent,
|
||||||
parentSuspense,
|
parentSuspense,
|
||||||
isSVG,
|
isSVG,
|
||||||
optimized
|
optimized,
|
||||||
|
slotScopeIds
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -876,6 +894,7 @@ function baseCreateRenderer(
|
|||||||
parentComponent: ComponentInternalInstance | null,
|
parentComponent: ComponentInternalInstance | null,
|
||||||
parentSuspense: SuspenseBoundary | null,
|
parentSuspense: SuspenseBoundary | null,
|
||||||
isSVG: boolean,
|
isSVG: boolean,
|
||||||
|
slotScopeIds: string[] | null,
|
||||||
optimized: boolean
|
optimized: boolean
|
||||||
) => {
|
) => {
|
||||||
const el = (n2.el = n1.el!)
|
const el = (n2.el = n1.el!)
|
||||||
@ -993,7 +1012,8 @@ function baseCreateRenderer(
|
|||||||
el,
|
el,
|
||||||
parentComponent,
|
parentComponent,
|
||||||
parentSuspense,
|
parentSuspense,
|
||||||
areChildrenSVG
|
areChildrenSVG,
|
||||||
|
slotScopeIds
|
||||||
)
|
)
|
||||||
if (__DEV__ && parentComponent && parentComponent.type.__hmrId) {
|
if (__DEV__ && parentComponent && parentComponent.type.__hmrId) {
|
||||||
traverseStaticChildren(n1, n2)
|
traverseStaticChildren(n1, n2)
|
||||||
@ -1007,7 +1027,9 @@ function baseCreateRenderer(
|
|||||||
null,
|
null,
|
||||||
parentComponent,
|
parentComponent,
|
||||||
parentSuspense,
|
parentSuspense,
|
||||||
areChildrenSVG
|
areChildrenSVG,
|
||||||
|
slotScopeIds,
|
||||||
|
false
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1026,7 +1048,8 @@ function baseCreateRenderer(
|
|||||||
fallbackContainer,
|
fallbackContainer,
|
||||||
parentComponent,
|
parentComponent,
|
||||||
parentSuspense,
|
parentSuspense,
|
||||||
isSVG
|
isSVG,
|
||||||
|
slotScopeIds
|
||||||
) => {
|
) => {
|
||||||
for (let i = 0; i < newChildren.length; i++) {
|
for (let i = 0; i < newChildren.length; i++) {
|
||||||
const oldVNode = oldChildren[i]
|
const oldVNode = oldChildren[i]
|
||||||
@ -1054,6 +1077,7 @@ function baseCreateRenderer(
|
|||||||
parentComponent,
|
parentComponent,
|
||||||
parentSuspense,
|
parentSuspense,
|
||||||
isSVG,
|
isSVG,
|
||||||
|
slotScopeIds,
|
||||||
true
|
true
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -1119,16 +1143,24 @@ function baseCreateRenderer(
|
|||||||
parentComponent: ComponentInternalInstance | null,
|
parentComponent: ComponentInternalInstance | null,
|
||||||
parentSuspense: SuspenseBoundary | null,
|
parentSuspense: SuspenseBoundary | null,
|
||||||
isSVG: boolean,
|
isSVG: boolean,
|
||||||
|
slotScopeIds: string[] | null,
|
||||||
optimized: boolean
|
optimized: boolean
|
||||||
) => {
|
) => {
|
||||||
const fragmentStartAnchor = (n2.el = n1 ? n1.el : hostCreateText(''))!
|
const fragmentStartAnchor = (n2.el = n1 ? n1.el : hostCreateText(''))!
|
||||||
const fragmentEndAnchor = (n2.anchor = n1 ? n1.anchor : hostCreateText(''))!
|
const fragmentEndAnchor = (n2.anchor = n1 ? n1.anchor : hostCreateText(''))!
|
||||||
|
|
||||||
let { patchFlag, dynamicChildren } = n2
|
let { patchFlag, dynamicChildren, slotScopeIds: fragmentSlotScopeIds } = n2
|
||||||
if (patchFlag > 0) {
|
if (patchFlag > 0) {
|
||||||
optimized = true
|
optimized = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check if this is a slot fragment with :slotted scope ids
|
||||||
|
if (fragmentSlotScopeIds) {
|
||||||
|
slotScopeIds = slotScopeIds
|
||||||
|
? slotScopeIds.concat(fragmentSlotScopeIds)
|
||||||
|
: fragmentSlotScopeIds
|
||||||
|
}
|
||||||
|
|
||||||
if (__DEV__ && isHmrUpdating) {
|
if (__DEV__ && isHmrUpdating) {
|
||||||
// HMR updated, force full diff
|
// HMR updated, force full diff
|
||||||
patchFlag = 0
|
patchFlag = 0
|
||||||
@ -1149,6 +1181,7 @@ function baseCreateRenderer(
|
|||||||
parentComponent,
|
parentComponent,
|
||||||
parentSuspense,
|
parentSuspense,
|
||||||
isSVG,
|
isSVG,
|
||||||
|
slotScopeIds,
|
||||||
optimized
|
optimized
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
@ -1168,7 +1201,8 @@ function baseCreateRenderer(
|
|||||||
container,
|
container,
|
||||||
parentComponent,
|
parentComponent,
|
||||||
parentSuspense,
|
parentSuspense,
|
||||||
isSVG
|
isSVG,
|
||||||
|
slotScopeIds
|
||||||
)
|
)
|
||||||
if (__DEV__ && parentComponent && parentComponent.type.__hmrId) {
|
if (__DEV__ && parentComponent && parentComponent.type.__hmrId) {
|
||||||
traverseStaticChildren(n1, n2)
|
traverseStaticChildren(n1, n2)
|
||||||
@ -1195,6 +1229,7 @@ function baseCreateRenderer(
|
|||||||
parentComponent,
|
parentComponent,
|
||||||
parentSuspense,
|
parentSuspense,
|
||||||
isSVG,
|
isSVG,
|
||||||
|
slotScopeIds,
|
||||||
optimized
|
optimized
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -1209,8 +1244,10 @@ function baseCreateRenderer(
|
|||||||
parentComponent: ComponentInternalInstance | null,
|
parentComponent: ComponentInternalInstance | null,
|
||||||
parentSuspense: SuspenseBoundary | null,
|
parentSuspense: SuspenseBoundary | null,
|
||||||
isSVG: boolean,
|
isSVG: boolean,
|
||||||
|
slotScopeIds: string[] | null,
|
||||||
optimized: boolean
|
optimized: boolean
|
||||||
) => {
|
) => {
|
||||||
|
n2.slotScopeIds = slotScopeIds
|
||||||
if (n1 == null) {
|
if (n1 == null) {
|
||||||
if (n2.shapeFlag & ShapeFlags.COMPONENT_KEPT_ALIVE) {
|
if (n2.shapeFlag & ShapeFlags.COMPONENT_KEPT_ALIVE) {
|
||||||
;(parentComponent!.ctx as KeepAliveContext).activate(
|
;(parentComponent!.ctx as KeepAliveContext).activate(
|
||||||
@ -1382,7 +1419,8 @@ function baseCreateRenderer(
|
|||||||
initialVNode.el as Node,
|
initialVNode.el as Node,
|
||||||
subTree,
|
subTree,
|
||||||
instance,
|
instance,
|
||||||
parentSuspense
|
parentSuspense,
|
||||||
|
null
|
||||||
)
|
)
|
||||||
if (__DEV__) {
|
if (__DEV__) {
|
||||||
endMeasure(instance, `hydrate`)
|
endMeasure(instance, `hydrate`)
|
||||||
@ -1543,6 +1581,7 @@ function baseCreateRenderer(
|
|||||||
parentComponent,
|
parentComponent,
|
||||||
parentSuspense,
|
parentSuspense,
|
||||||
isSVG,
|
isSVG,
|
||||||
|
slotScopeIds,
|
||||||
optimized = false
|
optimized = false
|
||||||
) => {
|
) => {
|
||||||
const c1 = n1 && n1.children
|
const c1 = n1 && n1.children
|
||||||
@ -1563,6 +1602,7 @@ function baseCreateRenderer(
|
|||||||
parentComponent,
|
parentComponent,
|
||||||
parentSuspense,
|
parentSuspense,
|
||||||
isSVG,
|
isSVG,
|
||||||
|
slotScopeIds,
|
||||||
optimized
|
optimized
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
@ -1576,6 +1616,7 @@ function baseCreateRenderer(
|
|||||||
parentComponent,
|
parentComponent,
|
||||||
parentSuspense,
|
parentSuspense,
|
||||||
isSVG,
|
isSVG,
|
||||||
|
slotScopeIds,
|
||||||
optimized
|
optimized
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
@ -1604,6 +1645,7 @@ function baseCreateRenderer(
|
|||||||
parentComponent,
|
parentComponent,
|
||||||
parentSuspense,
|
parentSuspense,
|
||||||
isSVG,
|
isSVG,
|
||||||
|
slotScopeIds,
|
||||||
optimized
|
optimized
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
@ -1625,6 +1667,7 @@ function baseCreateRenderer(
|
|||||||
parentComponent,
|
parentComponent,
|
||||||
parentSuspense,
|
parentSuspense,
|
||||||
isSVG,
|
isSVG,
|
||||||
|
slotScopeIds,
|
||||||
optimized
|
optimized
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -1640,6 +1683,7 @@ function baseCreateRenderer(
|
|||||||
parentComponent: ComponentInternalInstance | null,
|
parentComponent: ComponentInternalInstance | null,
|
||||||
parentSuspense: SuspenseBoundary | null,
|
parentSuspense: SuspenseBoundary | null,
|
||||||
isSVG: boolean,
|
isSVG: boolean,
|
||||||
|
slotScopeIds: string[] | null,
|
||||||
optimized: boolean
|
optimized: boolean
|
||||||
) => {
|
) => {
|
||||||
c1 = c1 || EMPTY_ARR
|
c1 = c1 || EMPTY_ARR
|
||||||
@ -1660,6 +1704,7 @@ function baseCreateRenderer(
|
|||||||
parentComponent,
|
parentComponent,
|
||||||
parentSuspense,
|
parentSuspense,
|
||||||
isSVG,
|
isSVG,
|
||||||
|
slotScopeIds,
|
||||||
optimized
|
optimized
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -1682,6 +1727,7 @@ function baseCreateRenderer(
|
|||||||
parentComponent,
|
parentComponent,
|
||||||
parentSuspense,
|
parentSuspense,
|
||||||
isSVG,
|
isSVG,
|
||||||
|
slotScopeIds,
|
||||||
optimized,
|
optimized,
|
||||||
commonLength
|
commonLength
|
||||||
)
|
)
|
||||||
@ -1697,6 +1743,7 @@ function baseCreateRenderer(
|
|||||||
parentComponent: ComponentInternalInstance | null,
|
parentComponent: ComponentInternalInstance | null,
|
||||||
parentSuspense: SuspenseBoundary | null,
|
parentSuspense: SuspenseBoundary | null,
|
||||||
isSVG: boolean,
|
isSVG: boolean,
|
||||||
|
slotScopeIds: string[] | null,
|
||||||
optimized: boolean
|
optimized: boolean
|
||||||
) => {
|
) => {
|
||||||
let i = 0
|
let i = 0
|
||||||
@ -1721,6 +1768,7 @@ function baseCreateRenderer(
|
|||||||
parentComponent,
|
parentComponent,
|
||||||
parentSuspense,
|
parentSuspense,
|
||||||
isSVG,
|
isSVG,
|
||||||
|
slotScopeIds,
|
||||||
optimized
|
optimized
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
@ -1746,6 +1794,7 @@ function baseCreateRenderer(
|
|||||||
parentComponent,
|
parentComponent,
|
||||||
parentSuspense,
|
parentSuspense,
|
||||||
isSVG,
|
isSVG,
|
||||||
|
slotScopeIds,
|
||||||
optimized
|
optimized
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
@ -1776,7 +1825,9 @@ function baseCreateRenderer(
|
|||||||
anchor,
|
anchor,
|
||||||
parentComponent,
|
parentComponent,
|
||||||
parentSuspense,
|
parentSuspense,
|
||||||
isSVG
|
isSVG,
|
||||||
|
slotScopeIds,
|
||||||
|
optimized
|
||||||
)
|
)
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
@ -1878,6 +1929,7 @@ function baseCreateRenderer(
|
|||||||
parentComponent,
|
parentComponent,
|
||||||
parentSuspense,
|
parentSuspense,
|
||||||
isSVG,
|
isSVG,
|
||||||
|
slotScopeIds,
|
||||||
optimized
|
optimized
|
||||||
)
|
)
|
||||||
patched++
|
patched++
|
||||||
@ -1905,7 +1957,9 @@ function baseCreateRenderer(
|
|||||||
anchor,
|
anchor,
|
||||||
parentComponent,
|
parentComponent,
|
||||||
parentSuspense,
|
parentSuspense,
|
||||||
isSVG
|
isSVG,
|
||||||
|
slotScopeIds,
|
||||||
|
optimized
|
||||||
)
|
)
|
||||||
} else if (moved) {
|
} else if (moved) {
|
||||||
// move if:
|
// move if:
|
||||||
|
@ -32,9 +32,11 @@ import {
|
|||||||
import { DirectiveBinding } from './directives'
|
import { DirectiveBinding } from './directives'
|
||||||
import { TransitionHooks } from './components/BaseTransition'
|
import { TransitionHooks } from './components/BaseTransition'
|
||||||
import { warn } from './warning'
|
import { warn } from './warning'
|
||||||
import { currentScopeId } from './helpers/scopeId'
|
|
||||||
import { TeleportImpl, isTeleport } from './components/Teleport'
|
import { TeleportImpl, isTeleport } from './components/Teleport'
|
||||||
import { currentRenderingInstance } from './componentRenderUtils'
|
import {
|
||||||
|
currentRenderingInstance,
|
||||||
|
currentScopeId
|
||||||
|
} from './componentRenderContext'
|
||||||
import { RendererNode, RendererElement } from './renderer'
|
import { RendererNode, RendererElement } from './renderer'
|
||||||
import { NULL_DYNAMIC_COMPONENT } from './helpers/resolveAssets'
|
import { NULL_DYNAMIC_COMPONENT } from './helpers/resolveAssets'
|
||||||
import { hmrDirtyComponents } from './hmr'
|
import { hmrDirtyComponents } from './hmr'
|
||||||
@ -133,7 +135,18 @@ export interface VNode<
|
|||||||
props: (VNodeProps & ExtraProps) | null
|
props: (VNodeProps & ExtraProps) | null
|
||||||
key: string | number | null
|
key: string | number | null
|
||||||
ref: VNodeNormalizedRef | null
|
ref: VNodeNormalizedRef | null
|
||||||
scopeId: string | null // SFC only
|
/**
|
||||||
|
* SFC only. This is assigned on vnode creation using currentScopeId
|
||||||
|
* which is set alongside currentRenderingInstance.
|
||||||
|
*/
|
||||||
|
scopeId: string | null
|
||||||
|
/**
|
||||||
|
* SFC only. This is assigned to:
|
||||||
|
* - Slot fragment vnodes with :slotted SFC styles.
|
||||||
|
* - Component vnodes (during patch/hydration) so that its root node can
|
||||||
|
* inherit the component's slotScopeIds
|
||||||
|
*/
|
||||||
|
slotScopeIds: string[] | null
|
||||||
children: VNodeNormalizedChildren
|
children: VNodeNormalizedChildren
|
||||||
component: ComponentInternalInstance | null
|
component: ComponentInternalInstance | null
|
||||||
dirs: DirectiveBinding[] | null
|
dirs: DirectiveBinding[] | null
|
||||||
@ -398,6 +411,7 @@ function _createVNode(
|
|||||||
key: props && normalizeKey(props),
|
key: props && normalizeKey(props),
|
||||||
ref: props && normalizeRef(props),
|
ref: props && normalizeRef(props),
|
||||||
scopeId: currentScopeId,
|
scopeId: currentScopeId,
|
||||||
|
slotScopeIds: null,
|
||||||
children: null,
|
children: null,
|
||||||
component: null,
|
component: null,
|
||||||
suspense: null,
|
suspense: null,
|
||||||
@ -479,6 +493,7 @@ export function cloneVNode<T, U>(
|
|||||||
: normalizeRef(extraProps)
|
: normalizeRef(extraProps)
|
||||||
: ref,
|
: ref,
|
||||||
scopeId: vnode.scopeId,
|
scopeId: vnode.scopeId,
|
||||||
|
slotScopeIds: vnode.slotScopeIds,
|
||||||
children:
|
children:
|
||||||
__DEV__ && patchFlag === PatchFlags.HOISTED && isArray(children)
|
__DEV__ && patchFlag === PatchFlags.HOISTED && isArray(children)
|
||||||
? (children as VNode[]).map(deepCloneVNode)
|
? (children as VNode[]).map(deepCloneVNode)
|
||||||
|
@ -2,13 +2,13 @@ import {
|
|||||||
createApp,
|
createApp,
|
||||||
h,
|
h,
|
||||||
createCommentVNode,
|
createCommentVNode,
|
||||||
withScopeId,
|
|
||||||
resolveComponent,
|
resolveComponent,
|
||||||
ComponentOptions,
|
ComponentOptions,
|
||||||
ref,
|
ref,
|
||||||
defineComponent,
|
defineComponent,
|
||||||
createTextVNode,
|
createTextVNode,
|
||||||
createStaticVNode
|
createStaticVNode,
|
||||||
|
withCtx
|
||||||
} from 'vue'
|
} from 'vue'
|
||||||
import { escapeHtml } from '@vue/shared'
|
import { escapeHtml } from '@vue/shared'
|
||||||
import { renderToString } from '../src/renderToString'
|
import { renderToString } from '../src/renderToString'
|
||||||
@ -634,34 +634,32 @@ function testRender(type: string, render: typeof renderToString) {
|
|||||||
describe('scopeId', () => {
|
describe('scopeId', () => {
|
||||||
// note: here we are only testing scopeId handling for vdom serialization.
|
// note: here we are only testing scopeId handling for vdom serialization.
|
||||||
// compiled srr render functions will include scopeId directly in strings.
|
// compiled srr render functions will include scopeId directly in strings.
|
||||||
const withId = withScopeId('data-v-test')
|
|
||||||
const withChildId = withScopeId('data-v-child')
|
|
||||||
|
|
||||||
test('basic', async () => {
|
test('basic', async () => {
|
||||||
expect(
|
const Foo = {
|
||||||
await render(
|
__scopeId: 'data-v-test',
|
||||||
withId(() => {
|
render() {
|
||||||
return h('div')
|
return h('div')
|
||||||
})()
|
}
|
||||||
)
|
}
|
||||||
).toBe(`<div data-v-test></div>`)
|
expect(await render(h(Foo))).toBe(`<div data-v-test></div>`)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('with slots', async () => {
|
test('with slots', async () => {
|
||||||
const Child = {
|
const Child = {
|
||||||
__scopeId: 'data-v-child',
|
__scopeId: 'data-v-child',
|
||||||
render: withChildId(function(this: any) {
|
render: function(this: any) {
|
||||||
return h('div', this.$slots.default())
|
return h('div', this.$slots.default())
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const Parent = {
|
const Parent = {
|
||||||
__scopeId: 'data-v-test',
|
__scopeId: 'data-v-test',
|
||||||
render: withId(() => {
|
render: () => {
|
||||||
return h(Child, null, {
|
return h(Child, null, {
|
||||||
default: withId(() => h('span', 'slot'))
|
default: withCtx(() => h('span', 'slot'))
|
||||||
})
|
})
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
expect(await render(h(Parent))).toBe(
|
expect(await render(h(Parent))).toBe(
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
import { createApp, withScopeId } from 'vue'
|
import { createApp, mergeProps, withCtx } from 'vue'
|
||||||
import { renderToString } from '../src/renderToString'
|
import { renderToString } from '../src/renderToString'
|
||||||
import { ssrRenderComponent, ssrRenderAttrs, ssrRenderSlot } from '../src'
|
import { ssrRenderComponent, ssrRenderAttrs, ssrRenderSlot } from '../src'
|
||||||
|
|
||||||
describe('ssr: scoped id on component root', () => {
|
describe('ssr: scopedId runtime behavior', () => {
|
||||||
test('basic', async () => {
|
test('id on component root', async () => {
|
||||||
const withParentId = withScopeId('parent')
|
|
||||||
|
|
||||||
const Child = {
|
const Child = {
|
||||||
ssrRender: (ctx: any, push: any, parent: any, attrs: any) => {
|
ssrRender: (ctx: any, push: any, parent: any, attrs: any) => {
|
||||||
push(`<div${ssrRenderAttrs(attrs)}></div>`)
|
push(`<div${ssrRenderAttrs(attrs)}></div>`)
|
||||||
@ -13,19 +11,19 @@ describe('ssr: scoped id on component root', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const Comp = {
|
const Comp = {
|
||||||
ssrRender: withParentId((ctx: any, push: any, parent: any) => {
|
__scopeId: 'parent',
|
||||||
|
ssrRender: (ctx: any, push: any, parent: any) => {
|
||||||
push(ssrRenderComponent(Child), null, null, parent)
|
push(ssrRenderComponent(Child), null, null, parent)
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await renderToString(createApp(Comp))
|
const result = await renderToString(createApp(Comp))
|
||||||
expect(result).toBe(`<div parent></div>`)
|
expect(result).toBe(`<div parent></div>`)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('inside slot', async () => {
|
test('id and :slotted on component root', async () => {
|
||||||
const withParentId = withScopeId('parent')
|
|
||||||
|
|
||||||
const Child = {
|
const Child = {
|
||||||
|
// <div></div>
|
||||||
ssrRender: (_: any, push: any, _parent: any, attrs: any) => {
|
ssrRender: (_: any, push: any, _parent: any, attrs: any) => {
|
||||||
push(`<div${ssrRenderAttrs(attrs)} child></div>`)
|
push(`<div${ssrRenderAttrs(attrs)} child></div>`)
|
||||||
}
|
}
|
||||||
@ -34,29 +32,126 @@ describe('ssr: scoped id on component root', () => {
|
|||||||
const Wrapper = {
|
const Wrapper = {
|
||||||
__scopeId: 'wrapper',
|
__scopeId: 'wrapper',
|
||||||
ssrRender: (ctx: any, push: any, parent: any) => {
|
ssrRender: (ctx: any, push: any, parent: any) => {
|
||||||
ssrRenderSlot(ctx.$slots, 'default', {}, null, push, parent)
|
// <slot/>
|
||||||
|
ssrRenderSlot(
|
||||||
|
ctx.$slots,
|
||||||
|
'default',
|
||||||
|
{},
|
||||||
|
null,
|
||||||
|
push,
|
||||||
|
parent,
|
||||||
|
'wrapper-s'
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const Comp = {
|
const Comp = {
|
||||||
ssrRender: withParentId((_: any, push: any, parent: any) => {
|
__scopeId: 'parent',
|
||||||
|
ssrRender: (_: any, push: any, parent: any) => {
|
||||||
|
// <Wrapper><Child/></Wrapper>
|
||||||
push(
|
push(
|
||||||
ssrRenderComponent(
|
ssrRenderComponent(
|
||||||
Wrapper,
|
Wrapper,
|
||||||
null,
|
null,
|
||||||
{
|
{
|
||||||
default: withParentId((_: any, push: any, parent: any) => {
|
default: withCtx(
|
||||||
push(ssrRenderComponent(Child, null, null, parent))
|
(_: any, push: any, parent: any, scopeId: string) => {
|
||||||
}),
|
push(ssrRenderComponent(Child, null, null, parent, scopeId))
|
||||||
|
}
|
||||||
|
),
|
||||||
_: 1
|
_: 1
|
||||||
} as any,
|
} as any,
|
||||||
parent
|
parent
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await renderToString(createApp(Comp))
|
const result = await renderToString(createApp(Comp))
|
||||||
expect(result).toBe(`<!--[--><div parent wrapper-s child></div><!--]-->`)
|
expect(result).toBe(`<!--[--><div parent wrapper-s child></div><!--]-->`)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// #2892
|
||||||
|
test(':slotted on forwarded slots', async () => {
|
||||||
|
const Wrapper = {
|
||||||
|
__scopeId: 'wrapper',
|
||||||
|
ssrRender: (ctx: any, push: any, parent: any, attrs: any) => {
|
||||||
|
// <div class="wrapper"><slot/></div>
|
||||||
|
push(
|
||||||
|
`<div${ssrRenderAttrs(
|
||||||
|
mergeProps({ class: 'wrapper' }, attrs)
|
||||||
|
)} wrapper>`
|
||||||
|
)
|
||||||
|
ssrRenderSlot(
|
||||||
|
ctx.$slots,
|
||||||
|
'default',
|
||||||
|
{},
|
||||||
|
null,
|
||||||
|
push,
|
||||||
|
parent,
|
||||||
|
'wrapper-s'
|
||||||
|
)
|
||||||
|
push(`</div>`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const Slotted = {
|
||||||
|
__scopeId: 'slotted',
|
||||||
|
ssrRender: (ctx: any, push: any, parent: any, attrs: any) => {
|
||||||
|
// <Wrapper><slot/></Wrapper>
|
||||||
|
push(
|
||||||
|
ssrRenderComponent(
|
||||||
|
Wrapper,
|
||||||
|
attrs,
|
||||||
|
{
|
||||||
|
default: withCtx(
|
||||||
|
(_: any, push: any, parent: any, scopeId: string) => {
|
||||||
|
ssrRenderSlot(
|
||||||
|
ctx.$slots,
|
||||||
|
'default',
|
||||||
|
{},
|
||||||
|
null,
|
||||||
|
push,
|
||||||
|
parent,
|
||||||
|
'slotted-s' + scopeId
|
||||||
|
)
|
||||||
|
}
|
||||||
|
),
|
||||||
|
_: 1
|
||||||
|
} as any,
|
||||||
|
parent
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const Root = {
|
||||||
|
__scopeId: 'root',
|
||||||
|
// <Slotted><div></div></Slotted>
|
||||||
|
ssrRender: (_: any, push: any, parent: any, attrs: any) => {
|
||||||
|
push(
|
||||||
|
ssrRenderComponent(
|
||||||
|
Slotted,
|
||||||
|
attrs,
|
||||||
|
{
|
||||||
|
default: withCtx(
|
||||||
|
(_: any, push: any, parent: any, scopeId: string) => {
|
||||||
|
push(`<div root${scopeId}></div>`)
|
||||||
|
}
|
||||||
|
),
|
||||||
|
_: 1
|
||||||
|
} as any,
|
||||||
|
parent
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await renderToString(createApp(Root))
|
||||||
|
expect(result).toBe(
|
||||||
|
`<div class="wrapper" root slotted wrapper>` +
|
||||||
|
`<!--[--><!--[--><div root slotted-s wrapper-s></div><!--]--><!--]-->` +
|
||||||
|
`</div>`
|
||||||
|
)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
@ -6,10 +6,12 @@ export function ssrRenderComponent(
|
|||||||
comp: Component,
|
comp: Component,
|
||||||
props: Props | null = null,
|
props: Props | null = null,
|
||||||
children: Slots | SSRSlots | null = null,
|
children: Slots | SSRSlots | null = null,
|
||||||
parentComponent: ComponentInternalInstance | null = null
|
parentComponent: ComponentInternalInstance | null = null,
|
||||||
|
slotScopeId?: string
|
||||||
): SSRBuffer | Promise<SSRBuffer> {
|
): SSRBuffer | Promise<SSRBuffer> {
|
||||||
return renderComponentVNode(
|
return renderComponentVNode(
|
||||||
createVNode(comp, props, children),
|
createVNode(comp, props, children),
|
||||||
parentComponent
|
parentComponent,
|
||||||
|
slotScopeId
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -15,13 +15,13 @@ export function ssrRenderSlot(
|
|||||||
slotProps: Props,
|
slotProps: Props,
|
||||||
fallbackRenderFn: (() => void) | null,
|
fallbackRenderFn: (() => void) | null,
|
||||||
push: PushFn,
|
push: PushFn,
|
||||||
parentComponent: ComponentInternalInstance
|
parentComponent: ComponentInternalInstance,
|
||||||
|
slotScopeId?: string | null
|
||||||
) {
|
) {
|
||||||
// template-compiled slots are always rendered as fragments
|
// template-compiled slots are always rendered as fragments
|
||||||
push(`<!--[-->`)
|
push(`<!--[-->`)
|
||||||
const slotFn = slots[slotName]
|
const slotFn = slots[slotName]
|
||||||
if (slotFn) {
|
if (slotFn) {
|
||||||
const scopeId = parentComponent && parentComponent.type.__scopeId
|
|
||||||
const slotBuffer: SSRBufferItem[] = []
|
const slotBuffer: SSRBufferItem[] = []
|
||||||
const bufferedPush = (item: SSRBufferItem) => {
|
const bufferedPush = (item: SSRBufferItem) => {
|
||||||
slotBuffer.push(item)
|
slotBuffer.push(item)
|
||||||
@ -30,7 +30,7 @@ export function ssrRenderSlot(
|
|||||||
slotProps,
|
slotProps,
|
||||||
bufferedPush,
|
bufferedPush,
|
||||||
parentComponent,
|
parentComponent,
|
||||||
scopeId ? ` ${scopeId}-s` : ``
|
slotScopeId ? ' ' + slotScopeId : ''
|
||||||
)
|
)
|
||||||
if (Array.isArray(ret)) {
|
if (Array.isArray(ret)) {
|
||||||
// normal slot
|
// normal slot
|
||||||
|
@ -80,7 +80,8 @@ export function createBuffer() {
|
|||||||
|
|
||||||
export function renderComponentVNode(
|
export function renderComponentVNode(
|
||||||
vnode: VNode,
|
vnode: VNode,
|
||||||
parentComponent: ComponentInternalInstance | null = null
|
parentComponent: ComponentInternalInstance | null = null,
|
||||||
|
slotScopeId?: string
|
||||||
): SSRBuffer | Promise<SSRBuffer> {
|
): SSRBuffer | Promise<SSRBuffer> {
|
||||||
const instance = createComponentInstance(vnode, parentComponent, null)
|
const instance = createComponentInstance(vnode, parentComponent, null)
|
||||||
const res = setupComponent(instance, true /* isSSR */)
|
const res = setupComponent(instance, true /* isSSR */)
|
||||||
@ -97,14 +98,15 @@ export function renderComponentVNode(
|
|||||||
warn(`[@vue/server-renderer]: Uncaught error in serverPrefetch:\n`, err)
|
warn(`[@vue/server-renderer]: Uncaught error in serverPrefetch:\n`, err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return p.then(() => renderComponentSubTree(instance))
|
return p.then(() => renderComponentSubTree(instance, slotScopeId))
|
||||||
} else {
|
} else {
|
||||||
return renderComponentSubTree(instance)
|
return renderComponentSubTree(instance, slotScopeId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderComponentSubTree(
|
function renderComponentSubTree(
|
||||||
instance: ComponentInternalInstance
|
instance: ComponentInternalInstance,
|
||||||
|
slotScopeId?: string
|
||||||
): SSRBuffer | Promise<SSRBuffer> {
|
): SSRBuffer | Promise<SSRBuffer> {
|
||||||
const comp = instance.type as Component
|
const comp = instance.type as Component
|
||||||
const { getBuffer, push } = createBuffer()
|
const { getBuffer, push } = createBuffer()
|
||||||
@ -133,13 +135,10 @@ function renderComponentSubTree(
|
|||||||
|
|
||||||
// inherited scopeId
|
// inherited scopeId
|
||||||
const scopeId = instance.vnode.scopeId
|
const scopeId = instance.vnode.scopeId
|
||||||
const treeOwnerId = instance.parent && instance.parent.type.__scopeId
|
|
||||||
const slotScopeId =
|
|
||||||
treeOwnerId && treeOwnerId !== scopeId ? treeOwnerId + '-s' : null
|
|
||||||
if (scopeId || slotScopeId) {
|
if (scopeId || slotScopeId) {
|
||||||
attrs = { ...attrs }
|
attrs = { ...attrs }
|
||||||
if (scopeId) attrs[scopeId] = ''
|
if (scopeId) attrs[scopeId] = ''
|
||||||
if (slotScopeId) attrs[slotScopeId] = ''
|
if (slotScopeId) attrs[slotScopeId.trim()] = ''
|
||||||
}
|
}
|
||||||
|
|
||||||
// set current rendering instance for asset resolution
|
// set current rendering instance for asset resolution
|
||||||
|
Loading…
x
Reference in New Issue
Block a user