fix(compiler-sfc): fix sfc template unref rewrite for class instantiation

close #6483
close #6491
This commit is contained in:
Evan You 2024-01-04 15:57:54 +08:00
parent fda51925f4
commit ae60a91cc2
4 changed files with 59 additions and 2 deletions

View File

@ -146,6 +146,19 @@ export function isInDestructureAssignment(
return false
}
export function isInNewExpression(parentStack: Node[]): boolean {
let i = parentStack.length
while (i--) {
const p = parentStack[i]
if (p.type === 'NewExpression') {
return true
} else if (p.type !== 'MemberExpression') {
break
}
}
return false
}
export function walkFunctionParams(
node: Function,
onIdent: (id: Identifier) => void,

View File

@ -19,6 +19,7 @@ import {
} from '../ast'
import {
isInDestructureAssignment,
isInNewExpression,
isStaticProperty,
isStaticPropertyKey,
walkIdentifiers,
@ -131,6 +132,11 @@ export function processExpression(
// ({ x } = y)
const isDestructureAssignment =
parent && isInDestructureAssignment(parent, parentStack)
const isNewExpression = parent && isInNewExpression(parentStack)
const wrapWithUnref = (raw: string) => {
const wrapped = `${context.helperString(UNREF)}(${raw})`
return isNewExpression ? `(${wrapped})` : wrapped
}
if (
isConst(type) ||
@ -147,7 +153,7 @@ export function processExpression(
// that assumes the value to be a ref for more efficiency
return isAssignmentLVal || isUpdateArg || isDestructureAssignment
? `${raw}.value`
: `${context.helperString(UNREF)}(${raw})`
: wrapWithUnref(raw)
} else if (type === BindingTypes.SETUP_LET) {
if (isAssignmentLVal) {
// let binding.
@ -190,7 +196,7 @@ export function processExpression(
// for now
return raw
} else {
return `${context.helperString(UNREF)}(${raw})`
return wrapWithUnref(raw)
}
} else if (type === BindingTypes.PROPS) {
// use __props which is generated by compileScript so in ts mode

View File

@ -1028,6 +1028,26 @@ return (_ctx, _cache) => {
}"
`;
exports[`SFC compile <script setup> > inlineTemplate mode > unref + new expression 1`] = `
"import { unref as _unref, toDisplayString as _toDisplayString, createElementVNode as _createElementVNode, Fragment as _Fragment, openBlock as _openBlock, createElementBlock as _createElementBlock } from "vue"
import Foo from './foo'
export default {
setup(__props) {
return (_ctx, _cache) => {
return (_openBlock(), _createElementBlock(_Fragment, null, [
_createElementVNode("div", null, _toDisplayString(new (_unref(Foo))()), 1 /* TEXT */),
_createElementVNode("div", null, _toDisplayString(new (_unref(Foo)).Bar()), 1 /* TEXT */)
], 64 /* STABLE_FRAGMENT */))
}
}
}"
`;
exports[`SFC compile <script setup> > inlineTemplate mode > v-model codegen 1`] = `
"import { vModelText as _vModelText, createElementVNode as _createElementVNode, withDirectives as _withDirectives, unref as _unref, isRef as _isRef, Fragment as _Fragment, openBlock as _openBlock, createElementBlock as _createElementBlock } from "vue"

View File

@ -650,6 +650,24 @@ describe('SFC compile <script setup>', () => {
),
).not.toThrowError()
})
test('unref + new expression', () => {
const { content } = compile(
`
<script setup>
import Foo from './foo'
</script>
<template>
<div>{{ new Foo() }}</div>
<div>{{ new Foo.Bar() }}</div>
</template>
`,
{ inlineTemplate: true },
)
expect(content).toMatch(`new (_unref(Foo))()`)
expect(content).toMatch(`new (_unref(Foo)).Bar()`)
assertCode(content)
})
})
describe('with TypeScript', () => {