Skip to content

Commit c9fe3f1

Browse files
committed
Merge tag 'v3.4.5'
2 parents 243af64 + 0275dd3 commit c9fe3f1

File tree

15 files changed

+157
-74
lines changed

15 files changed

+157
-74
lines changed

CHANGELOG.md

+12
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,15 @@
1+
## [3.4.5](https://github.com/vuejs/core/compare/v3.4.4...v3.4.5) (2024-01-04)
2+
3+
4+
### Bug Fixes
5+
6+
* **compiler-sfc:** fix co-usage of defineModel transform options and props destructure ([b20350d](https://github.com/vuejs/core/commit/b20350ded562d27e5901f308d0bc13344f840c4a)), closes [#9972](https://github.com/vuejs/core/issues/9972)
7+
* **compiler-sfc:** fix sfc template unref rewrite for class instantiation ([ae60a91](https://github.com/vuejs/core/commit/ae60a91cc23424493071ad9088782763eb1e8ff7)), closes [#6483](https://github.com/vuejs/core/issues/6483) [#6491](https://github.com/vuejs/core/issues/6491)
8+
* **compiler-ssr:** fix node clone edge case caused by AST reuse ([#9983](https://github.com/vuejs/core/issues/9983)) ([7dbdb3e](https://github.com/vuejs/core/commit/7dbdb3edf0ab648965331ca42f069387c97a1c8a)), closes [#9981](https://github.com/vuejs/core/issues/9981)
9+
* **watch:** cleanup watcher effect from scope when manually stopped ([#9978](https://github.com/vuejs/core/issues/9978)) ([d2d8955](https://github.com/vuejs/core/commit/d2d89551bb06dc05cb7ae0496b8f345ae0de78ed))
10+
11+
12+
113
## [3.4.4](https://github.com/vuejs/core/compare/v3.4.3...v3.4.4) (2024-01-03)
214

315

packages/compiler-core/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@vue/compiler-core",
3-
"version": "3.4.4",
3+
"version": "3.4.5",
44
"description": "@vue/compiler-core",
55
"main": "index.js",
66
"module": "dist/compiler-core.esm-bundler.js",

packages/compiler-dom/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@vue/compiler-dom",
3-
"version": "3.4.4",
3+
"version": "3.4.5",
44
"description": "@vue/compiler-dom",
55
"main": "index.js",
66
"module": "dist/compiler-dom.esm-bundler.js",

packages/compiler-sfc/__tests__/compileScript/__snapshots__/defineModel.spec.ts.snap

+46-14
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ export default {
1717
__expose();
1818
1919
const modelValue = _useModel(__props, "modelValue")
20-
const c = _useModel(__props, "count")
21-
const toString = _useModel(__props, "toString")
20+
const c = _useModel(__props, 'count')
21+
const toString = _useModel(__props, 'toString')
2222
2323
return { modelValue, c, toString }
2424
}
@@ -40,7 +40,10 @@ export default /*#__PURE__*/_defineComponent({
4040
setup(__props, { expose: __expose }) {
4141
__expose();
4242
43-
const modelValue = _useModel(__props, "modelValue", { get(v) { return v - 1 }, set: (v) => { return v + 1 }, })
43+
const modelValue = _useModel(__props, "modelValue", {
44+
get(v) { return v - 1 },
45+
set: (v) => { return v + 1 },
46+
})
4447
4548
return { modelValue }
4649
}
@@ -63,7 +66,36 @@ export default /*#__PURE__*/_defineComponent({
6366
setup(__props, { expose: __expose }) {
6467
__expose();
6568
66-
const modelValue = _useModel(__props, "modelValue", { get(v) { return v - 1 }, set: (v) => { return v + 1 }, })
69+
const modelValue = _useModel(__props, "modelValue", {
70+
get(v) { return v - 1 },
71+
set: (v) => { return v + 1 },
72+
})
73+
74+
return { modelValue }
75+
}
76+
77+
})"
78+
`;
79+
80+
exports[`defineModel() > usage w/ props destructure 1`] = `
81+
"import { useModel as _useModel, mergeModels as _mergeModels, defineComponent as _defineComponent } from 'vue'
82+
83+
export default /*#__PURE__*/_defineComponent({
84+
props: /*#__PURE__*/_mergeModels({
85+
x: { type: Number, required: true }
86+
}, {
87+
"modelValue": {
88+
},
89+
"modelModifiers": {},
90+
}),
91+
emits: ["update:modelValue"],
92+
setup(__props: any, { expose: __expose }) {
93+
__expose();
94+
95+
96+
const modelValue = _useModel(__props, "modelValue", {
97+
set: (v) => { return v + __props.x }
98+
})
6799
68100
return { modelValue }
69101
}
@@ -84,7 +116,7 @@ export default {
84116
__expose();
85117
86118
87-
const count = _useModel(__props, "count")
119+
const count = _useModel(__props, 'count')
88120
89121
return { count }
90122
}
@@ -132,10 +164,10 @@ export default /*#__PURE__*/_defineComponent({
132164
setup(__props, { expose: __expose }) {
133165
__expose();
134166
135-
const modelValue = _useModel(__props, "modelValue")
136-
const count = _useModel(__props, "count")
137-
const disabled = _useModel(__props, "disabled")
138-
const any = _useModel(__props, "any")
167+
const modelValue = _useModel<boolean | string>(__props, "modelValue")
168+
const count = _useModel<number>(__props, 'count')
169+
const disabled = _useModel<number>(__props, 'disabled')
170+
const any = _useModel<any | boolean>(__props, 'any')
139171
140172
return { modelValue, count, disabled, any }
141173
}
@@ -163,11 +195,11 @@ export default /*#__PURE__*/_defineComponent({
163195
setup(__props, { expose: __expose }) {
164196
__expose();
165197
166-
const modelValue = _useModel(__props, "modelValue")
167-
const fn = _useModel(__props, "fn")
168-
const fnWithDefault = _useModel(__props, "fnWithDefault")
169-
const str = _useModel(__props, "str")
170-
const optional = _useModel(__props, "optional")
198+
const modelValue = _useModel<boolean>(__props, "modelValue")
199+
const fn = _useModel<() => void>(__props, 'fn')
200+
const fnWithDefault = _useModel<() => void>(__props, 'fnWithDefault')
201+
const str = _useModel<string>(__props, 'str')
202+
const optional = _useModel<string>(__props, 'optional')
171203
172204
return { modelValue, fn, fnWithDefault, str, optional }
173205
}

packages/compiler-sfc/__tests__/compileScript/defineModel.spec.ts

+38-11
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ describe('defineModel()', () => {
2323
expect(content).toMatch(
2424
`const modelValue = _useModel(__props, "modelValue")`,
2525
)
26-
expect(content).toMatch(`const c = _useModel(__props, "count")`)
26+
expect(content).toMatch(`const c = _useModel(__props, 'count')`)
27+
expect(content).toMatch(`const toString = _useModel(__props, 'toString')`)
2728
expect(content).toMatch(`return { modelValue, c, toString }`)
2829
expect(content).not.toMatch('defineModel')
2930

@@ -71,7 +72,7 @@ describe('defineModel()', () => {
7172
"count": {},
7273
"countModifiers": {},
7374
})`)
74-
expect(content).toMatch(`const count = _useModel(__props, "count")`)
75+
expect(content).toMatch(`const count = _useModel(__props, 'count')`)
7576
expect(content).not.toMatch('defineModel')
7677
expect(bindings).toStrictEqual({
7778
foo: BindingTypes.PROPS,
@@ -104,11 +105,15 @@ describe('defineModel()', () => {
104105
)
105106

106107
expect(content).toMatch(
107-
`const modelValue = _useModel(__props, "modelValue")`,
108+
`const modelValue = _useModel<boolean | string>(__props, "modelValue")`,
109+
)
110+
expect(content).toMatch(`const count = _useModel<number>(__props, 'count')`)
111+
expect(content).toMatch(
112+
`const disabled = _useModel<number>(__props, 'disabled')`,
113+
)
114+
expect(content).toMatch(
115+
`const any = _useModel<any | boolean>(__props, 'any')`,
108116
)
109-
expect(content).toMatch(`const count = _useModel(__props, "count")`)
110-
expect(content).toMatch(`const disabled = _useModel(__props, "disabled")`)
111-
expect(content).toMatch(`const any = _useModel(__props, "any")`)
112117

113118
expect(bindings).toStrictEqual({
114119
modelValue: BindingTypes.SETUP_REF,
@@ -143,10 +148,10 @@ describe('defineModel()', () => {
143148
'emits: ["update:modelValue", "update:fn", "update:fnWithDefault", "update:str", "update:optional"]',
144149
)
145150
expect(content).toMatch(
146-
`const modelValue = _useModel(__props, "modelValue")`,
151+
`const modelValue = _useModel<boolean>(__props, "modelValue")`,
147152
)
148-
expect(content).toMatch(`const fn = _useModel(__props, "fn")`)
149-
expect(content).toMatch(`const str = _useModel(__props, "str")`)
153+
expect(content).toMatch(`const fn = _useModel<() => void>(__props, 'fn')`)
154+
expect(content).toMatch(`const str = _useModel<string>(__props, 'str')`)
150155
expect(bindings).toStrictEqual({
151156
modelValue: BindingTypes.SETUP_REF,
152157
fn: BindingTypes.SETUP_REF,
@@ -171,7 +176,10 @@ describe('defineModel()', () => {
171176
assertCode(content)
172177
expect(content).toMatch(/"modelValue": {\s+required: true,?\s+}/m)
173178
expect(content).toMatch(
174-
`_useModel(__props, "modelValue", { get(v) { return v - 1 }, set: (v) => { return v + 1 }, })`,
179+
`_useModel(__props, "modelValue", {
180+
get(v) { return v - 1 },
181+
set: (v) => { return v + 1 },
182+
})`,
175183
)
176184

177185
const { content: content2 } = compile(
@@ -191,7 +199,26 @@ describe('defineModel()', () => {
191199
/"modelValue": {\s+default: 0,\s+required: true,?\s+}/m,
192200
)
193201
expect(content2).toMatch(
194-
`_useModel(__props, "modelValue", { get(v) { return v - 1 }, set: (v) => { return v + 1 }, })`,
202+
`_useModel(__props, "modelValue", {
203+
get(v) { return v - 1 },
204+
set: (v) => { return v + 1 },
205+
})`,
195206
)
196207
})
208+
209+
test('usage w/ props destructure', () => {
210+
const { content } = compile(
211+
`
212+
<script setup lang="ts">
213+
const { x } = defineProps<{ x: number }>()
214+
const modelValue = defineModel({
215+
set: (v) => { return v + x }
216+
})
217+
</script>
218+
`,
219+
{ propsDestructure: true },
220+
)
221+
assertCode(content)
222+
expect(content).toMatch(`set: (v) => { return v + __props.x }`)
223+
})
197224
})

packages/compiler-sfc/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@vue/compiler-sfc",
3-
"version": "3.4.4",
3+
"version": "3.4.5",
44
"description": "@vue/compiler-sfc",
55
"main": "dist/compiler-sfc.cjs.js",
66
"module": "dist/compiler-sfc.esm-browser.js",

packages/compiler-sfc/src/script/defineModel.ts

+50-38
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ export function processDefineModel(
3333
let modelName: string
3434
let options: Node | undefined
3535
const arg0 = node.arguments[0] && unwrapTSNode(node.arguments[0])
36-
if (arg0 && arg0.type === 'StringLiteral') {
36+
const hasName = arg0 && arg0.type === 'StringLiteral'
37+
if (hasName) {
3738
modelName = arg0.value
3839
options = node.arguments[1]
3940
} else {
@@ -46,39 +47,42 @@ export function processDefineModel(
4647
}
4748

4849
let optionsString = options && ctx.getString(options)
49-
let runtimeOptions = ''
50-
let transformOptions = ''
51-
52-
if (options) {
53-
if (options.type === 'ObjectExpression') {
54-
for (let i = options.properties.length - 1; i >= 0; i--) {
55-
const p = options.properties[i]
56-
if (p.type === 'SpreadElement' || p.computed) {
57-
runtimeOptions = optionsString!
58-
break
59-
}
60-
if (
61-
(p.type === 'ObjectProperty' || p.type === 'ObjectMethod') &&
62-
((p.key.type === 'Identifier' &&
63-
(p.key.name === 'get' || p.key.name === 'set')) ||
64-
(p.key.type === 'StringLiteral' &&
65-
(p.key.value === 'get' || p.key.value === 'set')))
66-
) {
67-
transformOptions = ctx.getString(p) + ', ' + transformOptions
68-
69-
// remove transform option from prop options to avoid duplicates
70-
const offset = p.start! - options.start!
71-
const next = options.properties[i + 1]
72-
const end = (next ? next.start! : options.end! - 1) - options.start!
73-
optionsString =
74-
optionsString.slice(0, offset) + optionsString.slice(end)
75-
}
50+
let optionsRemoved = !options
51+
52+
if (
53+
options &&
54+
options.type === 'ObjectExpression' &&
55+
!options.properties.some(p => p.type === 'SpreadElement' || p.computed)
56+
) {
57+
let removed = 0
58+
for (let i = options.properties.length - 1; i >= 0; i--) {
59+
const p = options.properties[i]
60+
const next = options.properties[i + 1]
61+
const start = p.start!
62+
const end = next ? next.start! : options.end! - 1
63+
if (
64+
(p.type === 'ObjectProperty' || p.type === 'ObjectMethod') &&
65+
((p.key.type === 'Identifier' &&
66+
(p.key.name === 'get' || p.key.name === 'set')) ||
67+
(p.key.type === 'StringLiteral' &&
68+
(p.key.value === 'get' || p.key.value === 'set')))
69+
) {
70+
// remove runtime-only options from prop options to avoid duplicates
71+
optionsString =
72+
optionsString.slice(0, start - options.start!) +
73+
optionsString.slice(end - options.start!)
74+
} else {
75+
// remove prop options from runtime options
76+
removed++
77+
ctx.s.remove(ctx.startOffset! + start, ctx.startOffset! + end)
7678
}
77-
if (!runtimeOptions && transformOptions) {
78-
runtimeOptions = `{ ${transformOptions} }`
79-
}
80-
} else {
81-
runtimeOptions = optionsString!
79+
}
80+
if (removed === options.properties.length) {
81+
optionsRemoved = true
82+
ctx.s.remove(
83+
ctx.startOffset! + (hasName ? arg0.end! : options.start!),
84+
ctx.startOffset! + options.end!,
85+
)
8286
}
8387
}
8488

@@ -91,12 +95,20 @@ export function processDefineModel(
9195
// register binding type
9296
ctx.bindingMetadata[modelName] = BindingTypes.PROPS
9397

98+
// defineModel -> useModel
9499
ctx.s.overwrite(
95-
ctx.startOffset! + node.start!,
96-
ctx.startOffset! + node.end!,
97-
`${ctx.helper('useModel')}(__props, ${JSON.stringify(modelName)}${
98-
runtimeOptions ? `, ${runtimeOptions}` : ``
99-
})`,
100+
ctx.startOffset! + node.callee.start!,
101+
ctx.startOffset! + node.callee.end!,
102+
ctx.helper('useModel'),
103+
)
104+
// inject arguments
105+
ctx.s.appendLeft(
106+
ctx.startOffset! +
107+
(node.arguments.length ? node.arguments[0].start! : node.end! - 1),
108+
`__props, ` +
109+
(hasName
110+
? ``
111+
: `${JSON.stringify(modelName)}${optionsRemoved ? `` : `, `}`),
100112
)
101113

102114
return true

packages/compiler-ssr/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@vue/compiler-ssr",
3-
"version": "3.4.4",
3+
"version": "3.4.5",
44
"description": "@vue/compiler-ssr",
55
"main": "dist/compiler-ssr.cjs.js",
66
"types": "dist/compiler-ssr.d.ts",

packages/reactivity/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@vue/reactivity",
3-
"version": "3.4.4",
3+
"version": "3.4.5",
44
"description": "@vue/reactivity",
55
"main": "index.js",
66
"module": "dist/reactivity.esm-bundler.js",

packages/runtime-core/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@vue/runtime-core",
3-
"version": "3.4.4",
3+
"version": "3.4.5",
44
"description": "@vue/runtime-core",
55
"main": "index.js",
66
"module": "dist/runtime-core.esm-bundler.js",

packages/runtime-dom/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@vue/runtime-dom",
3-
"version": "3.4.4",
3+
"version": "3.4.5",
44
"description": "@vue/runtime-dom",
55
"main": "index.js",
66
"module": "dist/runtime-dom.esm-bundler.js",

packages/server-renderer/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@vue/server-renderer",
3-
"version": "3.4.4",
3+
"version": "3.4.5",
44
"description": "@vue/server-renderer",
55
"main": "index.js",
66
"module": "dist/server-renderer.esm-bundler.js",

packages/shared/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@vue/shared",
3-
"version": "3.4.4",
3+
"version": "3.4.5",
44
"description": "internal utils shared across @vue packages",
55
"main": "index.js",
66
"module": "dist/shared.esm-bundler.js",

0 commit comments

Comments
 (0)