[CompilerDeprecationTypes.COMPILER_V_BIND_OBJECT_ORDER]: {
message:
`v-bind="obj" usage is now order sensitive and behaves like JavaScript ` +
- `object spread: it will now overwrite an existing attribute that appears ` +
- `before v-bind in the case of conflicting keys. To retain 2.x behavior, ` +
- `move v-bind to and make it the first attribute. If all occurences ` +
- `of this warning are working as intended, you can suppress it.`,
+ `object spread: it will now overwrite an existing non-mergeable attribute ` +
+ `that appears before v-bind in the case of conflict. ` +
+ `To retain 2.x behavior, move v-bind to make it the first attribute. ` +
+ `You can also suppress this warning if the usage is intended.`,
link: `https://v3.vuejs.org/guide/migration/v-bind.html`
},
}
}
+export function isCompatEnabled(
+ key: CompilerDeprecationTypes,
+ context: ParserContext | TransformContext
+) {
+ const mode = getCompatValue('MODE', context)
+ const value = getCompatValue(key, context)
+ // in v3 mode, only enable if explicitly set to true
+ // otherwise enable for any non-false value
+ return mode === 3 ? value === true : value !== false
+}
+
export function checkCompatEnabled(
key: CompilerDeprecationTypes,
context: ParserContext | TransformContext,
loc: SourceLocation | null,
...args: any[]
): boolean {
- const mode = getCompatValue('MODE', context)
- const value = getCompatValue(key, context)
- // in v3 mode, only enable if explicitly set to true
- // otherwise enable for any non-false value
- const enabled = mode === 3 ? value === true : value !== false
+ const enabled = isCompatEnabled(key, context)
if (__DEV__ && enabled) {
warnDeprecation(key, context, loc, ...args)
}
import { buildSlots } from './vSlot'
import { getConstantType } from './hoistStatic'
import { BindingTypes } from '../options'
+import {
+ checkCompatEnabled,
+ CompilerDeprecationTypes,
+ isCompatEnabled
+} from '../compat/compatConfig'
// some directive transforms (e.g. v-model) may return a symbol for runtime
// import, which should be used instead of a resolveDirective call.
} else {
// directives
const { name, arg, exp, loc } = prop
- const isBind = name === 'bind'
- const isOn = name === 'on'
+ const isVBind = name === 'bind'
+ const isVOn = name === 'on'
// skip v-slot - it is handled by its dedicated transform.
if (name === 'slot') {
// skip v-is and :is on <component>
if (
name === 'is' ||
- (isBind && isComponentTag(tag) && isBindKey(arg, 'is'))
+ (isVBind && isComponentTag(tag) && isBindKey(arg, 'is'))
) {
continue
}
// skip v-on in SSR compilation
- if (isOn && ssr) {
+ if (isVOn && ssr) {
continue
}
// special case for v-bind and v-on with no argument
- if (!arg && (isBind || isOn)) {
+ if (!arg && (isVBind || isVOn)) {
hasDynamicKeys = true
if (exp) {
if (properties.length) {
)
properties = []
}
- if (isBind) {
+ if (isVBind) {
+ if (__COMPAT__) {
+ if (__DEV__) {
+ const hasOverridableKeys = mergeArgs.some(arg => {
+ if (arg.type === NodeTypes.JS_OBJECT_EXPRESSION) {
+ return arg.properties.some(({ key }) => {
+ if (
+ key.type !== NodeTypes.SIMPLE_EXPRESSION ||
+ !key.isStatic
+ ) {
+ return true
+ }
+ return (
+ key.content !== 'class' &&
+ key.content !== 'style' &&
+ !isOn(key.content)
+ )
+ })
+ } else {
+ // dynamic expression
+ return true
+ }
+ })
+ if (hasOverridableKeys) {
+ checkCompatEnabled(
+ CompilerDeprecationTypes.COMPILER_V_BIND_OBJECT_ORDER,
+ context,
+ loc
+ )
+ }
+ }
+
+ if (
+ isCompatEnabled(
+ CompilerDeprecationTypes.COMPILER_V_BIND_OBJECT_ORDER,
+ context
+ )
+ ) {
+ mergeArgs.unshift(exp)
+ continue
+ }
+ }
+
mergeArgs.push(exp)
} else {
// v-on="obj" -> toHandlers(obj)
} else {
context.onError(
createCompilerError(
- isBind
+ isVBind
? ErrorCodes.X_V_BIND_NO_EXPRESSION
: ErrorCodes.X_V_ON_NO_EXPRESSION,
loc