wip: vapor warning context integration

This commit is contained in:
Evan You 2024-12-04 10:53:29 +08:00
parent e88c4e2ea7
commit cc2439c9e6
No known key found for this signature in database
GPG Key ID: 00E9AB7A6704CE0A
7 changed files with 83 additions and 36 deletions

View File

@ -120,13 +120,11 @@ export interface App<HostElement = any> {
export type OptionMergeFunction = (to: unknown, from: unknown) => any
export interface AppConfig {
// @private
readonly isNativeTag: (tag: string) => boolean
performance: boolean
optionMergeStrategies: Record<string, OptionMergeFunction>
globalProperties: ComponentCustomProperties & Record<string, any>
/**
* Shared app config between vdom and vapor
*/
export interface GenericAppConfig {
performance?: boolean
errorHandler?: (
err: unknown,
instance: ComponentPublicInstance | null,
@ -138,17 +136,6 @@ export interface AppConfig {
trace: string,
) => void
/**
* Options to pass to `@vue/compiler-dom`.
* Only supported in runtime compiler build.
*/
compilerOptions: RuntimeCompilerOptions
/**
* @deprecated use config.compilerOptions.isCustomElement
*/
isCustomElement?: (tag: string) => boolean
/**
* TODO document for 3.5
* Enable warnings for computed getters that recursively trigger itself.
@ -168,13 +155,46 @@ export interface AppConfig {
idPrefix?: string
}
export interface AppContext {
export interface AppConfig extends GenericAppConfig {
// @private
readonly isNativeTag: (tag: string) => boolean
optionMergeStrategies: Record<string, OptionMergeFunction>
globalProperties: ComponentCustomProperties & Record<string, any>
/**
* Options to pass to `@vue/compiler-dom`.
* Only supported in runtime compiler build.
*/
compilerOptions: RuntimeCompilerOptions
/**
* @deprecated use config.compilerOptions.isCustomElement
*/
isCustomElement?: (tag: string) => boolean
}
/**
* Minimal app context shared between vdom and vapor
*/
export interface GenericAppContext {
app: App // for devtools
config: GenericAppConfig
provides: Record<string | symbol, any>
components?: Record<string, Component>
directives?: Record<string, Directive>
/**
* HMR only
* @internal
*/
reload?: () => void
}
export interface AppContext extends GenericAppContext {
config: AppConfig
mixins: ComponentOptions[]
components: Record<string, Component>
directives: Record<string, Directive>
provides: Record<string | symbol, any>
mixins: ComponentOptions[]
/**
* Cache for merged/normalized component options
@ -193,11 +213,6 @@ export interface AppContext {
* @internal
*/
emitsCache: WeakMap<ConcreteComponent, ObjectEmitsOptions | null>
/**
* HMR only
* @internal
*/
reload?: () => void
/**
* v2 compat only
* @internal

View File

@ -39,6 +39,7 @@ import { ErrorCodes, callWithErrorHandling, handleError } from './errorHandling'
import {
type AppConfig,
type AppContext,
type GenericAppContext,
createAppContext,
} from './apiCreateApp'
import { type Directive, validateDirectiveName } from './directives'
@ -328,7 +329,7 @@ export interface GenericComponentInstance {
uid: number
type: GenericComponent
parent: GenericComponentInstance | null
appContext: AppContext
appContext: GenericAppContext
/**
* Object containing values this component provides for its descendants
* @internal

View File

@ -114,7 +114,6 @@ export function emit(
event: string,
...rawArgs: any[]
): ComponentPublicInstance | null | undefined {
if (instance.isUnmounted) return
return baseEmit(
instance,
instance.vnode.props || EMPTY_OBJ,
@ -134,6 +133,7 @@ export function baseEmit(
event: string,
...rawArgs: any[]
): ComponentPublicInstance | null | undefined {
if (instance.isUnmounted) return
if (__DEV__) {
const { emitsOptions, propsOptions } = instance
if (emitsOptions) {
@ -173,6 +173,8 @@ export function baseEmit(
const isModelListener = event.startsWith('update:')
// for v-model update:xxx events, apply modifiers on args
// it's ok to use static get because modelModifiers can only be in the static
// part of the props
const modifiers = isModelListener && getModelModifiers(props, event.slice(7))
if (modifiers) {
if (modifiers.trim) {

View File

@ -240,6 +240,7 @@ export type {
App,
AppConfig,
AppContext,
GenericAppContext,
Plugin,
ObjectPlugin,
FunctionPlugin,
@ -499,3 +500,4 @@ export {
type LifecycleHook,
nextUid,
} from './component'
export { pushWarningContext, popWarningContext } from './warning'

View File

@ -18,12 +18,18 @@ type TraceEntry = {
type ComponentTraceStack = TraceEntry[]
/**
* @internal
*/
export function pushWarningContext(
ctx: GenericComponentInstance | VNode,
): void {
stack.push(ctx)
}
/**
* @internal
*/
export function popWarningContext(): void {
stack.pop()
}

View File

@ -1,14 +1,16 @@
import {
type AppContext,
type ComponentInternalOptions,
type ComponentPropsOptions,
EffectScope,
type EmitsOptions,
type GenericAppContext,
type GenericComponentInstance,
type LifecycleHook,
type NormalizedPropsOptions,
type ObjectEmitsOptions,
nextUid,
popWarningContext,
pushWarningContext,
} from '@vue/runtime-core'
import type { Block } from '../block'
import type { Data } from '@vue/runtime-shared'
@ -86,6 +88,10 @@ export function createComponent(
currentInstance = instance
instance.scope.on()
if (__DEV__) {
pushWarningContext(instance)
}
const setupFn = isFunction(component) ? component : component.setup
const setupContext = setupFn!.length > 1 ? new SetupContext(instance) : null
instance.block = setupFn!(
@ -108,6 +114,10 @@ export function createComponent(
})
}
if (__DEV__) {
popWarningContext()
}
instance.scope.off()
currentInstance = prevInstance
resetTracking()
@ -116,11 +126,17 @@ export function createComponent(
export let currentInstance: VaporComponentInstance | null = null
const emptyContext: GenericAppContext = {
app: null as any,
config: {},
provides: /*@__PURE__*/ Object.create(null),
}
export class VaporComponentInstance implements GenericComponentInstance {
uid: number
type: VaporComponent
parent: GenericComponentInstance | null
appContext: AppContext
appContext: GenericAppContext
block: Block
scope: EffectScope
@ -153,8 +169,9 @@ export class VaporComponentInstance implements GenericComponentInstance {
this.uid = nextUid()
this.type = comp
this.parent = currentInstance
// @ts-expect-error TODO use proper appContext
this.appContext = currentInstance ? currentInstance.appContext : {}
this.appContext = currentInstance
? currentInstance.appContext
: emptyContext
this.block = null! // to be set
this.scope = new EffectScope(true)

View File

@ -8,7 +8,7 @@ import {
type VaporComponentInstance,
currentInstance,
} from './component'
import { NOOP, hasOwn, isArray } from '@vue/shared'
import { EMPTY_OBJ, NOOP, hasOwn, isArray } from '@vue/shared'
import { resolveSource } from './componentProps'
/**
@ -48,9 +48,13 @@ export function emit(
event: string,
...rawArgs: any[]
): void {
const rawProps = instance.rawProps
if (!rawProps || instance.isUnmounted) return
baseEmit(instance, rawProps, propGetter, event, ...rawArgs)
baseEmit(
instance,
instance.rawProps || EMPTY_OBJ,
propGetter,
event,
...rawArgs,
)
}
function propGetter(rawProps: Record<string, any>, key: string) {