]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
wip: unify currentInstance between vdom and vapor + provide/inject
authorEvan You <evan@vuejs.org>
Thu, 5 Dec 2024 15:13:24 +0000 (23:13 +0800)
committerEvan You <evan@vuejs.org>
Thu, 5 Dec 2024 15:13:24 +0000 (23:13 +0800)
packages/runtime-core/src/apiInject.ts
packages/runtime-core/src/apiLifecycle.ts
packages/runtime-core/src/component.ts
packages/runtime-core/src/componentCurrentInstance.ts
packages/runtime-core/src/componentOptions.ts
packages/runtime-core/src/components/KeepAlive.ts
packages/runtime-core/src/index.ts
packages/runtime-vapor/src/component.ts
packages/runtime-vapor/src/renderEffect.ts

index f05d7333da6594b12aec1b545b3dc155d0fb02b4..d12fef248ea87c8e0df11efaeee54879207cb8c8 100644 (file)
@@ -1,6 +1,5 @@
 import { isFunction } from '@vue/shared'
-import { currentInstance } from './component'
-import { currentRenderingInstance } from './componentRenderContext'
+import { getCurrentGenericInstance } from './component'
 import { currentApp } from './apiCreateApp'
 import { warn } from './warning'
 
@@ -12,6 +11,7 @@ export function provide<T, K = InjectionKey<T> | string | number>(
   key: K,
   value: K extends InjectionKey<infer V> ? V : T,
 ): void {
+  const currentInstance = getCurrentGenericInstance()
   if (!currentInstance) {
     if (__DEV__) {
       warn(`provide() can only be used inside setup().`)
@@ -51,7 +51,7 @@ export function inject(
 ) {
   // fallback to `currentRenderingInstance` so that this can be called in
   // a functional component
-  const instance = currentInstance || currentRenderingInstance
+  const instance = getCurrentGenericInstance()
 
   // also support looking up from app-level provides w/ `app.runWithContext()`
   if (instance || currentApp) {
@@ -63,7 +63,7 @@ export function inject(
       ? currentApp._context.provides
       : instance
         ? instance.parent == null
-          ? instance.vnode.appContext && instance.vnode.appContext.provides
+          ? instance.appContext && instance.appContext.provides
           : instance.parent.provides
         : undefined
 
@@ -88,5 +88,5 @@ export function inject(
  * user. One example is `useRoute()` in `vue-router`.
  */
 export function hasInjectionContext(): boolean {
-  return !!(currentInstance || currentRenderingInstance || currentApp)
+  return !!(getCurrentGenericInstance() || currentApp)
 }
index b79a6d38a06185be7d94406fb8dfd5616a92dc8c..550ae914a4ff50c3756c31e8b986a43547b99f8f 100644 (file)
@@ -1,5 +1,5 @@
 import {
-  type ComponentInternalInstance,
+  type GenericComponentInstance,
   currentInstance,
   isInSSRComponentSetup,
   setCurrentInstance,
@@ -20,7 +20,7 @@ export { onActivated, onDeactivated } from './components/KeepAlive'
 export function injectHook(
   type: LifecycleHooks,
   hook: Function & { __weh?: Function },
-  target: ComponentInternalInstance | null = currentInstance,
+  target: GenericComponentInstance | null = currentInstance,
   prepend: boolean = false,
 ): Function | undefined {
   if (target) {
@@ -67,7 +67,7 @@ const createHook =
   <T extends Function = () => any>(lifecycle: LifecycleHooks) =>
   (
     hook: T,
-    target: ComponentInternalInstance | null = currentInstance,
+    target: GenericComponentInstance | null = currentInstance,
   ): void => {
     // post-create lifecycle registrations are noops during SSR (except for serverPrefetch)
     if (
@@ -79,7 +79,7 @@ const createHook =
   }
 type CreateHook<T = any> = (
   hook: T,
-  target?: ComponentInternalInstance | null,
+  target?: GenericComponentInstance | null,
 ) => void
 
 export const onBeforeMount: CreateHook = createHook(LifecycleHooks.BEFORE_MOUNT)
@@ -110,7 +110,7 @@ export type ErrorCapturedHook<TError = unknown> = (
 
 export function onErrorCaptured<TError = Error>(
   hook: ErrorCapturedHook<TError>,
-  target: ComponentInternalInstance | null = currentInstance,
+  target: GenericComponentInstance | null = currentInstance,
 ): void {
   injectHook(LifecycleHooks.ERROR_CAPTURED, hook, target)
 }
index c07d468f631f92f4d21e110a87097ef402306b86..f963ad81ffb82f0074728d5b6870b613214f315b 100644 (file)
@@ -332,6 +332,7 @@ export type InternalRenderFunction = {
  * operate on both.
  */
 export interface GenericComponentInstance {
+  vapor?: boolean
   uid: number
   type: GenericComponent
   parent: GenericComponentInstance | null
@@ -395,10 +396,64 @@ export interface GenericComponentInstance {
 
   // the following are for error handling logic only
   proxy?: any
+
+  // lifecycle
+  /**
+   * @internal
+   */
+  [LifecycleHooks.BEFORE_CREATE]?: LifecycleHook
+  /**
+   * @internal
+   */
+  [LifecycleHooks.CREATED]?: LifecycleHook
+  /**
+   * @internal
+   */
+  [LifecycleHooks.BEFORE_MOUNT]?: LifecycleHook
   /**
    * @internal
    */
-  [LifecycleHooks.ERROR_CAPTURED]: LifecycleHook
+  [LifecycleHooks.MOUNTED]?: LifecycleHook
+  /**
+   * @internal
+   */
+  [LifecycleHooks.BEFORE_UPDATE]?: LifecycleHook
+  /**
+   * @internal
+   */
+  [LifecycleHooks.UPDATED]?: LifecycleHook
+  /**
+   * @internal
+   */
+  [LifecycleHooks.BEFORE_UNMOUNT]?: LifecycleHook
+  /**
+   * @internal
+   */
+  [LifecycleHooks.UNMOUNTED]?: LifecycleHook
+  /**
+   * @internal
+   */
+  [LifecycleHooks.RENDER_TRACKED]?: LifecycleHook
+  /**
+   * @internal
+   */
+  [LifecycleHooks.RENDER_TRIGGERED]?: LifecycleHook
+  /**
+   * @internal
+   */
+  [LifecycleHooks.ACTIVATED]?: LifecycleHook
+  /**
+   * @internal
+   */
+  [LifecycleHooks.DEACTIVATED]?: LifecycleHook
+  /**
+   * @internal
+   */
+  [LifecycleHooks.ERROR_CAPTURED]?: LifecycleHook
+  /**
+   * @internal
+   */
+  [LifecycleHooks.SERVER_PREFETCH]?: LifecycleHook<() => Promise<unknown>>
 }
 
 /**
@@ -406,6 +461,7 @@ export interface GenericComponentInstance {
  * useful for advanced external libraries and tools.
  */
 export interface ComponentInternalInstance extends GenericComponentInstance {
+  vapor?: never
   uid: number
   type: ConcreteComponent
   parent: ComponentInternalInstance | null
@@ -563,64 +619,6 @@ export interface ComponentInternalInstance extends GenericComponentInstance {
    */
   asyncResolved: boolean
 
-  // lifecycle
-  /**
-   * @internal
-   */
-  [LifecycleHooks.BEFORE_CREATE]: LifecycleHook
-  /**
-   * @internal
-   */
-  [LifecycleHooks.CREATED]: LifecycleHook
-  /**
-   * @internal
-   */
-  [LifecycleHooks.BEFORE_MOUNT]: LifecycleHook
-  /**
-   * @internal
-   */
-  [LifecycleHooks.MOUNTED]: LifecycleHook
-  /**
-   * @internal
-   */
-  [LifecycleHooks.BEFORE_UPDATE]: LifecycleHook
-  /**
-   * @internal
-   */
-  [LifecycleHooks.UPDATED]: LifecycleHook
-  /**
-   * @internal
-   */
-  [LifecycleHooks.BEFORE_UNMOUNT]: LifecycleHook
-  /**
-   * @internal
-   */
-  [LifecycleHooks.UNMOUNTED]: LifecycleHook
-  /**
-   * @internal
-   */
-  [LifecycleHooks.RENDER_TRACKED]: LifecycleHook
-  /**
-   * @internal
-   */
-  [LifecycleHooks.RENDER_TRIGGERED]: LifecycleHook
-  /**
-   * @internal
-   */
-  [LifecycleHooks.ACTIVATED]: LifecycleHook
-  /**
-   * @internal
-   */
-  [LifecycleHooks.DEACTIVATED]: LifecycleHook
-  /**
-   * @internal
-   */
-  [LifecycleHooks.ERROR_CAPTURED]: LifecycleHook
-  /**
-   * @internal
-   */
-  [LifecycleHooks.SERVER_PREFETCH]: LifecycleHook<() => Promise<unknown>>
-
   /**
    * For caching bound $forceUpdate on public proxy access
    * @internal
index 268a400813f67066340b0f941e4f3d79178f9f60..b2170a164c5d69030a20fb25f9d772e9670f1ec1 100644 (file)
@@ -1,18 +1,32 @@
 import { getGlobalThis } from '@vue/shared'
-import type { ComponentInternalInstance } from './component'
+import type {
+  ComponentInternalInstance,
+  GenericComponentInstance,
+} from './component'
 import { currentRenderingInstance } from './componentRenderContext'
 
-export let currentInstance: ComponentInternalInstance | null = null
+/**
+ * @internal
+ */
+export let currentInstance: GenericComponentInstance | null = null
+
+/**
+ * @internal
+ */
+export const getCurrentGenericInstance: () => GenericComponentInstance | null =
+  () => currentInstance || currentRenderingInstance
 
 export const getCurrentInstance: () => ComponentInternalInstance | null = () =>
-  currentInstance || currentRenderingInstance
+  currentInstance && !currentInstance.vapor
+    ? (currentInstance as ComponentInternalInstance)
+    : currentRenderingInstance
 
 export let isInSSRComponentSetup = false
 
 export let setInSSRSetupState: (state: boolean) => void
 
 let internalSetCurrentInstance: (
-  instance: ComponentInternalInstance | null,
+  instance: GenericComponentInstance | null,
 ) => void
 
 /**
@@ -60,7 +74,10 @@ if (__SSR__) {
   }
 }
 
-export const setCurrentInstance = (instance: ComponentInternalInstance) => {
+/**
+ * @internal
+ */
+export const setCurrentInstance = (instance: GenericComponentInstance) => {
   const prev = currentInstance
   internalSetCurrentInstance(instance)
   instance.scope.on()
index f864f39e4199f0d469d4bb0a837fbe42ec148f96..75fbbd77ab5db18daffe4b92d1b4b303146d1e50 100644 (file)
@@ -6,7 +6,7 @@ import {
   type Data,
   type InternalRenderFunction,
   type SetupContext,
-  currentInstance,
+  getCurrentInstance,
 } from './component'
 import {
   type LooseRequired,
@@ -855,10 +855,8 @@ export function createWatcher(
 
   const options: WatchOptions = {}
   if (__COMPAT__) {
-    const instance =
-      currentInstance && getCurrentScope() === currentInstance.scope
-        ? currentInstance
-        : null
+    const cur = getCurrentInstance()
+    const instance = cur && getCurrentScope() === cur.scope ? cur : null
 
     const newValue = getter()
     if (
index 5976f3a4b339f725833e929dbe2e02cb62faf253..b0fb27207ae8e248cc0ddb11afe35038c1c3fd6f 100644 (file)
@@ -3,7 +3,6 @@ import {
   type ComponentOptions,
   type ConcreteComponent,
   type SetupContext,
-  currentInstance,
   getComponentName,
   getCurrentInstance,
 } from '../component'
@@ -411,7 +410,7 @@ export function onDeactivated(
 function registerKeepAliveHook(
   hook: Function & { __wdc?: Function },
   type: LifecycleHooks,
-  target: ComponentInternalInstance | null = currentInstance,
+  target: ComponentInternalInstance | null = getCurrentInstance(),
 ) {
   // cache the deactivate branch check wrapper for injected hooks so the same
   // hook can be properly deduped by the scheduler. "__wdc" stands for "with
index 589cdaac28540256bc80d1b3805a6b35e26d8115..eb5f44896a8e773d45c9274a07983eba20f67131 100644 (file)
@@ -507,3 +507,4 @@ export {
   type AppMountFn,
   type AppUnmountFn,
 } from './apiCreateApp'
+export { currentInstance, setCurrentInstance } from './componentCurrentInstance'
index 614054a3b25b382d2eee8e7dcfcc99f6ede98fbd..96f5552f9f53d967f4823b57ddc700985a4c093f 100644 (file)
@@ -9,9 +9,11 @@ import {
   type LifecycleHook,
   type NormalizedPropsOptions,
   type ObjectEmitsOptions,
+  currentInstance,
   nextUid,
   popWarningContext,
   pushWarningContext,
+  setCurrentInstance,
   warn,
 } from '@vue/runtime-dom'
 import { type Block, isBlock } from './block'
@@ -28,6 +30,8 @@ import { setDynamicProp } from './dom/prop'
 import { renderEffect } from './renderEffect'
 import { emit, normalizeEmitsOptions } from './componentEmits'
 
+export { currentInstance } from '@vue/runtime-dom'
+
 export type VaporComponent = FunctionalVaporComponent | ObjectVaporComponent
 
 export type VaporSetupFn = (
@@ -77,7 +81,11 @@ export function createComponent(
 ): VaporComponentInstance {
   // check if we are the single root of the parent
   // if yes, inject parent attrs as dynamic props source
-  if (isSingleRoot && currentInstance && currentInstance.hasFallthrough) {
+  if (
+    isSingleRoot &&
+    isVaporComponent(currentInstance) &&
+    currentInstance.hasFallthrough
+  ) {
     const attrs = currentInstance.attrs
     if (rawProps) {
       ;(rawProps.$ || (rawProps.$ = [])).push(() => attrs)
@@ -87,12 +95,9 @@ export function createComponent(
   }
 
   const instance = new VaporComponentInstance(component, rawProps)
+  const resetCurrentInstance = setCurrentInstance(instance)
 
   pauseTracking()
-  let prevInstance = currentInstance
-  currentInstance = instance
-  instance.scope.on()
-
   if (__DEV__) {
     pushWarningContext(instance)
   }
@@ -140,15 +145,12 @@ export function createComponent(
   if (__DEV__) {
     popWarningContext()
   }
-
-  instance.scope.off()
-  currentInstance = prevInstance
   resetTracking()
+  resetCurrentInstance()
+
   return instance
 }
 
-export let currentInstance: VaporComponentInstance | null = null
-
 const emptyContext: GenericAppContext = {
   app: null as any,
   config: {},
@@ -156,6 +158,7 @@ const emptyContext: GenericAppContext = {
 }
 
 export class VaporComponentInstance implements GenericComponentInstance {
+  vapor: true
   uid: number
   type: VaporComponent
   parent: GenericComponentInstance | null
@@ -178,11 +181,25 @@ export class VaporComponentInstance implements GenericComponentInstance {
 
   hasFallthrough: boolean
 
+  // lifecycle hooks
   isMounted: boolean
   isUnmounted: boolean
   isDeactivated: boolean
-  // LifecycleHooks.ERROR_CAPTURED
-  ec: LifecycleHook
+
+  bc?: LifecycleHook // LifecycleHooks.BEFORE_CREATE
+  c?: LifecycleHook // LifecycleHooks.CREATED
+  bm?: LifecycleHook // LifecycleHooks.BEFORE_MOUNT
+  m?: LifecycleHook // LifecycleHooks.MOUNTED
+  bu?: LifecycleHook // LifecycleHooks.BEFORE_UPDATE
+  u?: LifecycleHook // LifecycleHooks.UPDATED
+  um?: LifecycleHook // LifecycleHooks.BEFORE_UNMOUNT
+  bum?: LifecycleHook // LifecycleHooks.UNMOUNTED
+  da?: LifecycleHook // LifecycleHooks.DEACTIVATED
+  a?: LifecycleHook // LifecycleHooks.ACTIVATED
+  rtg?: LifecycleHook // LifecycleHooks.RENDER_TRACKED
+  rtc?: LifecycleHook // LifecycleHooks.RENDER_TRIGGERED
+  ec?: LifecycleHook // LifecycleHooks.ERROR_CAPTURED
+  sp?: LifecycleHook<() => Promise<unknown>> // LifecycleHooks.SERVER_PREFETCH
 
   // dev only
   setupState?: Record<string, any>
@@ -190,9 +207,10 @@ export class VaporComponentInstance implements GenericComponentInstance {
   emitsOptions?: ObjectEmitsOptions | null
 
   constructor(comp: VaporComponent, rawProps?: RawProps) {
+    this.vapor = true
     this.uid = nextUid()
     this.type = comp
-    this.parent = currentInstance
+    this.parent = currentInstance // TODO when inside
     this.appContext = currentInstance
       ? currentInstance.appContext
       : emptyContext
@@ -200,14 +218,17 @@ export class VaporComponentInstance implements GenericComponentInstance {
     this.block = null! // to be set
     this.scope = new EffectScope(true)
 
-    this.rawProps = rawProps
-    this.provides = this.refs = EMPTY_OBJ
+    this.provides = currentInstance
+      ? currentInstance.provides
+      : Object.create(this.appContext.provides)
+    this.refs = EMPTY_OBJ
     this.emitted = this.ec = this.exposed = this.propsDefaults = null
     this.isMounted = this.isUnmounted = this.isDeactivated = false
 
     // init props
     const target = rawProps || EMPTY_OBJ
     const handlers = getPropsProxyHandlers(comp, this)
+    this.rawProps = rawProps
     this.props = comp.props ? new Proxy(target, handlers[0]!) : {}
     this.attrs = new Proxy(target, handlers[1])
     this.hasFallthrough = hasFallthroughAttrs(comp, rawProps)
index 170f29bb4c13d7f334fa920998c0dffad9f5cfab..6721661a03e9de8a954ea5a4029964bcc782ac13 100644 (file)
@@ -1,6 +1,5 @@
 import { ReactiveEffect } from '@vue/reactivity'
-import { type SchedulerJob, queueJob } from '@vue/runtime-dom'
-import { currentInstance } from './component'
+import { type SchedulerJob, currentInstance, queueJob } from '@vue/runtime-dom'
 
 export function renderEffect(fn: () => void): void {
   const updateFn = () => {