Skip to content

Commit 7940b00

Browse files
committed
chore: Merge branch 'edison/feat/setScopeId' into edison/testVapor
2 parents 023b005 + 7d72638 commit 7940b00

File tree

5 files changed

+158
-8
lines changed

5 files changed

+158
-8
lines changed
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
import {
2+
createComponent,
3+
createSlot,
4+
defineVaporComponent,
5+
setInsertionState,
6+
template,
7+
} from '../src'
8+
import { makeRender } from './_utils'
9+
10+
const define = makeRender()
11+
12+
describe('scopeId', () => {
13+
test('should attach scopeId to child component', () => {
14+
const Child = defineVaporComponent({
15+
__scopeId: 'child',
16+
setup() {
17+
return template('<div child></div>', true)()
18+
},
19+
})
20+
21+
const { html } = define({
22+
__scopeId: 'parent',
23+
setup() {
24+
const t0 = template('<div parent></div>', true)
25+
const n1 = t0() as any
26+
setInsertionState(n1)
27+
createComponent(Child)
28+
return n1
29+
},
30+
}).render()
31+
expect(html()).toBe(`<div parent=""><div child="" parent=""></div></div>`)
32+
})
33+
34+
test('should attach scopeId to nested child component', () => {
35+
const Child = defineVaporComponent({
36+
__scopeId: 'child',
37+
setup() {
38+
return template('<div child></div>', true)()
39+
},
40+
})
41+
42+
const Parent = defineVaporComponent({
43+
__scopeId: 'parent',
44+
setup() {
45+
return createComponent(Child)
46+
},
47+
})
48+
49+
const { html } = define({
50+
__scopeId: 'app',
51+
setup() {
52+
const t0 = template('<div app></div>', true)
53+
const n1 = t0() as any
54+
setInsertionState(n1)
55+
createComponent(Parent)
56+
return n1
57+
},
58+
}).render()
59+
expect(html()).toBe(
60+
`<div app=""><div child="" parent="" app=""></div></div>`,
61+
)
62+
})
63+
64+
test.todo('should attach scopeId to suspense content', async () => {})
65+
66+
// :slotted basic
67+
test('should work on slots', () => {
68+
const Child = defineVaporComponent({
69+
__scopeId: 'child',
70+
setup() {
71+
const n1 = template('<div child></div>', true)() as any
72+
setInsertionState(n1)
73+
createSlot('default', null)
74+
return n1
75+
},
76+
})
77+
78+
const Child2 = defineVaporComponent({
79+
__scopeId: 'child2',
80+
setup() {
81+
return template('<span child2></span>', true)()
82+
},
83+
})
84+
85+
const { html } = define({
86+
__scopeId: 'parent',
87+
setup() {
88+
const n2 = createComponent(
89+
Child,
90+
null,
91+
{
92+
default: () => {
93+
const n0 = template('<div parent></div>')()
94+
const n1 = createComponent(Child2)
95+
return [n0, n1]
96+
},
97+
},
98+
true,
99+
)
100+
return n2
101+
},
102+
}).render()
103+
104+
expect(html()).toBe(
105+
`<div child="" parent="">` +
106+
`<div parent="" child-s=""></div>` +
107+
// component inside slot should have:
108+
// - scopeId from template context
109+
// - slotted scopeId from slot owner
110+
// - its own scopeId
111+
`<span child2="" child="" parent="" child-s=""></span>` +
112+
`<!--slot-->` +
113+
`</div>`,
114+
)
115+
})
116+
117+
test.todo(':slotted on forwarded slots', async () => {})
118+
})

packages/runtime-vapor/src/block.ts

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,9 @@ export type BlockFn = (...args: any[]) => Block
2727
export class VaporFragment {
2828
nodes: Block
2929
anchor?: Node
30-
insert?: (parent: ParentNode, anchor: Node | null) => void
30+
insert?: (parent: ParentNode, anchor: Node | null, scopeId?: string) => void
3131
remove?: (parent?: ParentNode) => void
32+
slotScopeIds?: string[]
3233

3334
constructor(nodes: Block) {
3435
this.nodes = nodes
@@ -70,7 +71,7 @@ export class DynamicFragment extends VaporFragment {
7071
if (render) {
7172
this.scope = new EffectScope()
7273
this.nodes = this.scope.run(render) || []
73-
if (parent) insert(this.nodes, parent, this.anchor)
74+
if (parent) insert(this.nodes, parent, this.anchor, this.slotScopeIds)
7475
} else {
7576
this.scope = undefined
7677
this.nodes = []
@@ -134,28 +135,39 @@ export function insert(
134135
block: Block,
135136
parent: ParentNode,
136137
anchor: Node | null | 0 = null, // 0 means prepend
138+
scopeIds?: string[],
137139
): void {
138140
anchor = anchor === 0 ? parent.firstChild : anchor
139141
if (block instanceof Node) {
142+
if (scopeIds && block instanceof Element) {
143+
for (const id of scopeIds) {
144+
block.setAttribute(id, '')
145+
}
146+
}
140147
if (!isHydrating) {
141148
parent.insertBefore(block, anchor)
142149
}
143150
} else if (isVaporComponent(block)) {
144151
if (block.isMounted) {
145-
insert(block.block!, parent, anchor)
152+
insert(block.block!, parent, anchor, scopeIds)
146153
} else {
147-
mountComponent(block, parent, anchor)
154+
mountComponent(block, parent, anchor, scopeIds)
148155
}
149156
} else if (isArray(block)) {
150157
for (const b of block) {
151-
insert(b, parent, anchor)
158+
insert(b, parent, anchor, scopeIds)
152159
}
153160
} else {
154161
// fragment
155162
if (block.insert) {
156163
block.insert(parent, anchor)
157164
} else {
158-
insert(block.nodes, parent, anchor)
165+
if (block.slotScopeIds) {
166+
scopeIds = scopeIds
167+
? scopeIds.concat(block.slotScopeIds)
168+
: block.slotScopeIds
169+
}
170+
insert(block.nodes, parent, anchor, scopeIds)
159171
}
160172
if (block.anchor) insert(block.anchor, parent, anchor)
161173
}

packages/runtime-vapor/src/component.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,10 @@ export function createComponentWithFallback(
482482
// mark single root
483483
;(el as any).$root = isSingleRoot
484484

485+
// set scopeId
486+
const scopeId = currentInstance && currentInstance.type.__scopeId
487+
if (scopeId) el.setAttribute(scopeId, '')
488+
485489
if (rawProps) {
486490
renderEffect(() => {
487491
setDynamicProps(el, [resolveDynamicProps(rawProps as RawProps)])
@@ -503,12 +507,17 @@ export function mountComponent(
503507
instance: VaporComponentInstance,
504508
parent: ParentNode,
505509
anchor?: Node | null | 0,
510+
scopeIds?: string[],
506511
): void {
507512
if (__DEV__) {
508513
startMeasure(instance, `mount`)
509514
}
510515
if (instance.bm) invokeArrayFns(instance.bm)
511-
insert(instance.block, parent, anchor)
516+
const parentScopeId = instance.parent && instance.parent.type.__scopeId
517+
if (parentScopeId) {
518+
scopeIds = scopeIds ? [parentScopeId].concat(scopeIds) : [parentScopeId]
519+
}
520+
insert(instance.block, parent, anchor, scopeIds)
512521
if (instance.m) queuePostFlushCb(() => invokeArrayFns(instance.m!))
513522
instance.isMounted = true
514523
if (__DEV__) {

packages/runtime-vapor/src/componentSlots.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,9 @@ export function createSlot(
144144
isHydrating || __DEV__
145145
? new DynamicFragment(SLOT_ANCHOR_LABEL)
146146
: new DynamicFragment()
147+
fragment.slotScopeIds = instance.type.__scopeId
148+
? [`${instance.type.__scopeId}-s`]
149+
: undefined
147150
const isDynamicName = isFunction(name)
148151
const renderSlot = () => {
149152
const slot = getSlot(rawSlots, isFunction(name) ? name() : name)
@@ -185,7 +188,14 @@ export function createSlot(
185188
// for vdom interop fragment, `fragment.insert` handles both hydration and mounting
186189
fragment.insert)
187190
) {
188-
insert(fragment, _insertionParent, _insertionAnchor)
191+
insert(
192+
fragment,
193+
_insertionParent,
194+
_insertionAnchor,
195+
instance.parent && instance.parent.type.__scopeId
196+
? [instance.parent.type.__scopeId]
197+
: undefined,
198+
)
189199
}
190200

191201
return fragment

packages/runtime-vapor/src/vdomInterop.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,7 @@ function renderVDOMSlot(
272272
isFunction(name) ? name() : name,
273273
props,
274274
)
275+
vnode.scopeId = parentComponent.type.__scopeId!
275276
if (isHydrating) {
276277
locateHydrationNode(true)
277278
;(

0 commit comments

Comments
 (0)