fix(compiler-sfc): fix script setup ref assignment codegen edge case (#4520)
fix #4514
This commit is contained in:
parent
e6fe751b20
commit
5594643d7b
@ -99,7 +99,8 @@ export function processExpression(
|
|||||||
// function params
|
// function params
|
||||||
asParams = false,
|
asParams = false,
|
||||||
// v-on handler values may contain multiple statements
|
// v-on handler values may contain multiple statements
|
||||||
asRawStatements = false
|
asRawStatements = false,
|
||||||
|
localVars: Record<string, number> = Object.create(context.identifiers)
|
||||||
): ExpressionNode {
|
): ExpressionNode {
|
||||||
if (__BROWSER__) {
|
if (__BROWSER__) {
|
||||||
if (__DEV__) {
|
if (__DEV__) {
|
||||||
@ -127,7 +128,7 @@ export function processExpression(
|
|||||||
const isDestructureAssignment =
|
const isDestructureAssignment =
|
||||||
parent && isInDestructureAssignment(parent, parentStack)
|
parent && isInDestructureAssignment(parent, parentStack)
|
||||||
|
|
||||||
if (type === BindingTypes.SETUP_CONST) {
|
if (type === BindingTypes.SETUP_CONST || localVars[raw]) {
|
||||||
return raw
|
return raw
|
||||||
} else if (type === BindingTypes.SETUP_REF) {
|
} else if (type === BindingTypes.SETUP_REF) {
|
||||||
return `${raw}.value`
|
return `${raw}.value`
|
||||||
@ -149,7 +150,13 @@ export function processExpression(
|
|||||||
const { right: rVal, operator } = parent as AssignmentExpression
|
const { right: rVal, operator } = parent as AssignmentExpression
|
||||||
const rExp = rawExp.slice(rVal.start! - 1, rVal.end! - 1)
|
const rExp = rawExp.slice(rVal.start! - 1, rVal.end! - 1)
|
||||||
const rExpString = stringifyExpression(
|
const rExpString = stringifyExpression(
|
||||||
processExpression(createSimpleExpression(rExp, false), context)
|
processExpression(
|
||||||
|
createSimpleExpression(rExp, false),
|
||||||
|
context,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
knownIds
|
||||||
|
)
|
||||||
)
|
)
|
||||||
return `${context.helperString(IS_REF)}(${raw})${
|
return `${context.helperString(IS_REF)}(${raw})${
|
||||||
context.isTS ? ` //@ts-ignore\n` : ``
|
context.isTS ? ` //@ts-ignore\n` : ``
|
||||||
@ -190,6 +197,7 @@ export function processExpression(
|
|||||||
return `$${type}.${raw}`
|
return `$${type}.${raw}`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// fallback to ctx
|
// fallback to ctx
|
||||||
return `_ctx.${raw}`
|
return `_ctx.${raw}`
|
||||||
}
|
}
|
||||||
@ -246,7 +254,6 @@ export function processExpression(
|
|||||||
}
|
}
|
||||||
|
|
||||||
type QualifiedId = Identifier & PrefixMeta
|
type QualifiedId = Identifier & PrefixMeta
|
||||||
|
|
||||||
const ids: QualifiedId[] = []
|
const ids: QualifiedId[] = []
|
||||||
const parentStack: Node[] = []
|
const parentStack: Node[] = []
|
||||||
const knownIds: Record<string, number> = Object.create(context.identifiers)
|
const knownIds: Record<string, number> = Object.create(context.identifiers)
|
||||||
|
@ -157,7 +157,7 @@ return { props, bar }
|
|||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`SFC compile <script setup> defineProps/defineEmits in multi-variable decalration (full removal) 1`] = `
|
exports[`SFC compile <script setup> defineProps/defineEmits in multi-variable declaration (full removal) 1`] = `
|
||||||
"export default {
|
"export default {
|
||||||
props: ['item'],
|
props: ['item'],
|
||||||
emits: ['a'],
|
emits: ['a'],
|
||||||
@ -173,7 +173,7 @@ return { props, emit }
|
|||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`SFC compile <script setup> defineProps/defineEmits in multi-variable decalration 1`] = `
|
exports[`SFC compile <script setup> defineProps/defineEmits in multi-variable declaration 1`] = `
|
||||||
"export default {
|
"export default {
|
||||||
props: ['item'],
|
props: ['item'],
|
||||||
emits: ['a'],
|
emits: ['a'],
|
||||||
@ -506,7 +506,7 @@ return (_ctx, _push, _parent, _attrs) => {
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`SFC compile <script setup> inlineTemplate mode template assignment expression codegen 1`] = `
|
exports[`SFC compile <script setup> inlineTemplate mode template assignment expression codegen 1`] = `
|
||||||
"import { createElementVNode as _createElementVNode, isRef as _isRef, Fragment as _Fragment, openBlock as _openBlock, createElementBlock as _createElementBlock } from \\"vue\\"
|
"import { createElementVNode as _createElementVNode, isRef as _isRef, unref as _unref, Fragment as _Fragment, openBlock as _openBlock, createElementBlock as _createElementBlock } from \\"vue\\"
|
||||||
|
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
|
|
||||||
@ -534,6 +534,26 @@ return (_ctx, _cache) => {
|
|||||||
}),
|
}),
|
||||||
_createElementVNode(\\"div\\", {
|
_createElementVNode(\\"div\\", {
|
||||||
onClick: _cache[4] || (_cache[4] = $event => (_isRef(v) ? v.value -= 1 : v -= 1))
|
onClick: _cache[4] || (_cache[4] = $event => (_isRef(v) ? v.value -= 1 : v -= 1))
|
||||||
|
}),
|
||||||
|
_createElementVNode(\\"div\\", {
|
||||||
|
onClick: _cache[5] || (_cache[5] = () => {
|
||||||
|
let a = '' + _unref(lett)
|
||||||
|
_isRef(v) ? v.value = a : v = a
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
_createElementVNode(\\"div\\", {
|
||||||
|
onClick: _cache[6] || (_cache[6] = () => {
|
||||||
|
// nested scopes
|
||||||
|
(()=>{
|
||||||
|
let x = _ctx.a
|
||||||
|
(()=>{
|
||||||
|
let z = x
|
||||||
|
let z2 = z
|
||||||
|
})
|
||||||
|
let lz = _ctx.z
|
||||||
|
})
|
||||||
|
_isRef(v) ? v.value = _ctx.a : v = _ctx.a
|
||||||
|
})
|
||||||
})
|
})
|
||||||
], 64 /* STABLE_FRAGMENT */))
|
], 64 /* STABLE_FRAGMENT */))
|
||||||
}
|
}
|
||||||
|
@ -98,7 +98,7 @@ const myEmit = defineEmits(['foo', 'bar'])
|
|||||||
emits: ['foo', 'bar'],`)
|
emits: ['foo', 'bar'],`)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('defineProps/defineEmits in multi-variable decalration', () => {
|
test('defineProps/defineEmits in multi-variable declaration', () => {
|
||||||
const { content } = compile(`
|
const { content } = compile(`
|
||||||
<script setup>
|
<script setup>
|
||||||
const props = defineProps(['item']),
|
const props = defineProps(['item']),
|
||||||
@ -112,7 +112,7 @@ const myEmit = defineEmits(['foo', 'bar'])
|
|||||||
expect(content).toMatch(`emits: ['a'],`)
|
expect(content).toMatch(`emits: ['a'],`)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('defineProps/defineEmits in multi-variable decalration (full removal)', () => {
|
test('defineProps/defineEmits in multi-variable declaration (full removal)', () => {
|
||||||
const { content } = compile(`
|
const { content } = compile(`
|
||||||
<script setup>
|
<script setup>
|
||||||
const props = defineProps(['item']),
|
const props = defineProps(['item']),
|
||||||
@ -517,6 +517,22 @@ defineExpose({ foo: 123 })
|
|||||||
<div @click="lett = count"/>
|
<div @click="lett = count"/>
|
||||||
<div @click="v += 1"/>
|
<div @click="v += 1"/>
|
||||||
<div @click="v -= 1"/>
|
<div @click="v -= 1"/>
|
||||||
|
<div @click="() => {
|
||||||
|
let a = '' + lett
|
||||||
|
v = a
|
||||||
|
}"/>
|
||||||
|
<div @click="() => {
|
||||||
|
// nested scopes
|
||||||
|
(()=>{
|
||||||
|
let x = a
|
||||||
|
(()=>{
|
||||||
|
let z = x
|
||||||
|
let z2 = z
|
||||||
|
})
|
||||||
|
let lz = z
|
||||||
|
})
|
||||||
|
v = a
|
||||||
|
}"/>
|
||||||
</template>
|
</template>
|
||||||
`,
|
`,
|
||||||
{ inlineTemplate: true }
|
{ inlineTemplate: true }
|
||||||
@ -531,6 +547,8 @@ defineExpose({ foo: 123 })
|
|||||||
)
|
)
|
||||||
expect(content).toMatch(`_isRef(v) ? v.value += 1 : v += 1`)
|
expect(content).toMatch(`_isRef(v) ? v.value += 1 : v += 1`)
|
||||||
expect(content).toMatch(`_isRef(v) ? v.value -= 1 : v -= 1`)
|
expect(content).toMatch(`_isRef(v) ? v.value -= 1 : v -= 1`)
|
||||||
|
expect(content).toMatch(`_isRef(v) ? v.value = a : v = a`)
|
||||||
|
expect(content).toMatch(`_isRef(v) ? v.value = _ctx.a : v = _ctx.a`)
|
||||||
assertCode(content)
|
assertCode(content)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -526,7 +526,7 @@ export function compileScript(
|
|||||||
/**
|
/**
|
||||||
* check defaults. If the default object is an object literal with only
|
* check defaults. If the default object is an object literal with only
|
||||||
* static properties, we can directly generate more optimzied default
|
* static properties, we can directly generate more optimzied default
|
||||||
* decalrations. Otherwise we will have to fallback to runtime merging.
|
* declarations. Otherwise we will have to fallback to runtime merging.
|
||||||
*/
|
*/
|
||||||
function checkStaticDefaults() {
|
function checkStaticDefaults() {
|
||||||
return (
|
return (
|
||||||
@ -895,7 +895,7 @@ export function compileScript(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// walk decalrations to record declared bindings
|
// walk declarations to record declared bindings
|
||||||
if (
|
if (
|
||||||
(node.type === 'VariableDeclaration' ||
|
(node.type === 'VariableDeclaration' ||
|
||||||
node.type === 'FunctionDeclaration' ||
|
node.type === 'FunctionDeclaration' ||
|
||||||
|
@ -40,7 +40,7 @@ const warnRuntimeUsage = (method: string) =>
|
|||||||
* })
|
* })
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
* Equivalent type-based decalration:
|
* Equivalent type-based declaration:
|
||||||
* ```ts
|
* ```ts
|
||||||
* // will be compiled into equivalent runtime declarations
|
* // will be compiled into equivalent runtime declarations
|
||||||
* const props = defineProps<{
|
* const props = defineProps<{
|
||||||
@ -79,7 +79,7 @@ export function defineProps() {
|
|||||||
* const emit = defineEmits(['change', 'update'])
|
* const emit = defineEmits(['change', 'update'])
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
* Example type-based decalration:
|
* Example type-based declaration:
|
||||||
* ```ts
|
* ```ts
|
||||||
* const emit = defineEmits<{
|
* const emit = defineEmits<{
|
||||||
* (event: 'change'): void
|
* (event: 'change'): void
|
||||||
@ -147,7 +147,7 @@ type PropsWithDefaults<Base, Defaults> = Base &
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Vue `<script setup>` compiler macro for providing props default values when
|
* Vue `<script setup>` compiler macro for providing props default values when
|
||||||
* using type-based `defineProps` decalration.
|
* using type-based `defineProps` declaration.
|
||||||
*
|
*
|
||||||
* Example usage:
|
* Example usage:
|
||||||
* ```ts
|
* ```ts
|
||||||
|
Loading…
Reference in New Issue
Block a user