wip: make singleton mutations affect all app instances
This commit is contained in:
parent
61edb700d7
commit
f2a5a3ee55
@ -15,7 +15,7 @@ import { RootHydrateFunction } from './hydration'
|
||||
import { devtoolsInitApp, devtoolsUnmountApp } from './devtools'
|
||||
import { isFunction, NO, isObject } from '@vue/shared'
|
||||
import { version } from '.'
|
||||
import { installCompatMount } from './compat/global'
|
||||
import { applySingletonAppMutations, installCompatMount } from './compat/global'
|
||||
import { installLegacyConfigProperties } from './compat/globalConfig'
|
||||
import { installGlobalFilterMethod } from './compat/filter'
|
||||
|
||||
@ -331,6 +331,7 @@ export function createAppAPI<HostElement>(
|
||||
installCompatMount(app, context, render, hydrate)
|
||||
installGlobalFilterMethod(app, context)
|
||||
if (__DEV__) installLegacyConfigProperties(app.config)
|
||||
applySingletonAppMutations(app)
|
||||
}
|
||||
|
||||
return app
|
||||
|
@ -115,15 +115,22 @@ export type CompatVue = Pick<App, 'version' | 'component' | 'directive'> & {
|
||||
|
||||
export let isCopyingConfig = false
|
||||
|
||||
// exported only for test
|
||||
export let singletonApp: App
|
||||
let singletonCtor: Function
|
||||
|
||||
// Legacy global Vue constructor
|
||||
export function createCompatVue(
|
||||
createApp: CreateAppFunction<Element>
|
||||
createApp: CreateAppFunction<Element>,
|
||||
createSingletonApp: CreateAppFunction<Element>
|
||||
): CompatVue {
|
||||
const Vue: CompatVue = function Vue(options: ComponentOptions = {}) {
|
||||
return createCompatApp(options, Vue)
|
||||
} as any
|
||||
singletonApp = createSingletonApp({})
|
||||
|
||||
const singletonApp = createApp({})
|
||||
const Vue: CompatVue = (singletonCtor = function Vue(
|
||||
options: ComponentOptions = {}
|
||||
) {
|
||||
return createCompatApp(options, Vue)
|
||||
} as any)
|
||||
|
||||
function createCompatApp(options: ComponentOptions = {}, Ctor: any) {
|
||||
assertCompatEnabled(DeprecationTypes.GLOBAL_MOUNT, null)
|
||||
@ -139,53 +146,8 @@ export function createCompatVue(
|
||||
|
||||
const app = createApp(options)
|
||||
|
||||
// copy over asset registries and deopt flag
|
||||
;['mixins', 'components', 'directives', 'filters', 'deopt'].forEach(key => {
|
||||
// @ts-ignore
|
||||
app._context[key] = singletonApp._context[key]
|
||||
})
|
||||
|
||||
// copy over global config mutations
|
||||
isCopyingConfig = true
|
||||
for (const key in singletonApp.config) {
|
||||
if (key === 'isNativeTag') continue
|
||||
if (
|
||||
isRuntimeOnly() &&
|
||||
(key === 'isCustomElement' || key === 'compilerOptions')
|
||||
) {
|
||||
continue
|
||||
}
|
||||
const val = singletonApp.config[key as keyof AppConfig]
|
||||
// @ts-ignore
|
||||
app.config[key] = val
|
||||
|
||||
// compat for runtime ignoredElements -> isCustomElement
|
||||
if (
|
||||
key === 'ignoredElements' &&
|
||||
isCompatEnabled(DeprecationTypes.CONFIG_IGNORED_ELEMENTS, null) &&
|
||||
!isRuntimeOnly() &&
|
||||
isArray(val)
|
||||
) {
|
||||
app.config.compilerOptions.isCustomElement = tag => {
|
||||
return val.some(v => (isString(v) ? v === tag : v.test(tag)))
|
||||
}
|
||||
}
|
||||
}
|
||||
isCopyingConfig = false
|
||||
|
||||
// copy prototype augmentations as config.globalProperties
|
||||
if (isCompatEnabled(DeprecationTypes.GLOBAL_PROTOTYPE, null)) {
|
||||
app.config.globalProperties = Ctor.prototype
|
||||
}
|
||||
let hasPrototypeAugmentations = false
|
||||
for (const key in Ctor.prototype) {
|
||||
if (key !== 'constructor') {
|
||||
hasPrototypeAugmentations = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if (__DEV__ && hasPrototypeAugmentations) {
|
||||
warnDeprecation(DeprecationTypes.GLOBAL_PROTOTYPE, null)
|
||||
if (Ctor !== Vue) {
|
||||
applySingletonPrototype(app, Ctor)
|
||||
}
|
||||
|
||||
const vm = app._createRoot!(options)
|
||||
@ -348,6 +310,66 @@ export function createCompatVue(
|
||||
return Vue
|
||||
}
|
||||
|
||||
export function applySingletonAppMutations(app: App, Ctor?: Function) {
|
||||
if (!singletonApp) {
|
||||
// this is the call of creating the singleton itself
|
||||
return
|
||||
}
|
||||
|
||||
// copy over asset registries and deopt flag
|
||||
;['mixins', 'components', 'directives', 'filters', 'deopt'].forEach(key => {
|
||||
// @ts-ignore
|
||||
app._context[key] = singletonApp._context[key]
|
||||
})
|
||||
|
||||
// copy over global config mutations
|
||||
isCopyingConfig = true
|
||||
for (const key in singletonApp.config) {
|
||||
if (key === 'isNativeTag') continue
|
||||
if (
|
||||
isRuntimeOnly() &&
|
||||
(key === 'isCustomElement' || key === 'compilerOptions')
|
||||
) {
|
||||
continue
|
||||
}
|
||||
const val = singletonApp.config[key as keyof AppConfig]
|
||||
// @ts-ignore
|
||||
app.config[key] = val
|
||||
|
||||
// compat for runtime ignoredElements -> isCustomElement
|
||||
if (
|
||||
key === 'ignoredElements' &&
|
||||
isCompatEnabled(DeprecationTypes.CONFIG_IGNORED_ELEMENTS, null) &&
|
||||
!isRuntimeOnly() &&
|
||||
isArray(val)
|
||||
) {
|
||||
app.config.compilerOptions.isCustomElement = tag => {
|
||||
return val.some(v => (isString(v) ? v === tag : v.test(tag)))
|
||||
}
|
||||
}
|
||||
}
|
||||
isCopyingConfig = false
|
||||
|
||||
applySingletonPrototype(app, singletonCtor)
|
||||
}
|
||||
|
||||
function applySingletonPrototype(app: App, Ctor: Function) {
|
||||
// copy prototype augmentations as config.globalProperties
|
||||
if (isCompatEnabled(DeprecationTypes.GLOBAL_PROTOTYPE, null)) {
|
||||
app.config.globalProperties = Ctor.prototype
|
||||
}
|
||||
let hasPrototypeAugmentations = false
|
||||
for (const key in Ctor.prototype) {
|
||||
if (key !== 'constructor') {
|
||||
hasPrototypeAugmentations = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if (__DEV__ && hasPrototypeAugmentations) {
|
||||
warnDeprecation(DeprecationTypes.GLOBAL_PROTOTYPE, null)
|
||||
}
|
||||
}
|
||||
|
||||
export function installCompatMount(
|
||||
app: App,
|
||||
context: AppContext,
|
||||
|
@ -6,6 +6,8 @@ import {
|
||||
deprecationData,
|
||||
toggleDeprecationWarning
|
||||
} from '../../runtime-core/src/compat/compatConfig'
|
||||
import { singletonApp } from '../../runtime-core/src/compat/global'
|
||||
import { createApp } from '../src/esm-index'
|
||||
|
||||
beforeEach(() => {
|
||||
toggleDeprecationWarning(false)
|
||||
@ -280,6 +282,15 @@ describe('GLOBAL_PROTOTYPE', () => {
|
||||
const plain = new Vue() as any
|
||||
expect(plain.$test).toBeUndefined()
|
||||
})
|
||||
|
||||
test('should affect apps created via createApp()', () => {
|
||||
Vue.prototype.$test = 1
|
||||
const vm = createApp({
|
||||
template: 'foo'
|
||||
}).mount(document.createElement('div')) as any
|
||||
expect(vm.$test).toBe(1)
|
||||
delete Vue.prototype.$test
|
||||
})
|
||||
})
|
||||
|
||||
describe('GLOBAL_SET/DELETE', () => {
|
||||
@ -381,3 +392,12 @@ describe('GLOBAL_PRIVATE_UTIL', () => {
|
||||
expect(n).toBe(2)
|
||||
})
|
||||
})
|
||||
|
||||
test('global asset registration should affect apps created via createApp', () => {
|
||||
Vue.component('foo', { template: 'foo' })
|
||||
const vm = createApp({
|
||||
template: '<foo/>'
|
||||
}).mount(document.createElement('div')) as any
|
||||
expect(vm.$el.textContent).toBe('foo')
|
||||
delete singletonApp._context.components.foo
|
||||
})
|
||||
|
@ -1,5 +1,6 @@
|
||||
import Vue from '@vue/compat'
|
||||
import { toggleDeprecationWarning } from '../../runtime-core/src/compat/compatConfig'
|
||||
import { createApp } from '../src/esm-index'
|
||||
import { triggerEvent } from './utils'
|
||||
|
||||
beforeEach(() => {
|
||||
@ -64,3 +65,12 @@ test('GLOBAL_IGNORED_ELEMENTS', () => {
|
||||
})
|
||||
expect(el.innerHTML).toBe(`<v-foo></v-foo><foo></foo>`)
|
||||
})
|
||||
|
||||
test('singleton config should affect apps created with createApp()', () => {
|
||||
Vue.config.ignoredElements = [/^v-/, 'foo']
|
||||
const el = document.createElement('div')
|
||||
createApp({
|
||||
template: `<v-foo/><foo/>`
|
||||
}).mount(el)
|
||||
expect(el.innerHTML).toBe(`<v-foo></v-foo><foo></foo>`)
|
||||
})
|
||||
|
@ -38,9 +38,7 @@ function wrappedCreateApp(...args: any[]) {
|
||||
}
|
||||
|
||||
export function createCompatVue() {
|
||||
const Vue = compatUtils.createCompatVue(wrappedCreateApp)
|
||||
const Vue = compatUtils.createCompatVue(createApp, wrappedCreateApp)
|
||||
extend(Vue, runtimeDom)
|
||||
// @ts-ignore
|
||||
Vue.createApp = wrappedCreateApp
|
||||
return Vue
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user