diff --git a/packages/compiler-core/__tests__/transforms/vBind.spec.ts b/packages/compiler-core/__tests__/transforms/vBind.spec.ts index 2221d926e52..ff21351d05d 100644 --- a/packages/compiler-core/__tests__/transforms/vBind.spec.ts +++ b/packages/compiler-core/__tests__/transforms/vBind.spec.ts @@ -112,6 +112,27 @@ describe('compiler: transform v-bind', () => { }) }) + test('no expression (shorthand) in-DOM templates', () => { + try { + __BROWSER__ = true + // :id in in-DOM templates will be parsed into :id="" by browser + const node = parseWithVBind(`
`) + const props = (node.codegenNode as VNodeCall).props as ObjectExpression + expect(props.properties[0]).toMatchObject({ + key: { + content: `id`, + isStatic: true, + }, + value: { + content: `id`, + isStatic: false, + }, + }) + } finally { + __BROWSER__ = false + } + }) + test('dynamic arg', () => { const node = parseWithVBind(``) const props = (node.codegenNode as VNodeCall).props as CallExpression diff --git a/packages/compiler-core/src/parser.ts b/packages/compiler-core/src/parser.ts index a6e25681d75..2d85289fc68 100644 --- a/packages/compiler-core/src/parser.ts +++ b/packages/compiler-core/src/parser.ts @@ -1054,7 +1054,7 @@ export function baseParse(input: string, options?: ParserOptions): RootNode { `[@vue/compiler-core] decodeEntities option is passed but will be ` + `ignored in non-browser builds.`, ) - } else if (__BROWSER__ && !currentOptions.decodeEntities) { + } else if (__BROWSER__ && !__TEST__ && !currentOptions.decodeEntities) { throw new Error( `[@vue/compiler-core] decodeEntities option is required in browser builds.`, ) diff --git a/packages/compiler-core/src/transforms/transformVBindShorthand.ts b/packages/compiler-core/src/transforms/transformVBindShorthand.ts index ff5b51047a3..a6b989e734a 100644 --- a/packages/compiler-core/src/transforms/transformVBindShorthand.ts +++ b/packages/compiler-core/src/transforms/transformVBindShorthand.ts @@ -15,7 +15,11 @@ export const transformVBindShorthand: NodeTransform = (node, context) => { if ( prop.type === NodeTypes.DIRECTIVE && prop.name === 'bind' && - !prop.exp + (!prop.exp || + // #13930 :foo in in-DOM templates will be parsed into :foo="" by browser + (__BROWSER__ && + prop.exp.type === NodeTypes.SIMPLE_EXPRESSION && + !prop.exp.content.trim())) ) { const arg = prop.arg! if (arg.type !== NodeTypes.SIMPLE_EXPRESSION || !arg.isStatic) {