Skip to content

Commit 926a1dc

Browse files
committed
feat(helper): resolve component
1 parent 1b2cb72 commit 926a1dc

File tree

5 files changed

+145
-2
lines changed

5 files changed

+145
-2
lines changed
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import {
2+
type Component,
3+
createComponent,
4+
createTextNode,
5+
ref,
6+
resolveComponent,
7+
setText,
8+
template,
9+
watchEffect,
10+
} from '../src'
11+
import { describe, expect } from 'vitest'
12+
import { makeRender } from './_utils'
13+
14+
const define = makeRender()
15+
16+
describe('resolveAssets', () => {
17+
test('should work', async () => {
18+
const child = {
19+
name: 'FooBaz',
20+
setup() {
21+
return (() => {
22+
const n2 = createTextNode()
23+
return n2
24+
})()
25+
},
26+
}
27+
const { render } = define({
28+
name: 'parent',
29+
setup() {
30+
return (() => {
31+
createComponent(child)
32+
expect(resolveComponent('foo-baz')).toBeDefined()
33+
expect(resolveComponent('foo-baz')).toBeDefined()
34+
expect(resolveComponent('FooBaz')).toBeDefined()
35+
})()
36+
},
37+
})
38+
render()
39+
})
40+
test('maybe self ref', async () => {
41+
let comp: Component | null = null
42+
const rootCompObj = {
43+
name: 'Root',
44+
setup() {
45+
comp = resolveComponent('Root', true, true)
46+
},
47+
}
48+
const root = define(rootCompObj)
49+
root.render()
50+
expect(comp).toMatchObject(rootCompObj)
51+
})
52+
describe('warning', () => {
53+
test('outside render() or setup()', () => {
54+
resolveComponent('foo')
55+
expect(
56+
'resolveComponent can only be used in render() or setup().',
57+
).toHaveBeenWarned()
58+
})
59+
test('not exists', () => {
60+
const root = {
61+
setup() {
62+
resolveComponent('not-exists-component')
63+
return (() => {
64+
const n = createTextNode()
65+
})()
66+
},
67+
}
68+
const { render } = define(root)
69+
render()
70+
expect(
71+
'Failed to resolve component: not-exists-component',
72+
).toHaveBeenWarned()
73+
})
74+
})
75+
})

packages/runtime-vapor/src/apiCreateComponent.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ export function createComponent(
2626

2727
// register sub-component with current component for lifecycle management
2828
current.comps.add(instance)
29+
current.components[
30+
instance.component.name ??
31+
instance.component.__name ??
32+
instance.component.__file!
33+
] = instance.component
2934

3035
return instance
3136
}

packages/runtime-vapor/src/apiCreateVaporApp.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ export function createAppContext(): AppContext {
102102
warnHandler: undefined,
103103
},
104104
provides: Object.create(null),
105+
components: {},
105106
}
106107
}
107108

@@ -137,6 +138,7 @@ export interface AppContext {
137138
app: App // for devtools
138139
config: AppConfig
139140
provides: Record<string | symbol, any>
141+
components: Record<string, Component>
140142
}
141143

142144
/**

packages/runtime-vapor/src/component.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@ export type SetupContext<E = EmitsOptions> = E extends any
4545
}
4646
: never
4747

48+
export const getComponentName = (component: Component) => {
49+
return isFunction(component)
50+
? component.displayName || component.name
51+
: component.name
52+
}
53+
4854
export function createSetupContext(
4955
instance: ComponentInternalInstance,
5056
): SetupContext {
@@ -157,6 +163,7 @@ export interface ComponentInternalInstance {
157163
scope: EffectScope
158164
component: Component
159165
comps: Set<ComponentInternalInstance>
166+
components: Record<string, Component>
160167
dirs: Map<Node, DirectiveBinding[]>
161168

162169
rawProps: NormalizedRawProps
@@ -283,6 +290,7 @@ export function createComponentInstance(
283290
provides: parent ? parent.provides : Object.create(_appContext.provides),
284291
component,
285292
comps: new Set(),
293+
components: {},
286294
dirs: new Map(),
287295

288296
// resolved props and emits options

packages/runtime-vapor/src/helpers/resolveAssets.ts

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,58 @@
1-
export function resolveComponent() {
2-
// TODO
1+
import { camelize, capitalize } from '@vue/shared'
2+
import {
3+
Component,
4+
type ComponentInternalInstance,
5+
currentInstance,
6+
getComponentName,
7+
} from '../component'
8+
import { warn } from '../warning'
9+
10+
const resolve = (registry: Record<string, any> | undefined, name: string) => {
11+
return (
12+
registry &&
13+
(registry[name] ||
14+
registry[camelize(name)] ||
15+
registry[capitalize(camelize(name))])
16+
)
17+
}
18+
19+
export function resolveComponent(
20+
name: string,
21+
warnMissing = true,
22+
maybeSelfReference = false,
23+
) {
24+
const instance = currentInstance
25+
if (!instance?.component) {
26+
if (__DEV__) {
27+
warn(`resolveComponent ` + `can only be used in render() or setup().`)
28+
}
29+
return
30+
}
31+
const component = instance.component
32+
const selfName = getComponentName(component)
33+
if (
34+
selfName &&
35+
(selfName === name ||
36+
selfName === camelize(name) ||
37+
selfName === capitalize(camelize(name)))
38+
) {
39+
return component
40+
}
41+
const registry =
42+
instance.components ?? (component as ComponentInternalInstance).component
43+
const res =
44+
resolve(registry, name) || resolve(instance.appContext.components, name)
45+
if (!res && maybeSelfReference) {
46+
return component
47+
}
48+
if (__DEV__ && warnMissing && !res) {
49+
const extra =
50+
`\nIf this is a native custom element, make sure to exclude it from ` +
51+
`component resolution via compilerOptions.isCustomElement.`
52+
warn(`Failed to resolve component: ${name}${extra}`)
53+
}
54+
return res
55+
// // TODO
356
}
457

558
export function resolveDirective() {

0 commit comments

Comments
 (0)