Skip to content

Commit 8d2d5bf

Browse files
committed
fix(runtime-core): support getCurrentInstance across mutiple builds of Vue
1 parent f597dc6 commit 8d2d5bf

File tree

1 file changed

+63
-3
lines changed

1 file changed

+63
-3
lines changed

packages/runtime-core/src/component.ts

+63-3
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ import {
5656
makeMap,
5757
isPromise,
5858
ShapeFlags,
59-
extend
59+
extend,
60+
getGlobalThis
6061
} from '@vue/shared'
6162
import { SuspenseBoundary } from './components/Suspense'
6263
import { CompilerOptions } from '@vue/compiler-core'
@@ -565,14 +566,73 @@ export let currentInstance: ComponentInternalInstance | null = null
565566
export const getCurrentInstance: () => ComponentInternalInstance | null = () =>
566567
currentInstance || currentRenderingInstance
567568

569+
type GlobalInstanceSetter = ((
570+
instance: ComponentInternalInstance | null
571+
) => void) & { version?: string }
572+
573+
let globalCurrentInstanceSetters: GlobalInstanceSetter[]
574+
let internalSetCurrentInstance: GlobalInstanceSetter
575+
let hasWarnedDuplicatedVue = false
576+
577+
/**
578+
* The following makes getCurrentInstance() usage across multiple copies of Vue
579+
* work. Some cases of how this can happen are summarized in #7590. In principle
580+
* the duplication should be avoided, but in practice there are often cases
581+
* where the user is unable to resolve on their own, especially in complicated
582+
* SSR setups.
583+
*
584+
* Note this fix is technically incomplete, as we still rely on other singletons
585+
* for effectScope and global reactive dependency maps. However, it does make
586+
* some of the most common cases work. It also warns if the duplication is
587+
* found during browser execution.
588+
*/
589+
if (__SSR__) {
590+
const settersKey = '__VUE_INSTANCE_SETTERS__'
591+
if (!(globalCurrentInstanceSetters = getGlobalThis()[settersKey])) {
592+
globalCurrentInstanceSetters = getGlobalThis()[settersKey] = []
593+
}
594+
globalCurrentInstanceSetters.push(i => (currentInstance = i))
595+
596+
if (__DEV__) {
597+
globalCurrentInstanceSetters[
598+
globalCurrentInstanceSetters.length - 1
599+
].version = __VERSION__
600+
}
601+
602+
internalSetCurrentInstance = instance => {
603+
if (globalCurrentInstanceSetters.length > 1) {
604+
// eslint-disable-next-line no-restricted-globals
605+
if (__DEV__ && !hasWarnedDuplicatedVue && typeof window !== 'undefined') {
606+
warn(
607+
`Mixed usage of duplicated Vue runtimes detected: ${globalCurrentInstanceSetters
608+
.map(fn => fn.version)
609+
.join(', ')}.\n` +
610+
`This likely means there are multiple versions of Vue ` +
611+
`duplicated in your dependency tree, and could lead to errors. ` +
612+
`To avoid this warning, ensure that the all imports of Vue are resolving to ` +
613+
`the same location on disk.`
614+
)
615+
hasWarnedDuplicatedVue = true
616+
}
617+
globalCurrentInstanceSetters.forEach(s => s(instance))
618+
} else {
619+
globalCurrentInstanceSetters[0](instance)
620+
}
621+
}
622+
} else {
623+
internalSetCurrentInstance = i => {
624+
currentInstance = i
625+
}
626+
}
627+
568628
export const setCurrentInstance = (instance: ComponentInternalInstance) => {
569-
currentInstance = instance
629+
internalSetCurrentInstance(instance)
570630
instance.scope.on()
571631
}
572632

573633
export const unsetCurrentInstance = () => {
574634
currentInstance && currentInstance.scope.off()
575-
currentInstance = null
635+
internalSetCurrentInstance(null)
576636
}
577637

578638
const isBuiltInTag = /*#__PURE__*/ makeMap('slot,component')

0 commit comments

Comments
 (0)