wip: compat configuration

This commit is contained in:
Evan You 2021-04-07 11:22:56 -04:00
parent 068d93b9e5
commit e2fc84c773
8 changed files with 111 additions and 52 deletions

View File

@ -0,0 +1,26 @@
import { extend } from '@vue/shared'
import { DeprecationTypes } from './deprecations'
export type CompatConfig = Partial<
Record<DeprecationTypes, DeprecationConfigItem>
>
export interface DeprecationConfigItem {
warning?: boolean // defaults to true
mode?: 2 | 3 // defaults to 2
}
const globalCompatConfig: CompatConfig = {}
export function configureCompat(config: CompatConfig) {
extend(globalCompatConfig, config)
}
/**
* @internal
*/
export function getCompatConfig(
key: DeprecationTypes
): DeprecationConfigItem | undefined {
return globalCompatConfig[key]
}

View File

@ -1,37 +1,38 @@
import { isRuntimeOnly } from '../component' import { isRuntimeOnly } from '../component'
import { warn } from '../warning' import { warn } from '../warning'
import { getCompatConfig } from './compatConfig'
export const enum DeprecationTypes { export const enum DeprecationTypes {
CONFIG_SILENT, CONFIG_SILENT = 'CONFIG_SILENT',
CONFIG_DEVTOOLS, CONFIG_DEVTOOLS = 'CONFIG_DEVTOOLS',
CONFIG_KEY_CODES, CONFIG_KEY_CODES = 'CONFIG_KEY_CODES',
CONFIG_PRODUCTION_TIP, CONFIG_PRODUCTION_TIP = 'CONFIG_PRODUCTION_TIP',
CONFIG_IGNORED_ELEMENTS, CONFIG_IGNORED_ELEMENTS = 'CONFIG_IGNORED_ELEMENTS',
GLOBAL_PROTOTYPE, GLOBAL_PROTOTYPE = 'GLOBAL_PROTOTYPE',
GLOBAL_SET, GLOBAL_SET = 'GLOBAL_SET',
GLOBAL_DELETE, GLOBAL_DELETE = 'GLOBAL_DELETE',
GLOBAL_OBSERVABLE, GLOBAL_OBSERVABLE = 'GLOBAL_OBSERVABLE',
GLOBAL_DOM_TEMPLATE_MOUNT, GLOBAL_MOUNT_CONTAINER = 'GLOBAL_MOUNT_CONTAINER',
INSTANCE_SET, INSTANCE_SET = 'INSTANCE_SET',
INSTANCE_DELETE, INSTANCE_DELETE = 'INSTANCE_DELETE',
INSTANCE_MOUNT, INSTANCE_MOUNT = 'INSTANCE_MOUNT',
INSTANCE_DESTROY, INSTANCE_DESTROY = 'INSTANCE_DESTROY',
INSTANCE_EVENT_EMITTER, INSTANCE_EVENT_EMITTER = 'INSTANCE_EVENT_EMITTER',
INSTANCE_EVENT_HOOKS, INSTANCE_EVENT_HOOKS = 'INSTANCE_EVENT_HOOKS',
INSTANCE_CHILDREN, INSTANCE_CHILDREN = 'INSTANCE_CHILDREN',
OPTIONS_DATA_FN, OPTIONS_DATA_FN = 'OPTIONS_DATA_FN',
OPTIONS_DATA_MERGE, OPTIONS_DATA_MERGE = 'OPTIONS_DATA_MERGE',
OPTIONS_BEFORE_DESTROY, OPTIONS_BEFORE_DESTROY = 'OPTIONS_BEFORE_DESTROY',
OPTIONS_DESTROYED, OPTIONS_DESTROYED = 'OPTIONS_DESTROYED',
PROPS_DEFAULT_THIS, PROPS_DEFAULT_THIS = 'PROPS_DEFAULT_THIS',
CUSTOM_DIR, CUSTOM_DIR = 'CUSTOM_DIR',
V_ON_KEYCODE_MODIFIER V_ON_KEYCODE_MODIFIER = 'V_ON_KEYCODE_MODIFIER'
} }
type DeprecationData = { type DeprecationData = {
@ -39,7 +40,7 @@ type DeprecationData = {
link?: string link?: string
} }
const deprecations: Record<DeprecationTypes, DeprecationData> = { const deprecationMessages: Record<DeprecationTypes, DeprecationData> = {
[DeprecationTypes.CONFIG_SILENT]: { [DeprecationTypes.CONFIG_SILENT]: {
message: message:
`config.silent has been removed because it is not good practice to ` + `config.silent has been removed because it is not good practice to ` +
@ -105,7 +106,7 @@ const deprecations: Record<DeprecationTypes, DeprecationData> = {
link: `https://v3.vuejs.org/api/basic-reactivity.html` link: `https://v3.vuejs.org/api/basic-reactivity.html`
}, },
[DeprecationTypes.GLOBAL_DOM_TEMPLATE_MOUNT]: { [DeprecationTypes.GLOBAL_MOUNT_CONTAINER]: {
message: message:
`Vue detected directives on the mount container. ` + `Vue detected directives on the mount container. ` +
`In Vue 3, the container is no longer considered part of the template ` + `In Vue 3, the container is no longer considered part of the template ` +
@ -204,18 +205,30 @@ const deprecations: Record<DeprecationTypes, DeprecationData> = {
const hasWarned: Record<string, boolean> = {} const hasWarned: Record<string, boolean> = {}
/**
* @internal
*/
export function warnDeprecation(key: DeprecationTypes, ...args: any[]) { export function warnDeprecation(key: DeprecationTypes, ...args: any[]) {
if (!__COMPAT__ || !__DEV__) { if (!__DEV__) {
return return
} }
// check user config
const config = getCompatConfig(key)
if (config && config.warning === false) {
return
}
// avoid spamming the same message
const dupKey = key + args.join('') const dupKey = key + args.join('')
if (hasWarned[dupKey]) { if (hasWarned[dupKey]) {
return return
} }
hasWarned[dupKey] = true hasWarned[dupKey] = true
const { message, link } = deprecations[key] const { message, link } = deprecationMessages[key]
warn( warn(
`[DEPRECATION] ${ `(DEPRECATION ${key}) ${
typeof message === 'function' ? message(...args) : message typeof message === 'function' ? message(...args) : message
}${link ? `\n Details: ${link}` : ``}` }${link ? `\n Details: ${link}` : ``}`
) )

View File

@ -29,6 +29,7 @@ import { warnDeprecation, DeprecationTypes } from './deprecations'
import { version } from '..' import { version } from '..'
import { LegacyConfig } from './globalConfig' import { LegacyConfig } from './globalConfig'
import { LegacyDirective } from './customDirective' import { LegacyDirective } from './customDirective'
import { configureCompat } from './compatConfig'
/** /**
* @deprecated the default `Vue` export has been removed in Vue 3. The type for * @deprecated the default `Vue` export has been removed in Vue 3. The type for
@ -73,6 +74,8 @@ export type CompatVue = Pick<App, 'version' | 'component' | 'directive'> & {
* @deprecated filters have been removed from Vue 3. * @deprecated filters have been removed from Vue 3.
*/ */
filter(name: string, arg: any): null filter(name: string, arg: any): null
configureCompat: typeof configureCompat
} }
export let isCopyingConfig = false export let isCopyingConfig = false
@ -81,11 +84,6 @@ export let isCopyingConfig = false
export function createCompatVue( export function createCompatVue(
createApp: CreateAppFunction<Element> createApp: CreateAppFunction<Element>
): CompatVue { ): CompatVue {
if (!__COMPAT__) {
// @ts-ignore this function will never be called in non-compat mode
return
}
const Vue: CompatVue = function Vue(options: ComponentOptions = {}) { const Vue: CompatVue = function Vue(options: ComponentOptions = {}) {
return createCompatApp(options, Vue) return createCompatApp(options, Vue)
} as any } as any
@ -215,6 +213,8 @@ export function createCompatVue(
// TODO compiler warning for filters (maybe behavior compat?) // TODO compiler warning for filters (maybe behavior compat?)
}) as any }) as any
Vue.configureCompat = configureCompat
return Vue return Vue
} }
@ -306,7 +306,7 @@ export function installCompatMount(
for (let i = 0; i < container.attributes.length; i++) { for (let i = 0; i < container.attributes.length; i++) {
const attr = container.attributes[i] const attr = container.attributes[i]
if (attr.name !== 'v-cloak' && /^(v-|:|@)/.test(attr.name)) { if (attr.name !== 'v-cloak' && /^(v-|:|@)/.test(attr.name)) {
warnDeprecation(DeprecationTypes.GLOBAL_DOM_TEMPLATE_MOUNT) warnDeprecation(DeprecationTypes.GLOBAL_MOUNT_CONTAINER)
break break
} }
} }

View File

@ -282,8 +282,20 @@ export const ssrUtils = (__NODE_JS__ ? _ssrUtils : null) as typeof _ssrUtils
// 2.x COMPAT ------------------------------------------------------------------ // 2.x COMPAT ------------------------------------------------------------------
// Important: every function exported here must have `if (!__COMPAT__) return` export { DeprecationTypes } from './compat/deprecations'
// checks export { CompatVue } from './compat/global'
export { warnDeprecation, DeprecationTypes } from './compat/deprecations'
export { createCompatVue, CompatVue } from './compat/global'
export { LegacyConfig } from './compat/globalConfig' export { LegacyConfig } from './compat/globalConfig'
import { warnDeprecation } from './compat/deprecations'
import { createCompatVue } from './compat/global'
import { getCompatConfig } from './compat/compatConfig'
const _compatUtils = {
warnDeprecation,
createCompatVue,
getCompatConfig
}
export const compatUtils = (__COMPAT__
? _compatUtils
: null) as typeof _compatUtils

View File

@ -1,8 +1,8 @@
import { import {
DeprecationTypes,
warnDeprecation,
getCurrentInstance, getCurrentInstance,
LegacyConfig DeprecationTypes,
LegacyConfig,
compatUtils
} from '@vue/runtime-core' } from '@vue/runtime-core'
import { hyphenate, isArray } from '@vue/shared' import { hyphenate, isArray } from '@vue/shared'
@ -62,7 +62,7 @@ export const withKeys = (fn: Function, modifiers: string[]) => {
keyCodes = ((getCurrentInstance()!.appContext keyCodes = ((getCurrentInstance()!.appContext
.config as any) as LegacyConfig).keyCodes .config as any) as LegacyConfig).keyCodes
if (__DEV__ && modifiers.some(m => /^\d+$/.test(m))) { if (__DEV__ && modifiers.some(m => /^\d+$/.test(m))) {
warnDeprecation(DeprecationTypes.V_ON_KEYCODE_MODIFIER) compatUtils.warnDeprecation(DeprecationTypes.V_ON_KEYCODE_MODIFIER)
} }
} }

View File

@ -9,8 +9,8 @@ import {
App, App,
RootHydrateFunction, RootHydrateFunction,
isRuntimeOnly, isRuntimeOnly,
warnDeprecation, DeprecationTypes,
DeprecationTypes compatUtils
} from '@vue/runtime-core' } from '@vue/runtime-core'
import { nodeOps } from './nodeOps' import { nodeOps } from './nodeOps'
import { patchProp, forcePatchProp } from './patchProp' import { patchProp, forcePatchProp } from './patchProp'
@ -78,7 +78,7 @@ export const createApp = ((...args) => {
for (let i = 0; i < container.attributes.length; i++) { for (let i = 0; i < container.attributes.length; i++) {
const attr = container.attributes[i] const attr = container.attributes[i]
if (attr.name !== 'v-cloak' && /^(v-|:|@)/.test(attr.name)) { if (attr.name !== 'v-cloak' && /^(v-|:|@)/.test(attr.name)) {
warnDeprecation(DeprecationTypes.GLOBAL_DOM_TEMPLATE_MOUNT) compatUtils.warnDeprecation(DeprecationTypes.GLOBAL_MOUNT_CONTAINER)
break break
} }
} }

View File

@ -7,7 +7,7 @@ import {
RenderFunction, RenderFunction,
warn, warn,
createApp, createApp,
createCompatVue compatUtils
} from '@vue/runtime-dom' } from '@vue/runtime-dom'
import { isString, NOOP, generateCodeFrame, extend } from '@vue/shared' import { isString, NOOP, generateCodeFrame, extend } from '@vue/shared'
import { InternalRenderFunction } from 'packages/runtime-core/src/component' import { InternalRenderFunction } from 'packages/runtime-core/src/component'
@ -92,9 +92,10 @@ function compileToFunction(
registerRuntimeCompiler(compileToFunction) registerRuntimeCompiler(compileToFunction)
const Vue = createCompatVue(createApp) const Vue = compatUtils.createCompatVue(createApp)
Vue.compile = compileToFunction Vue.compile = compileToFunction
extend(Vue, runtimeDom) extend(Vue, runtimeDom)
export default Vue export default Vue

View File

@ -1,15 +1,18 @@
// This entry exports the runtime only, and is built as // This entry exports the runtime only, and is built as
// `dist/vue.esm-bundler.js` which is used by default for bundlers. // `dist/vue.esm-bundler.js` which is used by default for bundlers.
import { initDev } from './dev' import { initDev } from './dev'
import { warn } from '@vue/runtime-dom' import { compatUtils, createApp, warn } from '@vue/runtime-dom'
import { extend } from '@vue/shared'
if (__DEV__) { if (__DEV__) {
initDev() initDev()
} }
export * from '@vue/runtime-dom' import * as runtimeDom from '@vue/runtime-dom'
export const compile = () => { const Vue = compatUtils.createCompatVue(createApp)
Vue.compile = (() => {
if (__DEV__) { if (__DEV__) {
warn( warn(
`Runtime compilation is not supported in this build of Vue.` + `Runtime compilation is not supported in this build of Vue.` +
@ -22,4 +25,8 @@ export const compile = () => {
: ``) /* should not happen */ : ``) /* should not happen */
) )
} }
} }) as any
extend(Vue, runtimeDom)
export default Vue