Просмотр исходного кода

wip: vapor warning context integration

Evan You 1 год назад
Родитель
Сommit
cc2439c9e6

+ 41 - 26
packages/runtime-core/src/apiCreateApp.ts

@@ -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

+ 2 - 1
packages/runtime-core/src/component.ts

@@ -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

+ 3 - 1
packages/runtime-core/src/componentEmits.ts

@@ -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) {

+ 2 - 0
packages/runtime-core/src/index.ts

@@ -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'

+ 6 - 0
packages/runtime-core/src/warning.ts

@@ -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()
 }

+ 21 - 4
packages/runtime-vapor/src/_new/component.ts

@@ -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)

+ 8 - 4
packages/runtime-vapor/src/_new/componentEmits.ts

@@ -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) {