Skip to content

Commit a0b5653

Browse files
committed
feat(runtime-vapor): extract apiSetup & init setup ctx
1 parent 3f155f2 commit a0b5653

File tree

6 files changed

+120
-46
lines changed

6 files changed

+120
-46
lines changed

packages/runtime-vapor/src/apiCreateComponent.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import {
33
createComponentInstance,
44
currentInstance,
55
} from './component'
6-
import { setupComponent } from './apiRender'
6+
import { setupComponent } from './apiSetup'
77
import type { RawProps } from './componentProps'
88

99
export function createComponent(comp: Component, rawProps: RawProps = null) {

packages/runtime-vapor/src/apiCreateVaporApp.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ import {
66
} from './component'
77
import { warn } from './warning'
88
import { version } from '.'
9-
import { render, setupComponent, unmountComponent } from './apiRender'
9+
import { render, unmountComponent } from './apiRender'
1010
import type { RawProps } from './componentProps'
11+
import { setupComponent } from './apiSetup'
1112

1213
export function createVaporApp(
1314
rootComponent: Component,

packages/runtime-vapor/src/apiRender.ts

Lines changed: 1 addition & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
import { isArray, isFunction, isObject } from '@vue/shared'
2-
import { type ComponentInternalInstance, setCurrentInstance } from './component'
1+
import type { ComponentInternalInstance } from './component'
32
import { insert, querySelector, remove } from './dom/element'
43
import { flushPostFlushCbs, queuePostRenderEffect } from './scheduler'
5-
import { proxyRefs } from '@vue/reactivity'
64
import { invokeLifecycle } from './componentLifecycle'
75
import { VaporLifecycleHooks } from './apiLifecycle'
86

@@ -15,43 +13,6 @@ export type Fragment = {
1513
[fragmentKey]: true
1614
}
1715

18-
export function setupComponent(instance: ComponentInternalInstance): void {
19-
const reset = setCurrentInstance(instance)
20-
instance.scope.run(() => {
21-
const { component, props, emit, attrs } = instance
22-
const ctx = { expose: () => {}, emit, attrs }
23-
24-
const setupFn = isFunction(component) ? component : component.setup
25-
const stateOrNode = setupFn && setupFn(props, ctx)
26-
27-
let block: Block | undefined
28-
29-
if (
30-
stateOrNode &&
31-
(stateOrNode instanceof Node ||
32-
isArray(stateOrNode) ||
33-
(stateOrNode as any)[fragmentKey])
34-
) {
35-
block = stateOrNode as Block
36-
} else if (isObject(stateOrNode)) {
37-
instance.setupState = proxyRefs(stateOrNode)
38-
}
39-
if (!block && component.render) {
40-
block = component.render(instance.setupState)
41-
}
42-
43-
if (block instanceof DocumentFragment) {
44-
block = Array.from(block.childNodes)
45-
}
46-
if (!block) {
47-
// TODO: warn no template
48-
block = []
49-
}
50-
return (instance.block = block)
51-
})
52-
reset()
53-
}
54-
5516
export function render(
5617
instance: ComponentInternalInstance,
5718
container: string | ParentNode,
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import { proxyRefs } from '@vue/reactivity'
2+
import { isArray, isFunction, isObject } from '@vue/shared'
3+
import { type ComponentInternalInstance, setCurrentInstance } from './component'
4+
import { getAttrsProxy } from './componentAttrs'
5+
// import { SetupContext } from 'vue'
6+
import { type Block, fragmentKey } from './apiRender'
7+
8+
export function setupComponent(instance: ComponentInternalInstance): void {
9+
const reset = setCurrentInstance(instance)
10+
instance.scope.run(() => {
11+
const { component, props } = instance
12+
const ctx = createSetupContext(instance)
13+
14+
const setupFn = isFunction(component) ? component : component.setup
15+
const stateOrNode = setupFn && setupFn(props, ctx)
16+
17+
let block: Block | undefined
18+
19+
if (
20+
stateOrNode &&
21+
(stateOrNode instanceof Node ||
22+
isArray(stateOrNode) ||
23+
(stateOrNode as any)[fragmentKey])
24+
) {
25+
block = stateOrNode as Block
26+
} else if (isObject(stateOrNode)) {
27+
instance.setupState = proxyRefs(stateOrNode)
28+
}
29+
if (!block && component.render) {
30+
block = component.render(instance.setupState)
31+
}
32+
33+
if (block instanceof DocumentFragment) {
34+
block = Array.from(block.childNodes)
35+
}
36+
if (!block) {
37+
// TODO: warn no template
38+
block = []
39+
}
40+
return (instance.block = block)
41+
})
42+
reset()
43+
}
44+
45+
export function createSetupContext(instance: ComponentInternalInstance): any {
46+
if (__DEV__) {
47+
// We use getters in dev in case libs like test-utils overwrite instance
48+
// properties (overwrites should not be done in prod)
49+
return Object.freeze({
50+
expose: () => {},
51+
get attrs() {
52+
return getAttrsProxy(instance)
53+
},
54+
get emit() {
55+
return (event: string, ...args: any[]) => instance.emit(event, ...args)
56+
},
57+
})
58+
} else {
59+
return {
60+
get attrs() {
61+
return getAttrsProxy(instance)
62+
},
63+
emit: instance.emit,
64+
}
65+
}
66+
}

packages/runtime-vapor/src/component.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ export interface ComponentInternalInstance {
6767
*/
6868
inheritAttrs?: boolean
6969

70+
attrsProxy: Data | null
71+
7072
// lifecycle
7173
isMounted: boolean
7274
isUnmounted: boolean
@@ -176,6 +178,9 @@ export function createComponentInstance(
176178
attrs: EMPTY_OBJ,
177179
refs: EMPTY_OBJ,
178180

181+
inheritAttrs: component.inheritAttrs,
182+
attrsProxy: null,
183+
179184
// lifecycle
180185
isMounted: false,
181186
isUnmounted: false,
@@ -230,9 +235,6 @@ export function createComponentInstance(
230235
*/
231236
// [VaporLifecycleHooks.SERVER_PREFETCH]: null,
232237
}
233-
if (component.inheritAttrs != null) {
234-
instance.inheritAttrs = component.inheritAttrs
235-
}
236238
initProps(instance, rawProps, !isFunction(component))
237239
instance.emit = emit.bind(null, instance)
238240

packages/runtime-vapor/src/componentAttrs.ts

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
import { camelize, isFunction } from '@vue/shared'
1+
import { type Data, camelize, isFunction } from '@vue/shared'
22
import type { ComponentInternalInstance } from './component'
33
import { isEmitListener } from './componentEmits'
4+
import { TrackOpTypes, track } from '@vue/reactivity'
5+
import { warn } from './warning'
46

57
export function patchAttrs(instance: ComponentInternalInstance) {
68
const attrs = instance.attrs
@@ -42,3 +44,45 @@ export function patchAttrs(instance: ComponentInternalInstance) {
4244
}
4345
}
4446
}
47+
48+
/**
49+
* dev only flag to track whether $attrs was used during render.
50+
* If $attrs was used during render then the warning for failed attrs
51+
* fallthrough can be suppressed.
52+
*/
53+
let accessedAttrs: boolean = false
54+
55+
function markAttrsAccessed() {
56+
accessedAttrs = true
57+
}
58+
59+
export function getAttrsProxy(instance: ComponentInternalInstance): Data {
60+
return (
61+
instance.attrsProxy ||
62+
(instance.attrsProxy = new Proxy(
63+
instance.attrs,
64+
__DEV__
65+
? {
66+
get(target, key: string) {
67+
markAttrsAccessed()
68+
track(instance, TrackOpTypes.GET, '$attrs')
69+
return target[key]
70+
},
71+
set() {
72+
warn(`setupContext.attrs is readonly.`)
73+
return false
74+
},
75+
deleteProperty() {
76+
warn(`setupContext.attrs is readonly.`)
77+
return false
78+
},
79+
}
80+
: {
81+
get(target, key: string) {
82+
track(instance, TrackOpTypes.GET, '$attrs')
83+
return target[key]
84+
},
85+
},
86+
))
87+
)
88+
}

0 commit comments

Comments
 (0)