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

refactor(runtime-vapor): improve interop-path treeshaking by isolating interop state (#14424)

edison 2 месяцев назад
Родитель
Сommit
342e8bb2ff

+ 2 - 1
packages/runtime-vapor/src/apiCreateDynamicComponent.ts

@@ -18,6 +18,7 @@ import {
 import { advanceHydrationNode, isHydrating } from './dom/hydration'
 import { DynamicFragment, type VaporFragment } from './fragment'
 import type { KeepAliveInstance } from './components/KeepAlive'
+import { isInteropEnabled } from './vdominteropState'
 
 export function createDynamicComponent(
   getter: () => any,
@@ -45,7 +46,7 @@ export function createDynamicComponent(
       if (isBlock(value)) return value
 
       // Handles VNodes passed from VDOM components (e.g., `h(VaporComp)` from slots)
-      if (appContext.vapor && isVNode(value)) {
+      if (isInteropEnabled && appContext.vapor && isVNode(value)) {
         if (isKeepAlive(currentInstance)) {
           const frag = (
             currentInstance as KeepAliveInstance

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

@@ -122,6 +122,7 @@ import type {
 import { DynamicFragment, isFragment } from './fragment'
 import type { VaporElement } from './apiDefineCustomElement'
 import { parentSuspense, setParentSuspense } from './components/Suspense'
+import { isInteropEnabled } from './vdominteropState'
 
 export { currentInstance } from '@vue/runtime-dom'
 
@@ -292,7 +293,7 @@ export function createComponent(
   }
 
   // vdom interop enabled and component is not an explicit vapor component
-  if (appContext.vapor && !component.__vapor) {
+  if (isInteropEnabled && appContext.vapor && !component.__vapor) {
     const frag = appContext.vapor.vdomMount(
       component as any,
       currentInstance as any,

+ 2 - 1
packages/runtime-vapor/src/componentSlots.ts

@@ -27,6 +27,7 @@ import {
 } from './fragment'
 import { createElement } from './dom/node'
 import { setDynamicProps } from './dom/prop'
+import { isInteropEnabled } from './vdominteropState'
 
 /**
  * Flag to indicate if we are executing a once slot.
@@ -195,7 +196,7 @@ export function createSlot(
     : EMPTY_OBJ
 
   let fragment: SlotFragment
-  if (isRef(rawSlots._)) {
+  if (isRef(rawSlots._) && isInteropEnabled) {
     if (isHydrating) locateHydrationNode()
     fragment = instance.appContext.vapor!.vdomSlot(
       rawSlots._,

+ 15 - 10
packages/runtime-vapor/src/components/KeepAlive.ts

@@ -39,6 +39,7 @@ import {
 import { createElement } from '../dom/node'
 import { type VaporFragment, isDynamicFragment, isFragment } from '../fragment'
 import type { EffectScope } from '@vue/reactivity'
+import { isInteropEnabled } from '../vdominteropState'
 
 export interface VaporKeepAliveContext {
   processShapeFlag(block: Block): boolean
@@ -154,7 +155,7 @@ const VaporKeepAliveImpl = defineVaporComponent({
     keepAliveInstance.ctx = {
       getStorageContainer: () => storageContainer,
       getCachedComponent: (comp, key) => {
-        if (isVNode(comp)) {
+        if (isInteropEnabled && isVNode(comp)) {
           return cache.get(resolveKey(comp.type, comp.key, currentBranchKey))
         }
         return cache.get(resolveKey(comp, key, currentBranchKey))
@@ -219,7 +220,7 @@ const VaporKeepAliveImpl = defineVaporComponent({
       const [innerBlock, interop] = getInnerBlock(block)
       if (!innerBlock || !shouldCache(innerBlock!, props, interop)) return false
 
-      if (interop) {
+      if (interop && isInteropEnabled) {
         const cacheKey = getCacheKey(innerBlock, true, currentBranchKey)
         if (cache.has(cacheKey)) {
           innerBlock.vnode!.shapeFlag! |= ShapeFlags.COMPONENT_KEPT_ALIVE
@@ -228,9 +229,11 @@ const VaporKeepAliveImpl = defineVaporComponent({
       } else {
         const cacheKey = getCacheKey(innerBlock, false, currentBranchKey)
         if (cache.has(cacheKey)) {
-          innerBlock!.shapeFlag! |= ShapeFlags.COMPONENT_KEPT_ALIVE
+          ;(innerBlock as VaporComponentInstance)!.shapeFlag! |=
+            ShapeFlags.COMPONENT_KEPT_ALIVE
         }
-        innerBlock!.shapeFlag! |= ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE
+        ;(innerBlock as VaporComponentInstance)!.shapeFlag! |=
+          ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE
       }
       return true
     }
@@ -352,7 +355,7 @@ const shouldCache = (
 ) => {
   const isAsync = !interop && isAsyncWrapper(block as GenericComponentInstance)
   const type = (
-    interop
+    interop && isInteropEnabled
       ? (block as VaporFragment).vnode!.type
       : (block as GenericComponentInstance).type
   ) as GenericComponent & AsyncComponentInternalOptions
@@ -376,7 +379,7 @@ const resetCachedShapeFlag = (
 ) => {
   if (isVaporComponent(cached)) {
     resetShapeFlag(cached)
-  } else {
+  } else if (isInteropEnabled) {
     resetShapeFlag(cached.vnode)
   }
 }
@@ -405,7 +408,7 @@ function getCacheKey(
   interop: boolean,
   branchKey?: any,
 ): CacheKey {
-  if (interop) {
+  if (interop && isInteropEnabled) {
     const frag = block as VaporFragment
     return resolveKey(
       frag.vnode!.type,
@@ -420,7 +423,7 @@ function getCacheKey(
 function getInnerBlock(block: Block): InnerBlockResult {
   if (isVaporComponent(block)) {
     return [block, false]
-  } else if (isInteropFragment(block)) {
+  } else if (isInteropEnabled && isInteropFragment(block)) {
     return [block, true]
   } else if (isFragment(block)) {
     return getInnerBlock(block.nodes)
@@ -434,12 +437,14 @@ function isInteropFragment(block: Block): block is VaporFragment {
 
 function getInstanceFromCache(
   cached: VaporComponentInstance | VaporFragment,
-): GenericComponentInstance {
+): GenericComponentInstance | undefined {
   if (isVaporComponent(cached)) {
     return cached
   }
   // vdom interop
-  return cached.vnode!.component as GenericComponentInstance
+  if (isInteropEnabled) {
+    return cached.vnode!.component as GenericComponentInstance
+  }
 }
 
 export function activate(

+ 2 - 0
packages/runtime-vapor/src/vdomInterop.ts

@@ -91,6 +91,7 @@ import {
 } from './fragment'
 import type { NodeRef } from './apiTemplateRef'
 import { setTransitionHooks as setVaporTransitionHooks } from './components/Transition'
+import { setInteropEnabled } from './vdominteropState'
 import {
   type KeepAliveInstance,
   activate,
@@ -794,6 +795,7 @@ function renderVDOMSlot(
 }
 
 export const vaporInteropPlugin: Plugin = app => {
+  setInteropEnabled()
   const internals = ensureRenderer().internals
   app._context.vapor = extend(vaporInteropImpl, {
     vdomMount: createVDOMComponent.bind(null, internals),

+ 7 - 0
packages/runtime-vapor/src/vdominteropState.ts

@@ -0,0 +1,7 @@
+// if vdom interop plugin is not installed, isInteropEnabled will be false
+// the interop code path will be tree-shaken out by bundlers
+export let isInteropEnabled = false
+
+export function setInteropEnabled(): void {
+  isInteropEnabled = true
+}