wip: support configuring compiler deprecations at runtime + warn invalid deprecation configs
This commit is contained in:
parent
79cbf21c3e
commit
bbf708dbe9
@ -14,14 +14,14 @@ export interface CompilerCompatOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const enum CompilerDeprecationTypes {
|
export const enum CompilerDeprecationTypes {
|
||||||
IS_ON_ELEMENT = 'IS_ON_ELEMENT',
|
COMPILER_IS_ON_ELEMENT = 'COMPILER_IS_ON_ELEMENT',
|
||||||
V_BIND_SYNC = 'V_BIND_SYNC',
|
COMPILER_V_BIND_SYNC = 'COMPILER_V_BIND_SYNC',
|
||||||
V_BIND_OBJECT_ORDER = 'V_BIND_OBJECT_ORDER',
|
COMPILER_V_BIND_OBJECT_ORDER = 'COMPILER_V_BIND_OBJECT_ORDER',
|
||||||
V_ON_NATIVE_MODIFIER = 'V_ON_NATIVE_MODIFIER',
|
COMPILER_V_ON_NATIVE_MODIFIER = 'COMPILER_V_ON_NATIVE_MODIFIER',
|
||||||
KEY_V_IF = 'KEY_V_IF',
|
COMPILER_KEY_V_IF = 'COMPILER_KEY_V_IF',
|
||||||
KEY_V_FOR_TEMPLATE = 'KEY_V_FOR_TEMPLATE',
|
COMPILER_KEY_V_FOR_TEMPLATE = 'COMPILER_KEY_V_FOR_TEMPLATE',
|
||||||
V_IF_V_FOR_PRECEDENCE = 'V_IF_V_FOR_PRECEDENCE',
|
COMPILER_V_IF_V_FOR_PRECEDENCE = 'COMPILER_V_IF_V_FOR_PRECEDENCE',
|
||||||
NATIVE_TEMPLATE = 'NATIVE_TEMPLATE'
|
COMPILER_NATIVE_TEMPLATE = 'COMPILER_NATIVE_TEMPLATE'
|
||||||
}
|
}
|
||||||
|
|
||||||
type DeprecationData = {
|
type DeprecationData = {
|
||||||
@ -30,7 +30,7 @@ type DeprecationData = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const deprecationData: Record<CompilerDeprecationTypes, DeprecationData> = {
|
const deprecationData: Record<CompilerDeprecationTypes, DeprecationData> = {
|
||||||
[CompilerDeprecationTypes.IS_ON_ELEMENT]: {
|
[CompilerDeprecationTypes.COMPILER_IS_ON_ELEMENT]: {
|
||||||
message:
|
message:
|
||||||
`Platform-native elements with "is" prop will no longer be ` +
|
`Platform-native elements with "is" prop will no longer be ` +
|
||||||
`treated as components in Vue 3 unless the "is" value is explicitly ` +
|
`treated as components in Vue 3 unless the "is" value is explicitly ` +
|
||||||
@ -38,7 +38,7 @@ const deprecationData: Record<CompilerDeprecationTypes, DeprecationData> = {
|
|||||||
link: `https://v3.vuejs.org/guide/migration/custom-elements-interop.html`
|
link: `https://v3.vuejs.org/guide/migration/custom-elements-interop.html`
|
||||||
},
|
},
|
||||||
|
|
||||||
[CompilerDeprecationTypes.V_BIND_SYNC]: {
|
[CompilerDeprecationTypes.COMPILER_V_BIND_SYNC]: {
|
||||||
message: key =>
|
message: key =>
|
||||||
`.sync modifier for v-bind has been removed. Use v-model with ` +
|
`.sync modifier for v-bind has been removed. Use v-model with ` +
|
||||||
`argument instead. \`v-bind:${key}.sync\` should be changed to ` +
|
`argument instead. \`v-bind:${key}.sync\` should be changed to ` +
|
||||||
@ -46,7 +46,7 @@ const deprecationData: Record<CompilerDeprecationTypes, DeprecationData> = {
|
|||||||
link: `https://v3.vuejs.org/guide/migration/v-model.html`
|
link: `https://v3.vuejs.org/guide/migration/v-model.html`
|
||||||
},
|
},
|
||||||
|
|
||||||
[CompilerDeprecationTypes.V_BIND_OBJECT_ORDER]: {
|
[CompilerDeprecationTypes.COMPILER_V_BIND_OBJECT_ORDER]: {
|
||||||
message:
|
message:
|
||||||
`v-bind="obj" usage is now order sensitive and behaves like JavaScript ` +
|
`v-bind="obj" usage is now order sensitive and behaves like JavaScript ` +
|
||||||
`object spread: it will now overwrite an existing attribute that appears ` +
|
`object spread: it will now overwrite an existing attribute that appears ` +
|
||||||
@ -56,22 +56,22 @@ const deprecationData: Record<CompilerDeprecationTypes, DeprecationData> = {
|
|||||||
link: `https://v3.vuejs.org/guide/migration/v-bind.html`
|
link: `https://v3.vuejs.org/guide/migration/v-bind.html`
|
||||||
},
|
},
|
||||||
|
|
||||||
[CompilerDeprecationTypes.V_ON_NATIVE_MODIFIER]: {
|
[CompilerDeprecationTypes.COMPILER_V_ON_NATIVE_MODIFIER]: {
|
||||||
message: `.native modifier for v-on has been removed as is no longer necessary.`,
|
message: `.native modifier for v-on has been removed as is no longer necessary.`,
|
||||||
link: `https://v3.vuejs.org/guide/migration/v-on-native-modifier-removed.html`
|
link: `https://v3.vuejs.org/guide/migration/v-on-native-modifier-removed.html`
|
||||||
},
|
},
|
||||||
|
|
||||||
[CompilerDeprecationTypes.KEY_V_IF]: {
|
[CompilerDeprecationTypes.COMPILER_KEY_V_IF]: {
|
||||||
message: ``,
|
message: ``,
|
||||||
link: `https://v3.vuejs.org/guide/migration/key-attribute.html#on-conditional-branches`
|
link: `https://v3.vuejs.org/guide/migration/key-attribute.html#on-conditional-branches`
|
||||||
},
|
},
|
||||||
|
|
||||||
[CompilerDeprecationTypes.KEY_V_FOR_TEMPLATE]: {
|
[CompilerDeprecationTypes.COMPILER_KEY_V_FOR_TEMPLATE]: {
|
||||||
message: ``,
|
message: ``,
|
||||||
link: `https://v3.vuejs.org/guide/migration/key-attribute.html#with-template-v-for`
|
link: `https://v3.vuejs.org/guide/migration/key-attribute.html#with-template-v-for`
|
||||||
},
|
},
|
||||||
|
|
||||||
[CompilerDeprecationTypes.V_IF_V_FOR_PRECEDENCE]: {
|
[CompilerDeprecationTypes.COMPILER_V_IF_V_FOR_PRECEDENCE]: {
|
||||||
message:
|
message:
|
||||||
`v-if / v-for precedence when used on the same element has changed ` +
|
`v-if / v-for precedence when used on the same element has changed ` +
|
||||||
`in Vue 3. It is best to avoid the ambiguity with either <template> tags ` +
|
`in Vue 3. It is best to avoid the ambiguity with either <template> tags ` +
|
||||||
@ -79,7 +79,7 @@ const deprecationData: Record<CompilerDeprecationTypes, DeprecationData> = {
|
|||||||
link: `https://v3.vuejs.org/guide/migration/v-if-v-for.html`
|
link: `https://v3.vuejs.org/guide/migration/v-if-v-for.html`
|
||||||
},
|
},
|
||||||
|
|
||||||
[CompilerDeprecationTypes.NATIVE_TEMPLATE]: {
|
[CompilerDeprecationTypes.COMPILER_NATIVE_TEMPLATE]: {
|
||||||
message:
|
message:
|
||||||
`<template> with no special directives will render as a native template` +
|
`<template> with no special directives will render as a native template` +
|
||||||
`element instead of its inner content in Vue 3.`
|
`element instead of its inner content in Vue 3.`
|
||||||
|
@ -517,7 +517,7 @@ function parseTag(
|
|||||||
if (
|
if (
|
||||||
__COMPAT__ &&
|
__COMPAT__ &&
|
||||||
checkCompatEnabled(
|
checkCompatEnabled(
|
||||||
CompilerDeprecationTypes.IS_ON_ELEMENT,
|
CompilerDeprecationTypes.COMPILER_IS_ON_ELEMENT,
|
||||||
context,
|
context,
|
||||||
p.loc
|
p.loc
|
||||||
)
|
)
|
||||||
|
@ -96,7 +96,7 @@ export const transformOn: DirectiveTransform = (dir, node, context) => {
|
|||||||
|
|
||||||
if (__COMPAT__ && __DEV__ && modifiers.includes('native')) {
|
if (__COMPAT__ && __DEV__ && modifiers.includes('native')) {
|
||||||
warnDeprecation(
|
warnDeprecation(
|
||||||
CompilerDeprecationTypes.V_ON_NATIVE_MODIFIER,
|
CompilerDeprecationTypes.COMPILER_V_ON_NATIVE_MODIFIER,
|
||||||
context,
|
context,
|
||||||
dir.loc
|
dir.loc
|
||||||
)
|
)
|
||||||
|
@ -456,12 +456,48 @@ export type CompatConfig = Partial<
|
|||||||
MODE?: 2 | 3
|
MODE?: 2 | 3
|
||||||
}
|
}
|
||||||
|
|
||||||
const globalCompatConfig: CompatConfig = {}
|
export const globalCompatConfig: CompatConfig = {}
|
||||||
|
|
||||||
export function configureCompat(config: CompatConfig) {
|
export function configureCompat(config: CompatConfig) {
|
||||||
|
if (__DEV__) {
|
||||||
|
validateCompatConfig(config)
|
||||||
|
}
|
||||||
extend(globalCompatConfig, config)
|
extend(globalCompatConfig, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const seenConfigObjects = /*#__PURE__*/ new WeakSet<CompatConfig>()
|
||||||
|
const warnedInvalidKeys: Record<string, boolean> = {}
|
||||||
|
|
||||||
|
// dev only
|
||||||
|
export function validateCompatConfig(config: CompatConfig) {
|
||||||
|
if (seenConfigObjects.has(config)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
seenConfigObjects.add(config)
|
||||||
|
|
||||||
|
for (const key of Object.keys(config)) {
|
||||||
|
if (
|
||||||
|
key !== 'MODE' &&
|
||||||
|
!(key in deprecationData) &&
|
||||||
|
!(key in warnedInvalidKeys)
|
||||||
|
) {
|
||||||
|
if (key.startsWith('COMPILER_')) {
|
||||||
|
if (isRuntimeOnly()) {
|
||||||
|
warn(
|
||||||
|
`Depreaction config "${key}" is compiler-specific and you are ` +
|
||||||
|
`running a runtime-only build of Vue. This deprecation should be ` +
|
||||||
|
`configured via compiler options in your build setup instead.`
|
||||||
|
// TODO link to migration build docs on build setup
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
warn(`Invalid deprecation config "${key}".`)
|
||||||
|
}
|
||||||
|
warnedInvalidKeys[key] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function getCompatConfigForKey(
|
export function getCompatConfigForKey(
|
||||||
key: DeprecationTypes | 'MODE',
|
key: DeprecationTypes | 'MODE',
|
||||||
instance: ComponentInternalInstance | null
|
instance: ComponentInternalInstance | null
|
||||||
|
@ -47,7 +47,8 @@ import {
|
|||||||
NO,
|
NO,
|
||||||
makeMap,
|
makeMap,
|
||||||
isPromise,
|
isPromise,
|
||||||
ShapeFlags
|
ShapeFlags,
|
||||||
|
extend
|
||||||
} from '@vue/shared'
|
} from '@vue/shared'
|
||||||
import { SuspenseBoundary } from './components/Suspense'
|
import { SuspenseBoundary } from './components/Suspense'
|
||||||
import { CompilerOptions } from '@vue/compiler-core'
|
import { CompilerOptions } from '@vue/compiler-core'
|
||||||
@ -55,6 +56,7 @@ import { markAttrsAccessed } from './componentRenderUtils'
|
|||||||
import { currentRenderingInstance } from './componentRenderContext'
|
import { currentRenderingInstance } from './componentRenderContext'
|
||||||
import { startMeasure, endMeasure } from './profiling'
|
import { startMeasure, endMeasure } from './profiling'
|
||||||
import { convertLegacyRenderFn } from './compat/renderFn'
|
import { convertLegacyRenderFn } from './compat/renderFn'
|
||||||
|
import { globalCompatConfig, validateCompatConfig } from './compat/compatConfig'
|
||||||
|
|
||||||
export type Data = Record<string, unknown>
|
export type Data = Record<string, unknown>
|
||||||
|
|
||||||
@ -692,6 +694,10 @@ export function finishComponentSetup(
|
|||||||
|
|
||||||
if (__COMPAT__) {
|
if (__COMPAT__) {
|
||||||
convertLegacyRenderFn(instance)
|
convertLegacyRenderFn(instance)
|
||||||
|
|
||||||
|
if (__DEV__ && Component.compatConfig) {
|
||||||
|
validateCompatConfig(Component.compatConfig)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// template / render function normalization
|
// template / render function normalization
|
||||||
@ -710,10 +716,18 @@ export function finishComponentSetup(
|
|||||||
if (__DEV__) {
|
if (__DEV__) {
|
||||||
startMeasure(instance, `compile`)
|
startMeasure(instance, `compile`)
|
||||||
}
|
}
|
||||||
Component.render = compile(Component.template, {
|
const compilerOptions: CompilerOptions = {
|
||||||
isCustomElement: instance.appContext.config.isCustomElement,
|
isCustomElement: instance.appContext.config.isCustomElement,
|
||||||
delimiters: Component.delimiters
|
delimiters: Component.delimiters
|
||||||
})
|
}
|
||||||
|
if (__COMPAT__) {
|
||||||
|
// pass runtime compat config into the compiler
|
||||||
|
compilerOptions.compatConfig = Object.create(globalCompatConfig)
|
||||||
|
if (Component.compatConfig) {
|
||||||
|
extend(compilerOptions.compatConfig, Component.compatConfig)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Component.render = compile(Component.template, compilerOptions)
|
||||||
if (__DEV__) {
|
if (__DEV__) {
|
||||||
endMeasure(instance, `compile`)
|
endMeasure(instance, `compile`)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user