componentCurrentInstance.ts 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. import { getGlobalThis } from '@vue/shared'
  2. import type {
  3. ComponentInternalInstance,
  4. GenericComponentInstance,
  5. } from './component'
  6. import { currentRenderingInstance } from './componentRenderContext'
  7. /**
  8. * @internal
  9. */
  10. export let currentInstance: GenericComponentInstance | null = null
  11. /**
  12. * @internal
  13. */
  14. export const getCurrentGenericInstance: () => GenericComponentInstance | null =
  15. () => currentInstance || currentRenderingInstance
  16. export const getCurrentInstance: () => ComponentInternalInstance | null = () =>
  17. currentInstance && !currentInstance.vapor
  18. ? (currentInstance as ComponentInternalInstance)
  19. : currentRenderingInstance
  20. export let isInSSRComponentSetup = false
  21. export let setInSSRSetupState: (state: boolean) => void
  22. let internalSetCurrentInstance: (
  23. instance: GenericComponentInstance | null,
  24. ) => void
  25. /**
  26. * The following makes getCurrentInstance() usage across multiple copies of Vue
  27. * work. Some cases of how this can happen are summarized in #7590. In principle
  28. * the duplication should be avoided, but in practice there are often cases
  29. * where the user is unable to resolve on their own, especially in complicated
  30. * SSR setups.
  31. *
  32. * Note this fix is technically incomplete, as we still rely on other singletons
  33. * for effectScope and global reactive dependency maps. However, it does make
  34. * some of the most common cases work. It also warns if the duplication is
  35. * found during browser execution.
  36. */
  37. if (__SSR__) {
  38. type Setter = (v: any) => void
  39. const g = getGlobalThis()
  40. const registerGlobalSetter = (key: string, setter: Setter) => {
  41. let setters: Setter[]
  42. if (!(setters = g[key])) setters = g[key] = []
  43. setters.push(setter)
  44. return (v: any) => {
  45. if (setters.length > 1) setters.forEach(set => set(v))
  46. else setters[0](v)
  47. }
  48. }
  49. internalSetCurrentInstance = registerGlobalSetter(
  50. `__VUE_INSTANCE_SETTERS__`,
  51. v => (currentInstance = v),
  52. )
  53. // also make `isInSSRComponentSetup` sharable across copies of Vue.
  54. // this is needed in the SFC playground when SSRing async components, since
  55. // we have to load both the runtime and the server-renderer from CDNs, they
  56. // contain duplicated copies of Vue runtime code.
  57. setInSSRSetupState = registerGlobalSetter(
  58. `__VUE_SSR_SETTERS__`,
  59. v => (isInSSRComponentSetup = v),
  60. )
  61. } else {
  62. internalSetCurrentInstance = i => {
  63. currentInstance = i
  64. }
  65. setInSSRSetupState = v => {
  66. isInSSRComponentSetup = v
  67. }
  68. }
  69. /**
  70. * @internal
  71. */
  72. export const setCurrentInstance = (instance: GenericComponentInstance) => {
  73. const prev = currentInstance
  74. internalSetCurrentInstance(instance)
  75. instance.scope.on()
  76. return (): void => {
  77. instance.scope.off()
  78. internalSetCurrentInstance(prev)
  79. }
  80. }
  81. export const unsetCurrentInstance = (): void => {
  82. currentInstance && currentInstance.scope.off()
  83. internalSetCurrentInstance(null)
  84. }