Skip to content

Commit aea88c3

Browse files
committed
refactor: fix implementation of SFC :slotted id handling
fix vuejs#2892
1 parent cc975c1 commit aea88c3

36 files changed

+723
-457
lines changed
Lines changed: 19 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,91 +1,78 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

33
exports[`scopeId compiler support should push scopeId for hoisted nodes 1`] = `
4-
"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\\"
5-
const _withId = /*#__PURE__*/_withScopeId(\\"test\\")
4+
"import { createVNode as _createVNode, toDisplayString as _toDisplayString, createTextVNode as _createTextVNode, openBlock as _openBlock, createBlock as _createBlock, setScopeId as _setScopeId } from \\"vue\\"
65
7-
_pushScopeId(\\"test\\")
6+
_setScopeId(\\"test\\")
87
const _hoisted_1 = /*#__PURE__*/_createVNode(\\"div\\", null, \\"hello\\", -1 /* HOISTED */)
98
const _hoisted_2 = /*#__PURE__*/_createVNode(\\"div\\", null, \\"world\\", -1 /* HOISTED */)
10-
_popScopeId()
9+
_setScopeId(null)
1110
12-
export const render = /*#__PURE__*/_withId((_ctx, _cache) => {
11+
export function render(_ctx, _cache) {
1312
return (_openBlock(), _createBlock(\\"div\\", null, [
1413
_hoisted_1,
1514
_createTextVNode(_toDisplayString(_ctx.foo), 1 /* TEXT */),
1615
_hoisted_2
1716
]))
18-
})"
17+
}"
1918
`;
2019

2120
exports[`scopeId compiler support should wrap default slot 1`] = `
22-
"import { createVNode as _createVNode, resolveComponent as _resolveComponent, withCtx as _withCtx, openBlock as _openBlock, createBlock as _createBlock, withScopeId as _withScopeId } from \\"vue\\"
23-
const _withId = /*#__PURE__*/_withScopeId(\\"test\\")
21+
"import { createVNode as _createVNode, resolveComponent as _resolveComponent, withCtx as _withCtx, openBlock as _openBlock, createBlock as _createBlock } from \\"vue\\"
2422
25-
export const render = /*#__PURE__*/_withId((_ctx, _cache) => {
23+
export function render(_ctx, _cache) {
2624
const _component_Child = _resolveComponent(\\"Child\\")
2725
2826
return (_openBlock(), _createBlock(_component_Child, null, {
29-
default: _withId(() => [
27+
default: _withCtx(() => [
3028
_createVNode(\\"div\\")
3129
]),
3230
_: 1 /* STABLE */
3331
}))
34-
})"
32+
}"
3533
`;
3634

3735
exports[`scopeId compiler support should wrap dynamic slots 1`] = `
38-
"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\\"
39-
const _withId = /*#__PURE__*/_withScopeId(\\"test\\")
36+
"import { createVNode as _createVNode, resolveComponent as _resolveComponent, withCtx as _withCtx, renderList as _renderList, createSlots as _createSlots, openBlock as _openBlock, createBlock as _createBlock } from \\"vue\\"
4037
41-
export const render = /*#__PURE__*/_withId((_ctx, _cache) => {
38+
export function render(_ctx, _cache) {
4239
const _component_Child = _resolveComponent(\\"Child\\")
4340
4441
return (_openBlock(), _createBlock(_component_Child, null, _createSlots({ _: 2 /* DYNAMIC */ }, [
4542
(_ctx.ok)
4643
? {
4744
name: \\"foo\\",
48-
fn: _withId(() => [
45+
fn: _withCtx(() => [
4946
_createVNode(\\"div\\")
5047
])
5148
}
5249
: undefined,
5350
_renderList(_ctx.list, (i) => {
5451
return {
5552
name: i,
56-
fn: _withId(() => [
53+
fn: _withCtx(() => [
5754
_createVNode(\\"div\\")
5855
])
5956
}
6057
})
6158
]), 1024 /* DYNAMIC_SLOTS */))
62-
})"
59+
}"
6360
`;
6461

6562
exports[`scopeId compiler support should wrap named slots 1`] = `
66-
"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\\"
67-
const _withId = /*#__PURE__*/_withScopeId(\\"test\\")
63+
"import { toDisplayString as _toDisplayString, createTextVNode as _createTextVNode, createVNode as _createVNode, resolveComponent as _resolveComponent, withCtx as _withCtx, openBlock as _openBlock, createBlock as _createBlock } from \\"vue\\"
6864
69-
export const render = /*#__PURE__*/_withId((_ctx, _cache) => {
65+
export function render(_ctx, _cache) {
7066
const _component_Child = _resolveComponent(\\"Child\\")
7167
7268
return (_openBlock(), _createBlock(_component_Child, null, {
73-
foo: _withId(({ msg }) => [
69+
foo: _withCtx(({ msg }) => [
7470
_createTextVNode(_toDisplayString(msg), 1 /* TEXT */)
7571
]),
76-
bar: _withId(() => [
72+
bar: _withCtx(() => [
7773
_createVNode(\\"div\\")
7874
]),
7975
_: 1 /* STABLE */
8076
}))
81-
})"
82-
`;
83-
84-
exports[`scopeId compiler support should wrap render function 1`] = `
85-
"import { createVNode as _createVNode, openBlock as _openBlock, createBlock as _createBlock, withScopeId as _withScopeId } from \\"vue\\"
86-
const _withId = /*#__PURE__*/_withScopeId(\\"test\\")
87-
88-
export const render = /*#__PURE__*/_withId((_ctx, _cache) => {
89-
return (_openBlock(), _createBlock(\\"div\\"))
90-
})"
77+
}"
9178
`;

packages/compiler-core/__tests__/scopeId.spec.ts

Lines changed: 14 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,26 @@
11
import { baseCompile } from '../src/compile'
2-
import {
3-
WITH_SCOPE_ID,
4-
PUSH_SCOPE_ID,
5-
POP_SCOPE_ID
6-
} from '../src/runtimeHelpers'
2+
import { SET_SCOPE_ID } from '../src/runtimeHelpers'
73
import { PatchFlags } from '@vue/shared'
84
import { genFlagText } from './testUtils'
95

6+
/**
7+
* Ensure all slot functions are wrapped with _withCtx
8+
* which sets the currentRenderingInstance and currentScopeId when rendering
9+
* the slot.
10+
*/
1011
describe('scopeId compiler support', () => {
1112
test('should only work in module mode', () => {
1213
expect(() => {
1314
baseCompile(``, { scopeId: 'test' })
1415
}).toThrow(`"scopeId" option is only supported in module mode`)
1516
})
1617

17-
test('should wrap render function', () => {
18-
const { ast, code } = baseCompile(`<div/>`, {
19-
mode: 'module',
20-
scopeId: 'test'
21-
})
22-
expect(ast.helpers).toContain(WITH_SCOPE_ID)
23-
expect(code).toMatch(`const _withId = /*#__PURE__*/_withScopeId("test")`)
24-
expect(code).toMatch(
25-
`export const render = /*#__PURE__*/_withId((_ctx, _cache) => {`
26-
)
27-
expect(code).toMatchSnapshot()
28-
})
29-
3018
test('should wrap default slot', () => {
3119
const { code } = baseCompile(`<Child><div/></Child>`, {
3220
mode: 'module',
3321
scopeId: 'test'
3422
})
35-
expect(code).toMatch(`default: _withId(() => [`)
23+
expect(code).toMatch(`default: _withCtx(() => [`)
3624
expect(code).toMatchSnapshot()
3725
})
3826

@@ -48,8 +36,8 @@ describe('scopeId compiler support', () => {
4836
scopeId: 'test'
4937
}
5038
)
51-
expect(code).toMatch(`foo: _withId(({ msg }) => [`)
52-
expect(code).toMatch(`bar: _withId(() => [`)
39+
expect(code).toMatch(`foo: _withCtx(({ msg }) => [`)
40+
expect(code).toMatch(`bar: _withCtx(() => [`)
5341
expect(code).toMatchSnapshot()
5442
})
5543

@@ -65,8 +53,8 @@ describe('scopeId compiler support', () => {
6553
scopeId: 'test'
6654
}
6755
)
68-
expect(code).toMatch(/name: "foo",\s+fn: _withId\(/)
69-
expect(code).toMatch(/name: i,\s+fn: _withId\(/)
56+
expect(code).toMatch(/name: "foo",\s+fn: _withCtx\(/)
57+
expect(code).toMatch(/name: i,\s+fn: _withCtx\(/)
7058
expect(code).toMatchSnapshot()
7159
})
7260

@@ -79,19 +67,18 @@ describe('scopeId compiler support', () => {
7967
hoistStatic: true
8068
}
8169
)
82-
expect(ast.helpers).toContain(PUSH_SCOPE_ID)
83-
expect(ast.helpers).toContain(POP_SCOPE_ID)
70+
expect(ast.helpers).toContain(SET_SCOPE_ID)
8471
expect(ast.hoists.length).toBe(2)
8572
expect(code).toMatch(
8673
[
87-
`_pushScopeId("test")`,
74+
`_setScopeId("test")`,
8875
`const _hoisted_1 = /*#__PURE__*/_createVNode("div", null, "hello", ${genFlagText(
8976
PatchFlags.HOISTED
9077
)})`,
9178
`const _hoisted_2 = /*#__PURE__*/_createVNode("div", null, "world", ${genFlagText(
9279
PatchFlags.HOISTED
9380
)})`,
94-
`_popScopeId()`
81+
`_setScopeId(null)`
9582
].join('\n')
9683
)
9784
expect(code).toMatchSnapshot()

packages/compiler-core/src/codegen.ts

Lines changed: 16 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,7 @@ import {
4343
SET_BLOCK_TRACKING,
4444
CREATE_COMMENT,
4545
CREATE_TEXT,
46-
PUSH_SCOPE_ID,
47-
POP_SCOPE_ID,
48-
WITH_SCOPE_ID,
46+
SET_SCOPE_ID,
4947
WITH_DIRECTIVES,
5048
CREATE_BLOCK,
5149
OPEN_BLOCK,
@@ -197,12 +195,11 @@ export function generate(
197195
indent,
198196
deindent,
199197
newline,
200-
scopeId,
201198
ssr
202199
} = context
200+
203201
const hasHelpers = ast.helpers.length > 0
204202
const useWithBlock = !prefixIdentifiers && mode !== 'module'
205-
const genScopeId = !__BROWSER__ && scopeId != null && mode === 'module'
206203
const isSetupInlined = !__BROWSER__ && !!options.inline
207204

208205
// preambles
@@ -212,7 +209,7 @@ export function generate(
212209
? createCodegenContext(ast, options)
213210
: context
214211
if (!__BROWSER__ && mode === 'module') {
215-
genModulePreamble(ast, preambleContext, genScopeId, isSetupInlined)
212+
genModulePreamble(ast, preambleContext, isSetupInlined)
216213
} else {
217214
genFunctionPreamble(ast, preambleContext)
218215
}
@@ -229,14 +226,7 @@ export function generate(
229226
? args.map(arg => `${arg}: any`).join(',')
230227
: args.join(', ')
231228

232-
if (genScopeId) {
233-
if (isSetupInlined) {
234-
push(`${PURE_ANNOTATION}_withId(`)
235-
} else {
236-
push(`const ${functionName} = ${PURE_ANNOTATION}_withId(`)
237-
}
238-
}
239-
if (isSetupInlined || genScopeId) {
229+
if (isSetupInlined) {
240230
push(`(${signature}) => {`)
241231
} else {
242232
push(`function ${functionName}(${signature}) {`)
@@ -301,10 +291,6 @@ export function generate(
301291
deindent()
302292
push(`}`)
303293

304-
if (genScopeId) {
305-
push(`)`)
306-
}
307-
308294
return {
309295
ast,
310296
code: context.code,
@@ -375,23 +361,20 @@ function genFunctionPreamble(ast: RootNode, context: CodegenContext) {
375361
function genModulePreamble(
376362
ast: RootNode,
377363
context: CodegenContext,
378-
genScopeId: boolean,
379364
inline?: boolean
380365
) {
381366
const {
382367
push,
383-
helper,
384368
newline,
385-
scopeId,
386369
optimizeImports,
387-
runtimeModuleName
370+
runtimeModuleName,
371+
scopeId,
372+
mode
388373
} = context
389374

390-
if (genScopeId) {
391-
ast.helpers.push(WITH_SCOPE_ID)
392-
if (ast.hoists.length) {
393-
ast.helpers.push(PUSH_SCOPE_ID, POP_SCOPE_ID)
394-
}
375+
const genScopeId = !__BROWSER__ && scopeId != null && mode === 'module'
376+
if (genScopeId && ast.hoists.length) {
377+
ast.helpers.push(SET_SCOPE_ID)
395378
}
396379

397380
// generate import statements for helpers
@@ -434,13 +417,6 @@ function genModulePreamble(
434417
newline()
435418
}
436419

437-
if (genScopeId) {
438-
push(
439-
`const _withId = ${PURE_ANNOTATION}${helper(WITH_SCOPE_ID)}("${scopeId}")`
440-
)
441-
newline()
442-
}
443-
444420
genHoists(ast.hoists, context)
445421
newline()
446422

@@ -480,7 +456,7 @@ function genHoists(hoists: (JSChildNode | null)[], context: CodegenContext) {
480456
// push scope Id before initializing hoisted vnodes so that these vnodes
481457
// get the proper scopeId as well.
482458
if (genScopeId) {
483-
push(`${helper(PUSH_SCOPE_ID)}("${scopeId}")`)
459+
push(`${helper(SET_SCOPE_ID)}("${scopeId}")`)
484460
newline()
485461
}
486462

@@ -493,7 +469,7 @@ function genHoists(hoists: (JSChildNode | null)[], context: CodegenContext) {
493469
})
494470

495471
if (genScopeId) {
496-
push(`${helper(POP_SCOPE_ID)}()`)
472+
push(`${helper(SET_SCOPE_ID)}(null)`)
497473
newline()
498474
}
499475
context.pure = false
@@ -817,15 +793,11 @@ function genFunctionExpression(
817793
node: FunctionExpression,
818794
context: CodegenContext
819795
) {
820-
const { push, indent, deindent, scopeId, mode } = context
796+
const { push, indent, deindent } = context
821797
const { params, returns, body, newline, isSlot } = node
822-
// slot functions also need to push scopeId before rendering its content
823-
const genScopeId =
824-
!__BROWSER__ && isSlot && scopeId != null && mode !== 'function'
825798

826-
if (genScopeId) {
827-
push(`_withId(`)
828-
} else if (isSlot) {
799+
if (isSlot) {
800+
// wrap slot functions with owner context
829801
push(`_${helperNameMap[WITH_CTX]}(`)
830802
}
831803
push(`(`, node)
@@ -855,7 +827,7 @@ function genFunctionExpression(
855827
deindent()
856828
push(`}`)
857829
}
858-
if (genScopeId || isSlot) {
830+
if (isSlot) {
859831
push(`)`)
860832
}
861833
}

packages/compiler-core/src/runtimeHelpers.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,7 @@ export const CAMELIZE = Symbol(__DEV__ ? `camelize` : ``)
2525
export const CAPITALIZE = Symbol(__DEV__ ? `capitalize` : ``)
2626
export const TO_HANDLER_KEY = Symbol(__DEV__ ? `toHandlerKey` : ``)
2727
export const SET_BLOCK_TRACKING = Symbol(__DEV__ ? `setBlockTracking` : ``)
28-
export const PUSH_SCOPE_ID = Symbol(__DEV__ ? `pushScopeId` : ``)
29-
export const POP_SCOPE_ID = Symbol(__DEV__ ? `popScopeId` : ``)
30-
export const WITH_SCOPE_ID = Symbol(__DEV__ ? `withScopeId` : ``)
28+
export const SET_SCOPE_ID = Symbol(__DEV__ ? `setScopeId` : ``)
3129
export const WITH_CTX = Symbol(__DEV__ ? `withCtx` : ``)
3230
export const UNREF = Symbol(__DEV__ ? `unref` : ``)
3331
export const IS_REF = Symbol(__DEV__ ? `isRef` : ``)
@@ -61,9 +59,7 @@ export const helperNameMap: any = {
6159
[CAPITALIZE]: `capitalize`,
6260
[TO_HANDLER_KEY]: `toHandlerKey`,
6361
[SET_BLOCK_TRACKING]: `setBlockTracking`,
64-
[PUSH_SCOPE_ID]: `pushScopeId`,
65-
[POP_SCOPE_ID]: `popScopeId`,
66-
[WITH_SCOPE_ID]: `withScopeId`,
62+
[SET_SCOPE_ID]: `setScopeId`,
6763
[WITH_CTX]: `withCtx`,
6864
[UNREF]: `unref`,
6965
[IS_REF]: `isRef`

0 commit comments

Comments
 (0)