Skip to content

Commit 801b8de

Browse files
committed
chore: Merge branch 'main' into minor
2 parents 5590ca3 + f750c41 commit 801b8de

File tree

22 files changed

+675
-318
lines changed

22 files changed

+675
-318
lines changed

.github/workflows/release-tag.yml

+2-1
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,5 @@ jobs:
2424
with:
2525
tag_name: ${{ github.ref }}
2626
body: |
27-
Please refer to [CHANGELOG.md](https://github.com/vuejs/core/blob/main/CHANGELOG.md) for details.
27+
For stable releases, please refer to [CHANGELOG.md](https://github.com/vuejs/core/blob/main/CHANGELOG.md) for details.
28+
For pre-releases, please refer to [CHANGELOG.md](https://github.com/vuejs/core/blob/minor/CHANGELOG.md) of the `minor` branch.

CHANGELOG.md

+14
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
## [3.4.26](https://github.com/vuejs/core/compare/v3.4.25...v3.4.26) (2024-04-29)
2+
3+
4+
### Bug Fixes
5+
6+
* **compiler-core:** fix bail constant for globals ([fefce06](https://github.com/vuejs/core/commit/fefce06b41e3b75de3d748dc6399628ec5056e78))
7+
* **compiler-core:** remove unnecessary constant bail check ([09b4df8](https://github.com/vuejs/core/commit/09b4df809e59ef5f4bc91acfc56dc8f82a8e243a)), closes [#10807](https://github.com/vuejs/core/issues/10807)
8+
* **runtime-core:** attrs should be readonly in functional components ([#10767](https://github.com/vuejs/core/issues/10767)) ([e8fd644](https://github.com/vuejs/core/commit/e8fd6446d14a6899e5e8ab1ee394d90088e01844))
9+
* **runtime-core:** ensure slot compiler marker writable ([#10825](https://github.com/vuejs/core/issues/10825)) ([9c2de62](https://github.com/vuejs/core/commit/9c2de6244cd44bc5fbfd82b5850c710ce725044f)), closes [#10818](https://github.com/vuejs/core/issues/10818)
10+
* **runtime-core:** properly handle inherit transition during clone VNode ([#10809](https://github.com/vuejs/core/issues/10809)) ([638a79f](https://github.com/vuejs/core/commit/638a79f64a7e184f2a2c65e21d764703f4bda561)), closes [#3716](https://github.com/vuejs/core/issues/3716) [#10497](https://github.com/vuejs/core/issues/10497) [#4091](https://github.com/vuejs/core/issues/4091)
11+
* **Transition:** re-fix [#10620](https://github.com/vuejs/core/issues/10620) ([#10832](https://github.com/vuejs/core/issues/10832)) ([accf839](https://github.com/vuejs/core/commit/accf8396ae1c9dd49759ba0546483f1d2c70c9bc)), closes [#10632](https://github.com/vuejs/core/issues/10632) [#10827](https://github.com/vuejs/core/issues/10827)
12+
13+
14+
115
# [3.5.0-alpha.1](https://github.com/vuejs/core/compare/v3.4.25...v3.5.0-alpha.1) (2024-04-29)
216

317

package.json

+11-11
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"private": true,
33
"version": "3.5.0-alpha.1",
4-
"packageManager": "[email protected].5",
4+
"packageManager": "[email protected].6",
55
"type": "module",
66
"scripts": {
77
"dev": "node scripts/dev.js",
@@ -72,15 +72,15 @@
7272
"@types/minimist": "^1.2.5",
7373
"@types/node": "^20.12.7",
7474
"@types/semver": "^7.5.8",
75-
"@vitest/coverage-istanbul": "^1.5.0",
75+
"@vitest/coverage-istanbul": "^1.5.2",
7676
"@vue/consolidate": "1.0.0",
7777
"conventional-changelog-cli": "^4.1.0",
7878
"enquirer": "^2.4.1",
7979
"esbuild": "^0.20.2",
8080
"esbuild-plugin-polyfill-node": "^0.3.0",
81-
"eslint": "^9.0.0",
81+
"eslint": "^9.1.1",
8282
"eslint-plugin-import-x": "^0.5.0",
83-
"eslint-plugin-vitest": "^0.5.3",
83+
"eslint-plugin-vitest": "^0.5.4",
8484
"estree-walker": "^2.0.2",
8585
"execa": "^8.0.1",
8686
"jsdom": "^24.0.0",
@@ -95,23 +95,23 @@
9595
"prettier": "^3.2.5",
9696
"pretty-bytes": "^6.1.1",
9797
"pug": "^3.0.2",
98-
"puppeteer": "~22.6.5",
98+
"puppeteer": "~22.7.1",
9999
"rimraf": "^5.0.5",
100-
"rollup": "^4.16.1",
100+
"rollup": "^4.17.1",
101101
"rollup-plugin-dts": "^6.1.0",
102102
"rollup-plugin-esbuild": "^6.1.1",
103103
"rollup-plugin-polyfill-node": "^0.13.0",
104104
"semver": "^7.6.0",
105-
"serve": "^14.2.1",
105+
"serve": "^14.2.3",
106106
"simple-git-hooks": "^2.11.1",
107-
"terser": "^5.30.3",
107+
"terser": "^5.30.4",
108108
"todomvc-app-css": "^2.4.3",
109109
"tslib": "^2.6.2",
110-
"tsx": "^4.7.2",
110+
"tsx": "^4.7.3",
111111
"typescript": "~5.4.5",
112-
"typescript-eslint": "^7.6.0",
112+
"typescript-eslint": "^7.7.1",
113113
"vite": "^5.2.10",
114-
"vitest": "^1.5.0"
114+
"vitest": "^1.5.2"
115115
},
116116
"pnpm": {
117117
"peerDependencyRules": {

packages/compiler-core/__tests__/transforms/transformExpressions.spec.ts

+25
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,31 @@ describe('compiler: expression transform', () => {
421421
})
422422
})
423423

424+
// #10807
425+
test('should not bail constant on strings w/ ()', () => {
426+
const node = parseWithExpressionTransform(
427+
`{{ { foo: 'ok()' } }}`,
428+
) as InterpolationNode
429+
expect(node.content).toMatchObject({
430+
constType: ConstantTypes.CAN_STRINGIFY,
431+
})
432+
})
433+
434+
test('should bail constant for global identifiers w/ new or call expressions', () => {
435+
const node = parseWithExpressionTransform(
436+
`{{ new Date().getFullYear() }}`,
437+
) as InterpolationNode
438+
expect(node.content).toMatchObject({
439+
children: [
440+
'new ',
441+
{ constType: ConstantTypes.NOT_CONSTANT },
442+
'().',
443+
{ constType: ConstantTypes.NOT_CONSTANT },
444+
'()',
445+
],
446+
})
447+
})
448+
424449
describe('ES Proposals support', () => {
425450
test('bigInt', () => {
426451
const node = parseWithExpressionTransform(

packages/compiler-core/src/babelUtils.ts

+3
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ import type {
1010
} from '@babel/types'
1111
import { walk } from 'estree-walker'
1212

13+
/**
14+
* Return value indicates whether the AST walked can be a constant
15+
*/
1316
export function walkIdentifiers(
1417
root: Node,
1518
onIdentifier: (

packages/compiler-core/src/parser.ts

+8-7
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ const tokenizer = new Tokenizer(stack, {
179179
const name = currentOpenTag!.tag
180180
currentOpenTag!.isSelfClosing = true
181181
endOpenTag(end)
182-
if (stack[0]?.tag === name) {
182+
if (stack[0] && stack[0].tag === name) {
183183
onCloseTag(stack.shift()!, end)
184184
}
185185
},
@@ -587,14 +587,14 @@ function endOpenTag(end: number) {
587587

588588
function onText(content: string, start: number, end: number) {
589589
if (__BROWSER__) {
590-
const tag = stack[0]?.tag
590+
const tag = stack[0] && stack[0].tag
591591
if (tag !== 'script' && tag !== 'style' && content.includes('&')) {
592592
content = currentOptions.decodeEntities!(content, false)
593593
}
594594
}
595595
const parent = stack[0] || currentRoot
596596
const lastNode = parent.children[parent.children.length - 1]
597-
if (lastNode?.type === NodeTypes.TEXT) {
597+
if (lastNode && lastNode.type === NodeTypes.TEXT) {
598598
// merge
599599
lastNode.content += content
600600
setLocEnd(lastNode.loc, end)
@@ -771,7 +771,8 @@ function isComponent({ tag, props }: ElementNode): boolean {
771771
tag === 'component' ||
772772
isUpperCase(tag.charCodeAt(0)) ||
773773
isCoreComponent(tag) ||
774-
currentOptions.isBuiltInComponent?.(tag) ||
774+
(currentOptions.isBuiltInComponent &&
775+
currentOptions.isBuiltInComponent(tag)) ||
775776
(currentOptions.isNativeTag && !currentOptions.isNativeTag(tag))
776777
) {
777778
return true
@@ -828,8 +829,8 @@ function condenseWhitespace(
828829
if (node.type === NodeTypes.TEXT) {
829830
if (!inPre) {
830831
if (isAllWhitespace(node.content)) {
831-
const prev = nodes[i - 1]?.type
832-
const next = nodes[i + 1]?.type
832+
const prev = nodes[i - 1] && nodes[i - 1].type
833+
const next = nodes[i + 1] && nodes[i + 1].type
833834
// Remove if:
834835
// - the whitespace is the first or last node, or:
835836
// - (condense mode) the whitespace is between two comments, or:
@@ -1063,7 +1064,7 @@ export function baseParse(input: string, options?: ParserOptions): RootNode {
10631064
currentOptions.ns === Namespaces.SVG ||
10641065
currentOptions.ns === Namespaces.MATH_ML
10651066

1066-
const delimiters = options?.delimiters
1067+
const delimiters = options && options.delimiters
10671068
if (delimiters) {
10681069
tokenizer.delimiterOpen = toCharCodes(delimiters[0])
10691070
tokenizer.delimiterClose = toCharCodes(delimiters[1])

packages/compiler-core/src/transforms/transformExpression.ts

+7-10
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,6 @@ import { BindingTypes } from '../options'
4646

4747
const isLiteralWhitelisted = /*#__PURE__*/ makeMap('true,false,null,this')
4848

49-
// a heuristic safeguard to bail constant expressions on presence of
50-
// likely function invocation and member access
51-
const constantBailRE = /\w\s*\(|\.[^\d]/
52-
5349
export const transformExpression: NodeTransform = (node, context) => {
5450
if (node.type === NodeTypes.INTERPOLATION) {
5551
node.content = processExpression(
@@ -226,8 +222,6 @@ export function processExpression(
226222

227223
// fast path if expression is a simple identifier.
228224
const rawExp = node.content
229-
// bail constant on parens (function invocation) and dot (member access)
230-
const bailConstant = constantBailRE.test(rawExp)
231225

232226
let ast = node.ast
233227

@@ -317,7 +311,12 @@ export function processExpression(
317311
} else {
318312
// The identifier is considered constant unless it's pointing to a
319313
// local scope variable (a v-for alias, or a v-slot prop)
320-
if (!(needPrefix && isLocal) && !bailConstant) {
314+
if (
315+
!(needPrefix && isLocal) &&
316+
parent.type !== 'CallExpression' &&
317+
parent.type !== 'NewExpression' &&
318+
parent.type !== 'MemberExpression'
319+
) {
321320
;(node as QualifiedId).isConstant = true
322321
}
323322
// also generate sub-expressions for other identifiers for better
@@ -371,9 +370,7 @@ export function processExpression(
371370
ret.ast = ast
372371
} else {
373372
ret = node
374-
ret.constType = bailConstant
375-
? ConstantTypes.NOT_CONSTANT
376-
: ConstantTypes.CAN_STRINGIFY
373+
ret.constType = ConstantTypes.CAN_STRINGIFY
377374
}
378375
ret.identifiers = Object.keys(knownIds)
379376
return ret

packages/runtime-core/__tests__/componentProps.spec.ts

+2-3
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import {
1717
ref,
1818
render,
1919
serializeInner,
20-
toRaw,
2120
toRefs,
2221
watch,
2322
} from '@vue/runtime-test'
@@ -129,12 +128,12 @@ describe('component props', () => {
129128
render(h(Comp, { foo: 1 }), root)
130129
expect(props).toEqual({ foo: 1 })
131130
expect(attrs).toEqual({ foo: 1 })
132-
expect(toRaw(props)).toBe(attrs)
131+
expect(props).toBe(attrs)
133132

134133
render(h(Comp, { bar: 2 }), root)
135134
expect(props).toEqual({ bar: 2 })
136135
expect(attrs).toEqual({ bar: 2 })
137-
expect(toRaw(props)).toBe(attrs)
136+
expect(props).toBe(attrs)
138137
})
139138

140139
test('boolean casting', () => {

packages/runtime-core/__tests__/components/BaseTransition.spec.ts

-37
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import {
77
h,
88
nextTick,
99
nodeOps,
10-
onUnmounted,
1110
ref,
1211
render,
1312
serialize,
@@ -769,42 +768,6 @@ describe('BaseTransition', () => {
769768
test('w/ KeepAlive', async () => {
770769
await runTestWithKeepAlive(testOutIn)
771770
})
772-
773-
test('w/ KeepAlive + unmount innerChild', async () => {
774-
const unmountSpy = vi.fn()
775-
const includeRef = ref(['TrueBranch'])
776-
const trueComp = {
777-
name: 'TrueBranch',
778-
setup() {
779-
onUnmounted(unmountSpy)
780-
const count = ref(0)
781-
return () => h('div', count.value)
782-
},
783-
}
784-
785-
const toggle = ref(true)
786-
const { props } = mockProps({ mode: 'out-in' }, true /*withKeepAlive*/)
787-
const root = nodeOps.createElement('div')
788-
const App = {
789-
render() {
790-
return h(BaseTransition, props, () => {
791-
return h(
792-
KeepAlive,
793-
{ include: includeRef.value },
794-
toggle.value ? h(trueComp) : h('div'),
795-
)
796-
})
797-
},
798-
}
799-
render(h(App), root)
800-
801-
// trigger toggle
802-
toggle.value = false
803-
includeRef.value = []
804-
805-
await nextTick()
806-
expect(unmountSpy).toHaveBeenCalledTimes(1)
807-
})
808771
})
809772

810773
// #6835

packages/runtime-core/__tests__/hmr.spec.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,7 @@ describe('hot module replacement', () => {
356356
triggerEvent(root.children[1] as TestElement, 'click')
357357
await nextTick()
358358
await new Promise(r => setTimeout(r, 0))
359-
expect(serializeInner(root)).toBe(`<button></button><!---->`)
359+
expect(serializeInner(root)).toBe(`<button></button><!--v-if-->`)
360360
expect(unmountSpy).toHaveBeenCalledTimes(1)
361361
expect(mountSpy).toHaveBeenCalledTimes(1)
362362
expect(activeSpy).toHaveBeenCalledTimes(1)

packages/runtime-core/src/apiWatch.ts

+7-14
Original file line numberDiff line numberDiff line change
@@ -472,39 +472,32 @@ export function createPathGetter(ctx: any, path: string) {
472472

473473
export function traverse(
474474
value: unknown,
475-
depth?: number,
476-
currentDepth = 0,
475+
depth = Infinity,
477476
seen?: Set<unknown>,
478477
) {
479-
if (!isObject(value) || (value as any)[ReactiveFlags.SKIP]) {
478+
if (depth <= 0 || !isObject(value) || (value as any)[ReactiveFlags.SKIP]) {
480479
return value
481480
}
482481

483-
if (depth && depth > 0) {
484-
if (currentDepth >= depth) {
485-
return value
486-
}
487-
currentDepth++
488-
}
489-
490482
seen = seen || new Set()
491483
if (seen.has(value)) {
492484
return value
493485
}
494486
seen.add(value)
487+
depth--
495488
if (isRef(value)) {
496-
traverse(value.value, depth, currentDepth, seen)
489+
traverse(value.value, depth, seen)
497490
} else if (isArray(value)) {
498491
for (let i = 0; i < value.length; i++) {
499-
traverse(value[i], depth, currentDepth, seen)
492+
traverse(value[i], depth, seen)
500493
}
501494
} else if (isSet(value) || isMap(value)) {
502495
value.forEach((v: any) => {
503-
traverse(v, depth, currentDepth, seen)
496+
traverse(v, depth, seen)
504497
})
505498
} else if (isPlainObject(value)) {
506499
for (const key in value) {
507-
traverse(value[key], depth, currentDepth, seen)
500+
traverse(value[key], depth, seen)
508501
}
509502
}
510503
return value

packages/runtime-core/src/compat/global.ts

+11-6
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,12 @@ export type CompatVue = Pick<App, 'version' | 'component' | 'directive'> & {
7777

7878
nextTick: typeof nextTick
7979

80-
use(plugin: Plugin, ...options: any[]): CompatVue
80+
use<Options extends unknown[]>(
81+
plugin: Plugin<Options>,
82+
...options: Options
83+
): CompatVue
84+
use<Options>(plugin: Plugin<Options>, options: Options): CompatVue
85+
8186
mixin(mixin: ComponentOptions): CompatVue
8287

8388
component(name: string): Component | undefined
@@ -176,11 +181,11 @@ export function createCompatVue(
176181
Vue.version = `2.6.14-compat:${__VERSION__}`
177182
Vue.config = singletonApp.config
178183

179-
Vue.use = (p, ...options) => {
180-
if (p && isFunction(p.install)) {
181-
p.install(Vue as any, ...options)
182-
} else if (isFunction(p)) {
183-
p(Vue as any, ...options)
184+
Vue.use = (plugin: Plugin, ...options: any[]) => {
185+
if (plugin && isFunction(plugin.install)) {
186+
plugin.install(Vue as any, ...options)
187+
} else if (isFunction(plugin)) {
188+
plugin(Vue as any, ...options)
184189
}
185190
return Vue
186191
}

0 commit comments

Comments
 (0)