parent
9ff70be2b3
commit
37c17091fd
@ -1,48 +1,51 @@
|
|||||||
// 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, setScopeId as _setScopeId } from \\"vue\\"
|
"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\\"
|
||||||
|
const _withId = /*#__PURE__*/_withScopeId(\\"test\\")
|
||||||
|
|
||||||
_setScopeId(\\"test\\")
|
_pushScopeId(\\"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 */)
|
||||||
_setScopeId(null)
|
_popScopeId()
|
||||||
|
|
||||||
export function render(_ctx, _cache) {
|
export const render = /*#__PURE__*/_withId((_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 } from \\"vue\\"
|
"import { createVNode as _createVNode, resolveComponent as _resolveComponent, withCtx as _withCtx, openBlock as _openBlock, createBlock as _createBlock, withScopeId as _withScopeId } from \\"vue\\"
|
||||||
|
const _withId = /*#__PURE__*/_withScopeId(\\"test\\")
|
||||||
|
|
||||||
export function render(_ctx, _cache) {
|
export const render = /*#__PURE__*/_withId((_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: _withCtx(() => [
|
default: _withId(() => [
|
||||||
_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 } from \\"vue\\"
|
"import { createVNode as _createVNode, resolveComponent as _resolveComponent, withCtx as _withCtx, renderList as _renderList, createSlots as _createSlots, openBlock as _openBlock, createBlock as _createBlock, withScopeId as _withScopeId } from \\"vue\\"
|
||||||
|
const _withId = /*#__PURE__*/_withScopeId(\\"test\\")
|
||||||
|
|
||||||
export function render(_ctx, _cache) {
|
export const render = /*#__PURE__*/_withId((_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: _withCtx(() => [
|
fn: _withId(() => [
|
||||||
_createVNode(\\"div\\")
|
_createVNode(\\"div\\")
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
@ -50,29 +53,30 @@ export function render(_ctx, _cache) {
|
|||||||
_renderList(_ctx.list, (i) => {
|
_renderList(_ctx.list, (i) => {
|
||||||
return {
|
return {
|
||||||
name: i,
|
name: i,
|
||||||
fn: _withCtx(() => [
|
fn: _withId(() => [
|
||||||
_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 } from \\"vue\\"
|
"import { toDisplayString as _toDisplayString, createTextVNode as _createTextVNode, createVNode as _createVNode, resolveComponent as _resolveComponent, withCtx as _withCtx, openBlock as _openBlock, createBlock as _createBlock, withScopeId as _withScopeId } from \\"vue\\"
|
||||||
|
const _withId = /*#__PURE__*/_withScopeId(\\"test\\")
|
||||||
|
|
||||||
export function render(_ctx, _cache) {
|
export const render = /*#__PURE__*/_withId((_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: _withCtx(({ msg }) => [
|
foo: _withId(({ msg }) => [
|
||||||
_createTextVNode(_toDisplayString(msg), 1 /* TEXT */)
|
_createTextVNode(_toDisplayString(msg), 1 /* TEXT */)
|
||||||
]),
|
]),
|
||||||
bar: _withCtx(() => [
|
bar: _withId(() => [
|
||||||
_createVNode(\\"div\\")
|
_createVNode(\\"div\\")
|
||||||
]),
|
]),
|
||||||
_: 1 /* STABLE */
|
_: 1 /* STABLE */
|
||||||
}))
|
}))
|
||||||
}"
|
})"
|
||||||
`;
|
`;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { baseCompile } from '../src/compile'
|
import { baseCompile } from '../src/compile'
|
||||||
import { SET_SCOPE_ID } from '../src/runtimeHelpers'
|
import { 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'
|
||||||
|
|
||||||
@ -20,7 +20,7 @@ describe('scopeId compiler support', () => {
|
|||||||
mode: 'module',
|
mode: 'module',
|
||||||
scopeId: 'test'
|
scopeId: 'test'
|
||||||
})
|
})
|
||||||
expect(code).toMatch(`default: _withCtx(() => [`)
|
expect(code).toMatch(`default: _withId(() => [`)
|
||||||
expect(code).toMatchSnapshot()
|
expect(code).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -36,8 +36,8 @@ describe('scopeId compiler support', () => {
|
|||||||
scopeId: 'test'
|
scopeId: 'test'
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
expect(code).toMatch(`foo: _withCtx(({ msg }) => [`)
|
expect(code).toMatch(`foo: _withId(({ msg }) => [`)
|
||||||
expect(code).toMatch(`bar: _withCtx(() => [`)
|
expect(code).toMatch(`bar: _withId(() => [`)
|
||||||
expect(code).toMatchSnapshot()
|
expect(code).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -53,8 +53,8 @@ describe('scopeId compiler support', () => {
|
|||||||
scopeId: 'test'
|
scopeId: 'test'
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
expect(code).toMatch(/name: "foo",\s+fn: _withCtx\(/)
|
expect(code).toMatch(/name: "foo",\s+fn: _withId\(/)
|
||||||
expect(code).toMatch(/name: i,\s+fn: _withCtx\(/)
|
expect(code).toMatch(/name: i,\s+fn: _withId\(/)
|
||||||
expect(code).toMatchSnapshot()
|
expect(code).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -67,18 +67,19 @@ describe('scopeId compiler support', () => {
|
|||||||
hoistStatic: true
|
hoistStatic: true
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
expect(ast.helpers).toContain(SET_SCOPE_ID)
|
expect(ast.helpers).toContain(PUSH_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(
|
||||||
[
|
[
|
||||||
`_setScopeId("test")`,
|
`_pushScopeId("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
|
||||||
)})`,
|
)})`,
|
||||||
`_setScopeId(null)`
|
`_popScopeId()`
|
||||||
].join('\n')
|
].join('\n')
|
||||||
)
|
)
|
||||||
expect(code).toMatchSnapshot()
|
expect(code).toMatchSnapshot()
|
||||||
|
@ -129,7 +129,7 @@ return function render(_ctx, _cache) {
|
|||||||
const { renderList: _renderList, Fragment: _Fragment, openBlock: _openBlock, createBlock: _createBlock, renderSlot: _renderSlot } = _Vue
|
const { renderList: _renderList, Fragment: _Fragment, openBlock: _openBlock, createBlock: _createBlock, renderSlot: _renderSlot } = _Vue
|
||||||
|
|
||||||
return (_openBlock(true), _createBlock(_Fragment, null, _renderList(items, (item) => {
|
return (_openBlock(true), _createBlock(_Fragment, null, _renderList(items, (item) => {
|
||||||
return _renderSlot($slots, \\"default\\", {}, undefined, true)
|
return _renderSlot($slots, \\"default\\")
|
||||||
}), 256 /* UNKEYED_FRAGMENT */))
|
}), 256 /* UNKEYED_FRAGMENT */))
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
@ -143,7 +143,7 @@ return function render(_ctx, _cache) {
|
|||||||
const { renderList: _renderList, Fragment: _Fragment, openBlock: _openBlock, createBlock: _createBlock, renderSlot: _renderSlot } = _Vue
|
const { renderList: _renderList, Fragment: _Fragment, openBlock: _openBlock, createBlock: _createBlock, renderSlot: _renderSlot } = _Vue
|
||||||
|
|
||||||
return (_openBlock(true), _createBlock(_Fragment, null, _renderList(items, (item) => {
|
return (_openBlock(true), _createBlock(_Fragment, null, _renderList(items, (item) => {
|
||||||
return _renderSlot($slots, \\"default\\", {}, undefined, true)
|
return _renderSlot($slots, \\"default\\")
|
||||||
}), 256 /* UNKEYED_FRAGMENT */))
|
}), 256 /* UNKEYED_FRAGMENT */))
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
|
@ -80,7 +80,7 @@ return function render(_ctx, _cache) {
|
|||||||
const { renderSlot: _renderSlot, createCommentVNode: _createCommentVNode } = _Vue
|
const { renderSlot: _renderSlot, createCommentVNode: _createCommentVNode } = _Vue
|
||||||
|
|
||||||
return ok
|
return ok
|
||||||
? _renderSlot($slots, \\"default\\", { key: 0 }, undefined, true)
|
? _renderSlot($slots, \\"default\\", { key: 0 })
|
||||||
: _createCommentVNode(\\"v-if\\", true)
|
: _createCommentVNode(\\"v-if\\", true)
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
@ -140,7 +140,7 @@ return function render(_ctx, _cache) {
|
|||||||
const { renderSlot: _renderSlot, createCommentVNode: _createCommentVNode } = _Vue
|
const { renderSlot: _renderSlot, createCommentVNode: _createCommentVNode } = _Vue
|
||||||
|
|
||||||
return ok
|
return ok
|
||||||
? _renderSlot($slots, \\"default\\", { key: 0 }, undefined, true)
|
? _renderSlot($slots, \\"default\\", { key: 0 })
|
||||||
: _createCommentVNode(\\"v-if\\", true)
|
: _createCommentVNode(\\"v-if\\", true)
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
|
@ -67,7 +67,7 @@ return function render(_ctx, _cache) {
|
|||||||
return (_openBlock(), _createBlock(\\"div\\", null, [
|
return (_openBlock(), _createBlock(\\"div\\", null, [
|
||||||
_cache[1] || (
|
_cache[1] || (
|
||||||
_setBlockTracking(-1),
|
_setBlockTracking(-1),
|
||||||
_cache[1] = _renderSlot($slots, \\"default\\", {}, undefined, true),
|
_cache[1] = _renderSlot($slots, \\"default\\"),
|
||||||
_setBlockTracking(1),
|
_setBlockTracking(1),
|
||||||
_cache[1]
|
_cache[1]
|
||||||
)
|
)
|
||||||
|
@ -16,7 +16,6 @@ import { transformSlotOutlet } from '../../src/transforms/transformSlotOutlet'
|
|||||||
function parseWithSlots(template: string, options: CompilerOptions = {}) {
|
function parseWithSlots(template: string, options: CompilerOptions = {}) {
|
||||||
const ast = parse(template)
|
const ast = parse(template)
|
||||||
transform(ast, {
|
transform(ast, {
|
||||||
slotted: false,
|
|
||||||
nodeTransforms: [
|
nodeTransforms: [
|
||||||
...(options.prefixIdentifiers ? [transformExpression] : []),
|
...(options.prefixIdentifiers ? [transformExpression] : []),
|
||||||
transformSlotOutlet,
|
transformSlotOutlet,
|
||||||
@ -340,8 +339,8 @@ describe('compiler: transform <slot> outlets', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
test('slot with slotted: true', async () => {
|
test('slot with slotted: false', async () => {
|
||||||
const ast = parseWithSlots(`<slot/>`, { slotted: true })
|
const ast = parseWithSlots(`<slot/>`, { slotted: false, scopeId: 'foo' })
|
||||||
expect((ast.children[0] as ElementNode).codegenNode).toMatchObject({
|
expect((ast.children[0] as ElementNode).codegenNode).toMatchObject({
|
||||||
type: NodeTypes.JS_CALL_EXPRESSION,
|
type: NodeTypes.JS_CALL_EXPRESSION,
|
||||||
callee: RENDER_SLOT,
|
callee: RENDER_SLOT,
|
||||||
|
@ -404,13 +404,7 @@ describe('compiler: v-if', () => {
|
|||||||
expect(codegenNode.consequent).toMatchObject({
|
expect(codegenNode.consequent).toMatchObject({
|
||||||
type: NodeTypes.JS_CALL_EXPRESSION,
|
type: NodeTypes.JS_CALL_EXPRESSION,
|
||||||
callee: RENDER_SLOT,
|
callee: RENDER_SLOT,
|
||||||
arguments: [
|
arguments: ['$slots', '"default"', createObjectMatcher({ key: `[0]` })]
|
||||||
'$slots',
|
|
||||||
'"default"',
|
|
||||||
createObjectMatcher({ key: `[0]` }),
|
|
||||||
'undefined',
|
|
||||||
'true'
|
|
||||||
]
|
|
||||||
})
|
})
|
||||||
expect(generate(root).code).toMatchSnapshot()
|
expect(generate(root).code).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
@ -423,13 +417,7 @@ describe('compiler: v-if', () => {
|
|||||||
expect(codegenNode.consequent).toMatchObject({
|
expect(codegenNode.consequent).toMatchObject({
|
||||||
type: NodeTypes.JS_CALL_EXPRESSION,
|
type: NodeTypes.JS_CALL_EXPRESSION,
|
||||||
callee: RENDER_SLOT,
|
callee: RENDER_SLOT,
|
||||||
arguments: [
|
arguments: ['$slots', '"default"', createObjectMatcher({ key: `[0]` })]
|
||||||
'$slots',
|
|
||||||
'"default"',
|
|
||||||
createObjectMatcher({ key: `[0]` }),
|
|
||||||
'undefined',
|
|
||||||
'true'
|
|
||||||
]
|
|
||||||
})
|
})
|
||||||
expect(generate(root).code).toMatchSnapshot()
|
expect(generate(root).code).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
@ -43,7 +43,9 @@ import {
|
|||||||
SET_BLOCK_TRACKING,
|
SET_BLOCK_TRACKING,
|
||||||
CREATE_COMMENT,
|
CREATE_COMMENT,
|
||||||
CREATE_TEXT,
|
CREATE_TEXT,
|
||||||
SET_SCOPE_ID,
|
PUSH_SCOPE_ID,
|
||||||
|
POP_SCOPE_ID,
|
||||||
|
WITH_SCOPE_ID,
|
||||||
WITH_DIRECTIVES,
|
WITH_DIRECTIVES,
|
||||||
CREATE_BLOCK,
|
CREATE_BLOCK,
|
||||||
OPEN_BLOCK,
|
OPEN_BLOCK,
|
||||||
@ -53,6 +55,7 @@ import {
|
|||||||
import { ImportItem } from './transform'
|
import { ImportItem } from './transform'
|
||||||
|
|
||||||
const PURE_ANNOTATION = `/*#__PURE__*/`
|
const PURE_ANNOTATION = `/*#__PURE__*/`
|
||||||
|
const WITH_ID = `_withId`
|
||||||
|
|
||||||
type CodegenNode = TemplateChildNode | JSChildNode | SSRCodegenNode
|
type CodegenNode = TemplateChildNode | JSChildNode | SSRCodegenNode
|
||||||
|
|
||||||
@ -195,11 +198,13 @@ 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
|
||||||
@ -209,7 +214,7 @@ export function generate(
|
|||||||
? createCodegenContext(ast, options)
|
? createCodegenContext(ast, options)
|
||||||
: context
|
: context
|
||||||
if (!__BROWSER__ && mode === 'module') {
|
if (!__BROWSER__ && mode === 'module') {
|
||||||
genModulePreamble(ast, preambleContext, isSetupInlined)
|
genModulePreamble(ast, preambleContext, genScopeId, isSetupInlined)
|
||||||
} else {
|
} else {
|
||||||
genFunctionPreamble(ast, preambleContext)
|
genFunctionPreamble(ast, preambleContext)
|
||||||
}
|
}
|
||||||
@ -226,7 +231,14 @@ export function generate(
|
|||||||
? args.map(arg => `${arg}: any`).join(',')
|
? args.map(arg => `${arg}: any`).join(',')
|
||||||
: args.join(', ')
|
: args.join(', ')
|
||||||
|
|
||||||
if (isSetupInlined) {
|
if (genScopeId) {
|
||||||
|
if (isSetupInlined) {
|
||||||
|
push(`${PURE_ANNOTATION}${WITH_ID}(`)
|
||||||
|
} else {
|
||||||
|
push(`const ${functionName} = ${PURE_ANNOTATION}${WITH_ID}(`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isSetupInlined || genScopeId) {
|
||||||
push(`(${signature}) => {`)
|
push(`(${signature}) => {`)
|
||||||
} else {
|
} else {
|
||||||
push(`function ${functionName}(${signature}) {`)
|
push(`function ${functionName}(${signature}) {`)
|
||||||
@ -291,6 +303,10 @@ export function generate(
|
|||||||
deindent()
|
deindent()
|
||||||
push(`}`)
|
push(`}`)
|
||||||
|
|
||||||
|
if (genScopeId) {
|
||||||
|
push(`)`)
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
ast,
|
ast,
|
||||||
code: context.code,
|
code: context.code,
|
||||||
@ -361,6 +377,7 @@ 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 {
|
||||||
@ -369,12 +386,14 @@ function genModulePreamble(
|
|||||||
optimizeImports,
|
optimizeImports,
|
||||||
runtimeModuleName,
|
runtimeModuleName,
|
||||||
scopeId,
|
scopeId,
|
||||||
mode
|
helper
|
||||||
} = context
|
} = context
|
||||||
|
|
||||||
const genScopeId = !__BROWSER__ && scopeId != null && mode === 'module'
|
if (genScopeId) {
|
||||||
if (genScopeId && ast.hoists.length) {
|
ast.helpers.push(WITH_SCOPE_ID)
|
||||||
ast.helpers.push(SET_SCOPE_ID)
|
if (ast.hoists.length) {
|
||||||
|
ast.helpers.push(PUSH_SCOPE_ID, POP_SCOPE_ID)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// generate import statements for helpers
|
// generate import statements for helpers
|
||||||
@ -417,6 +436,17 @@ function genModulePreamble(
|
|||||||
newline()
|
newline()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// we technically don't need this anymore since `withCtx` already sets the
|
||||||
|
// correct scopeId, but this is necessary for backwards compat
|
||||||
|
if (genScopeId) {
|
||||||
|
push(
|
||||||
|
`const ${WITH_ID} = ${PURE_ANNOTATION}${helper(
|
||||||
|
WITH_SCOPE_ID
|
||||||
|
)}("${scopeId}")`
|
||||||
|
)
|
||||||
|
newline()
|
||||||
|
}
|
||||||
|
|
||||||
genHoists(ast.hoists, context)
|
genHoists(ast.hoists, context)
|
||||||
newline()
|
newline()
|
||||||
|
|
||||||
@ -463,7 +493,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(SET_SCOPE_ID)}("${scopeId}")`)
|
push(`${helper(PUSH_SCOPE_ID)}("${scopeId}")`)
|
||||||
newline()
|
newline()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -476,7 +506,7 @@ function genHoists(hoists: (JSChildNode | null)[], context: CodegenContext) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
if (genScopeId) {
|
if (genScopeId) {
|
||||||
push(`${helper(SET_SCOPE_ID)}(null)`)
|
push(`${helper(POP_SCOPE_ID)}()`)
|
||||||
newline()
|
newline()
|
||||||
}
|
}
|
||||||
context.pure = false
|
context.pure = false
|
||||||
@ -800,12 +830,15 @@ function genFunctionExpression(
|
|||||||
node: FunctionExpression,
|
node: FunctionExpression,
|
||||||
context: CodegenContext
|
context: CodegenContext
|
||||||
) {
|
) {
|
||||||
const { push, indent, deindent } = context
|
const { push, indent, deindent, scopeId, mode } = 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 (isSlot) {
|
if (isSlot) {
|
||||||
// wrap slot functions with owner context
|
// wrap slot functions with owner context
|
||||||
push(`_${helperNameMap[WITH_CTX]}(`)
|
push(genScopeId ? `${WITH_ID}(` : `_${helperNameMap[WITH_CTX]}(`)
|
||||||
}
|
}
|
||||||
push(`(`, node)
|
push(`(`, node)
|
||||||
if (isArray(params)) {
|
if (isArray(params)) {
|
||||||
|
@ -25,7 +25,9 @@ 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 SET_SCOPE_ID = Symbol(__DEV__ ? `setScopeId` : ``)
|
export const PUSH_SCOPE_ID = Symbol(__DEV__ ? `pushScopeId` : ``)
|
||||||
|
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` : ``)
|
||||||
@ -59,7 +61,9 @@ export const helperNameMap: any = {
|
|||||||
[CAPITALIZE]: `capitalize`,
|
[CAPITALIZE]: `capitalize`,
|
||||||
[TO_HANDLER_KEY]: `toHandlerKey`,
|
[TO_HANDLER_KEY]: `toHandlerKey`,
|
||||||
[SET_BLOCK_TRACKING]: `setBlockTracking`,
|
[SET_BLOCK_TRACKING]: `setBlockTracking`,
|
||||||
[SET_SCOPE_ID]: `setScopeId`,
|
[PUSH_SCOPE_ID]: `pushScopeId`,
|
||||||
|
[POP_SCOPE_ID]: `popScopeId`,
|
||||||
|
[WITH_SCOPE_ID]: `withScopeId`,
|
||||||
[WITH_CTX]: `withCtx`,
|
[WITH_CTX]: `withCtx`,
|
||||||
[UNREF]: `unref`,
|
[UNREF]: `unref`,
|
||||||
[IS_REF]: `isRef`
|
[IS_REF]: `isRef`
|
||||||
|
@ -34,7 +34,7 @@ export const transformSlotOutlet: NodeTransform = (node, context) => {
|
|||||||
slotArgs.push(createFunctionExpression([], children, false, false, loc))
|
slotArgs.push(createFunctionExpression([], children, false, false, loc))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context.slotted) {
|
if (context.scopeId && !context.slotted) {
|
||||||
if (!slotProps) {
|
if (!slotProps) {
|
||||||
slotArgs.push(`{}`)
|
slotArgs.push(`{}`)
|
||||||
}
|
}
|
||||||
|
@ -10,11 +10,13 @@ describe('ssr: scopeId', () => {
|
|||||||
mode: 'module'
|
mode: 'module'
|
||||||
}).code
|
}).code
|
||||||
).toMatchInlineSnapshot(`
|
).toMatchInlineSnapshot(`
|
||||||
"import { ssrRenderAttrs as _ssrRenderAttrs } from \\"@vue/server-renderer\\"
|
"import { withScopeId as _withScopeId } from \\"vue\\"
|
||||||
|
import { ssrRenderAttrs as _ssrRenderAttrs } from \\"@vue/server-renderer\\"
|
||||||
|
const _withId = /*#__PURE__*/_withScopeId(\\"data-v-xxxxxxx\\")
|
||||||
|
|
||||||
export function ssrRender(_ctx, _push, _parent, _attrs) {
|
export const ssrRender = /*#__PURE__*/_withId((_ctx, _push, _parent, _attrs) => {
|
||||||
_push(\`<div\${_ssrRenderAttrs(_attrs)} data-v-xxxxxxx><span data-v-xxxxxxx>hello</span></div>\`)
|
_push(\`<div\${_ssrRenderAttrs(_attrs)} data-v-xxxxxxx><span data-v-xxxxxxx>hello</span></div>\`)
|
||||||
}"
|
})"
|
||||||
`)
|
`)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -26,14 +28,15 @@ describe('ssr: scopeId', () => {
|
|||||||
mode: 'module'
|
mode: 'module'
|
||||||
}).code
|
}).code
|
||||||
).toMatchInlineSnapshot(`
|
).toMatchInlineSnapshot(`
|
||||||
"import { resolveComponent as _resolveComponent, withCtx as _withCtx, createTextVNode as _createTextVNode } from \\"vue\\"
|
"import { resolveComponent as _resolveComponent, withCtx as _withCtx, createTextVNode as _createTextVNode, withScopeId as _withScopeId } 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 function ssrRender(_ctx, _push, _parent, _attrs) {
|
export const ssrRender = /*#__PURE__*/_withId((_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: _withCtx((_, _push, _parent, _scopeId) => {
|
default: _withId((_, _push, _parent, _scopeId) => {
|
||||||
if (_push) {
|
if (_push) {
|
||||||
_push(\`foo\`)
|
_push(\`foo\`)
|
||||||
} else {
|
} else {
|
||||||
@ -44,7 +47,7 @@ describe('ssr: scopeId', () => {
|
|||||||
}),
|
}),
|
||||||
_: 1 /* STABLE */
|
_: 1 /* STABLE */
|
||||||
}, _parent))
|
}, _parent))
|
||||||
}"
|
})"
|
||||||
`)
|
`)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -55,14 +58,15 @@ describe('ssr: scopeId', () => {
|
|||||||
mode: 'module'
|
mode: 'module'
|
||||||
}).code
|
}).code
|
||||||
).toMatchInlineSnapshot(`
|
).toMatchInlineSnapshot(`
|
||||||
"import { resolveComponent as _resolveComponent, withCtx as _withCtx, createVNode as _createVNode } from \\"vue\\"
|
"import { resolveComponent as _resolveComponent, withCtx as _withCtx, createVNode as _createVNode, withScopeId as _withScopeId } 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 function ssrRender(_ctx, _push, _parent, _attrs) {
|
export const ssrRender = /*#__PURE__*/_withId((_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: _withCtx((_, _push, _parent, _scopeId) => {
|
default: _withId((_, _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 {
|
||||||
@ -73,7 +77,7 @@ describe('ssr: scopeId', () => {
|
|||||||
}),
|
}),
|
||||||
_: 1 /* STABLE */
|
_: 1 /* STABLE */
|
||||||
}, _parent))
|
}, _parent))
|
||||||
}"
|
})"
|
||||||
`)
|
`)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -84,19 +88,20 @@ describe('ssr: scopeId', () => {
|
|||||||
mode: 'module'
|
mode: 'module'
|
||||||
}).code
|
}).code
|
||||||
).toMatchInlineSnapshot(`
|
).toMatchInlineSnapshot(`
|
||||||
"import { resolveComponent as _resolveComponent, withCtx as _withCtx, createVNode as _createVNode } from \\"vue\\"
|
"import { resolveComponent as _resolveComponent, withCtx as _withCtx, createVNode as _createVNode, withScopeId as _withScopeId } 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 function ssrRender(_ctx, _push, _parent, _attrs) {
|
export const ssrRender = /*#__PURE__*/_withId((_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: _withCtx((_, _push, _parent, _scopeId) => {
|
default: _withId((_, _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: _withCtx((_, _push, _parent, _scopeId) => {
|
default: _withId((_, _push, _parent, _scopeId) => {
|
||||||
if (_push) {
|
if (_push) {
|
||||||
_push(\`<span data-v-xxxxxxx\${_scopeId}></span>\`)
|
_push(\`<span data-v-xxxxxxx\${_scopeId}></span>\`)
|
||||||
} else {
|
} else {
|
||||||
@ -111,7 +116,7 @@ describe('ssr: scopeId', () => {
|
|||||||
return [
|
return [
|
||||||
_createVNode(\\"span\\", null, \\"hello\\"),
|
_createVNode(\\"span\\", null, \\"hello\\"),
|
||||||
_createVNode(_component_bar, null, {
|
_createVNode(_component_bar, null, {
|
||||||
default: _withCtx(() => [
|
default: _withId(() => [
|
||||||
_createVNode(\\"span\\")
|
_createVNode(\\"span\\")
|
||||||
]),
|
]),
|
||||||
_: 1 /* STABLE */
|
_: 1 /* STABLE */
|
||||||
@ -121,7 +126,7 @@ describe('ssr: scopeId', () => {
|
|||||||
}),
|
}),
|
||||||
_: 1 /* STABLE */
|
_: 1 /* STABLE */
|
||||||
}, _parent))
|
}, _parent))
|
||||||
}"
|
})"
|
||||||
`)
|
`)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -105,7 +105,7 @@ describe('ssr: <slot>', () => {
|
|||||||
_ssrRenderSlot(_ctx.$slots, \\"default\\", {}, null, _push, _parent, \\"hello-s\\" + _scopeId)
|
_ssrRenderSlot(_ctx.$slots, \\"default\\", {}, null, _push, _parent, \\"hello-s\\" + _scopeId)
|
||||||
} else {
|
} else {
|
||||||
return [
|
return [
|
||||||
_renderSlot(_ctx.$slots, \\"default\\", {}, undefined, true)
|
_renderSlot(_ctx.$slots, \\"default\\")
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
@ -3,9 +3,12 @@ import {
|
|||||||
render,
|
render,
|
||||||
nodeOps,
|
nodeOps,
|
||||||
serializeInner,
|
serializeInner,
|
||||||
renderSlot
|
renderSlot,
|
||||||
|
withScopeId,
|
||||||
|
pushScopeId,
|
||||||
|
popScopeId
|
||||||
} from '@vue/runtime-test'
|
} from '@vue/runtime-test'
|
||||||
import { setScopeId, withCtx } from '../src/componentRenderContext'
|
import { withCtx } from '../src/componentRenderContext'
|
||||||
|
|
||||||
describe('scopeId runtime support', () => {
|
describe('scopeId runtime support', () => {
|
||||||
test('should attach scopeId', () => {
|
test('should attach scopeId', () => {
|
||||||
@ -40,7 +43,7 @@ describe('scopeId runtime support', () => {
|
|||||||
const Child = {
|
const Child = {
|
||||||
__scopeId: 'child',
|
__scopeId: 'child',
|
||||||
render(this: any) {
|
render(this: any) {
|
||||||
return h('div', renderSlot(this.$slots, 'default', {}, undefined, true))
|
return h('div', renderSlot(this.$slots, 'default'))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const Child2 = {
|
const Child2 = {
|
||||||
@ -82,7 +85,13 @@ describe('scopeId runtime support', () => {
|
|||||||
render(this: any) {
|
render(this: any) {
|
||||||
// <div class="wrapper"><slot/></div>
|
// <div class="wrapper"><slot/></div>
|
||||||
return h('div', { class: 'wrapper' }, [
|
return h('div', { class: 'wrapper' }, [
|
||||||
renderSlot(this.$slots, 'default')
|
renderSlot(
|
||||||
|
this.$slots,
|
||||||
|
'default',
|
||||||
|
{},
|
||||||
|
undefined,
|
||||||
|
true /* noSlotted */
|
||||||
|
)
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -92,17 +101,15 @@ describe('scopeId runtime support', () => {
|
|||||||
render(this: any) {
|
render(this: any) {
|
||||||
// <Wrapper><slot/></Wrapper>
|
// <Wrapper><slot/></Wrapper>
|
||||||
return h(Wrapper, null, {
|
return h(Wrapper, null, {
|
||||||
default: withCtx(() => [
|
default: withCtx(() => [renderSlot(this.$slots, 'default')])
|
||||||
renderSlot(this.$slots, 'default', {}, undefined, true)
|
|
||||||
])
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// simulate hoisted node
|
// simulate hoisted node
|
||||||
setScopeId('root')
|
pushScopeId('root')
|
||||||
const hoisted = h('div', 'hoisted')
|
const hoisted = h('div', 'hoisted')
|
||||||
setScopeId(null)
|
popScopeId()
|
||||||
|
|
||||||
const Root = {
|
const Root = {
|
||||||
__scopeId: 'root',
|
__scopeId: 'root',
|
||||||
@ -178,3 +185,124 @@ describe('scopeId runtime support', () => {
|
|||||||
expect(serializeInner(root)).toBe(`<div parent></div>`)
|
expect(serializeInner(root)).toBe(`<div parent></div>`)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('backwards compat with <=3.0.7', () => {
|
||||||
|
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', renderSlot(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>`)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('hoisted nodes', async () => {
|
||||||
|
pushScopeId('foobar')
|
||||||
|
const hoisted = h('div', 'hello')
|
||||||
|
popScopeId()
|
||||||
|
|
||||||
|
const App = {
|
||||||
|
__scopeId: 'foobar',
|
||||||
|
render: () => h('div', [hoisted])
|
||||||
|
}
|
||||||
|
|
||||||
|
const root = nodeOps.createElement('div')
|
||||||
|
render(h(App), root)
|
||||||
|
|
||||||
|
expect(serializeInner(root)).toBe(
|
||||||
|
`<div foobar><div foobar>hello</div></div>`
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
@ -32,10 +32,25 @@ export function setCurrentRenderingInstance(
|
|||||||
* Set scope id when creating hoisted vnodes.
|
* Set scope id when creating hoisted vnodes.
|
||||||
* @private compiler helper
|
* @private compiler helper
|
||||||
*/
|
*/
|
||||||
export function setScopeId(id: string | null) {
|
export function pushScopeId(id: string | null) {
|
||||||
currentScopeId = id
|
currentScopeId = id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Technically we no longer need this after 3.0.8 but we need to keep the same
|
||||||
|
* API for backwards compat w/ code generated by compilers.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
export function popScopeId() {
|
||||||
|
currentScopeId = null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Only for backwards compat
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
export const withScopeId = (_id: string) => withCtx
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrap a slot function to memoize current rendering instance
|
* Wrap a slot function to memoize current rendering instance
|
||||||
* @private compiler helper
|
* @private compiler helper
|
||||||
|
@ -26,7 +26,7 @@ export function renderSlot(
|
|||||||
// this is not a user-facing function, so the fallback is always generated by
|
// this is not a user-facing function, so the fallback is always generated by
|
||||||
// the compiler and guaranteed to be a function returning an array
|
// the compiler and guaranteed to be a function returning an array
|
||||||
fallback?: () => VNodeArrayChildren,
|
fallback?: () => VNodeArrayChildren,
|
||||||
hasSlotted?: boolean
|
noSlotted?: boolean
|
||||||
): VNode {
|
): VNode {
|
||||||
let slot = slots[name]
|
let slot = slots[name]
|
||||||
|
|
||||||
@ -54,7 +54,7 @@ export function renderSlot(
|
|||||||
? PatchFlags.STABLE_FRAGMENT
|
? PatchFlags.STABLE_FRAGMENT
|
||||||
: PatchFlags.BAIL
|
: PatchFlags.BAIL
|
||||||
)
|
)
|
||||||
if (hasSlotted && rendered.scopeId) {
|
if (!noSlotted && rendered.scopeId) {
|
||||||
rendered.slotScopeIds = [rendered.scopeId + '-s']
|
rendered.slotScopeIds = [rendered.scopeId + '-s']
|
||||||
}
|
}
|
||||||
isRenderingCompiledSlot--
|
isRenderingCompiledSlot--
|
||||||
|
@ -226,8 +226,13 @@ export { HMRRuntime } from './hmr'
|
|||||||
// user code should avoid relying on them.
|
// user code should avoid relying on them.
|
||||||
|
|
||||||
// For compiler generated code
|
// For compiler generated code
|
||||||
// should sync with '@vue/compiler-core/src/runtimeConstants.ts'
|
// should sync with '@vue/compiler-core/src/runtimeHelpers.ts'
|
||||||
export { withCtx, setScopeId } from './componentRenderContext'
|
export {
|
||||||
|
withCtx,
|
||||||
|
pushScopeId,
|
||||||
|
popScopeId,
|
||||||
|
withScopeId
|
||||||
|
} 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'
|
||||||
|
Loading…
Reference in New Issue
Block a user