Skip to content

Commit

Permalink
fix(runtime-core): support getCurrentInstance across mutiple builds…
Browse files Browse the repository at this point in the history
… of Vue
  • Loading branch information
yyx990803 committed Feb 21, 2023
1 parent f597dc6 commit 8d2d5bf
Showing 1 changed file with 63 additions and 3 deletions.
66 changes: 63 additions & 3 deletions packages/runtime-core/src/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ import {
makeMap,
isPromise,
ShapeFlags,
extend
extend,
getGlobalThis
} from '@vue/shared'
import { SuspenseBoundary } from './components/Suspense'
import { CompilerOptions } from '@vue/compiler-core'
Expand Down Expand Up @@ -565,14 +566,73 @@ export let currentInstance: ComponentInternalInstance | null = null
export const getCurrentInstance: () => ComponentInternalInstance | null = () =>
currentInstance || currentRenderingInstance

type GlobalInstanceSetter = ((
instance: ComponentInternalInstance | null
) => void) & { version?: string }

let globalCurrentInstanceSetters: GlobalInstanceSetter[]
let internalSetCurrentInstance: GlobalInstanceSetter
let hasWarnedDuplicatedVue = false

/**
* The following makes getCurrentInstance() usage across multiple copies of Vue
* work. Some cases of how this can happen are summarized in #7590. In principle
* the duplication should be avoided, but in practice there are often cases
* where the user is unable to resolve on their own, especially in complicated
* SSR setups.
*
* Note this fix is technically incomplete, as we still rely on other singletons
* for effectScope and global reactive dependency maps. However, it does make
* some of the most common cases work. It also warns if the duplication is
* found during browser execution.
*/
if (__SSR__) {
const settersKey = '__VUE_INSTANCE_SETTERS__'
if (!(globalCurrentInstanceSetters = getGlobalThis()[settersKey])) {
globalCurrentInstanceSetters = getGlobalThis()[settersKey] = []
}
globalCurrentInstanceSetters.push(i => (currentInstance = i))

if (__DEV__) {
globalCurrentInstanceSetters[
globalCurrentInstanceSetters.length - 1
].version = __VERSION__
}

internalSetCurrentInstance = instance => {
if (globalCurrentInstanceSetters.length > 1) {
// eslint-disable-next-line no-restricted-globals
if (__DEV__ && !hasWarnedDuplicatedVue && typeof window !== 'undefined') {
warn(
`Mixed usage of duplicated Vue runtimes detected: ${globalCurrentInstanceSetters
.map(fn => fn.version)
.join(', ')}.\n` +
`This likely means there are multiple versions of Vue ` +
`duplicated in your dependency tree, and could lead to errors. ` +
`To avoid this warning, ensure that the all imports of Vue are resolving to ` +
`the same location on disk.`
)
hasWarnedDuplicatedVue = true
}
globalCurrentInstanceSetters.forEach(s => s(instance))
} else {
globalCurrentInstanceSetters[0](instance)
}
}
} else {
internalSetCurrentInstance = i => {
currentInstance = i
}
}

export const setCurrentInstance = (instance: ComponentInternalInstance) => {
currentInstance = instance
internalSetCurrentInstance(instance)
instance.scope.on()
}

export const unsetCurrentInstance = () => {
currentInstance && currentInstance.scope.off()
currentInstance = null
internalSetCurrentInstance(null)
}

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

0 comments on commit 8d2d5bf

Please sign in to comment.