Merge remote-tracking branch 'upstream/main'

This commit is contained in:
三咲智子 Kevin Deng 2024-09-22 02:42:52 +08:00
commit b8713589de
No known key found for this signature in database
33 changed files with 376 additions and 58 deletions

View File

@ -1,3 +1,27 @@
## [3.5.7](https://github.com/vuejs/core/compare/v3.5.6...v3.5.7) (2024-09-20)
### Bug Fixes
* **compile-core:** fix v-model with newlines edge case ([#11960](https://github.com/vuejs/core/issues/11960)) ([6224288](https://github.com/vuejs/core/commit/62242886d705ece88dbcad45bb78072ecccad0ca)), closes [#8306](https://github.com/vuejs/core/issues/8306)
* **compiler-sfc:** initialize scope with null prototype object ([#11963](https://github.com/vuejs/core/issues/11963)) ([215e154](https://github.com/vuejs/core/commit/215e15407294bf667261360218f975b88c99c2e5))
* **hydration:** avoid observing non-Element node ([#11954](https://github.com/vuejs/core/issues/11954)) ([7257e6a](https://github.com/vuejs/core/commit/7257e6a34200409b3fc347d3bb807e11e2785974)), closes [#11952](https://github.com/vuejs/core/issues/11952)
* **reactivity:** do not remove dep from depsMap when unsubbed by computed ([960706e](https://github.com/vuejs/core/commit/960706eebf73f08ebc9d5dd853a05def05e2c153))
* **reactivity:** fix dev-only memory leak by updating dep.subsHead on sub removal ([5c8b76e](https://github.com/vuejs/core/commit/5c8b76ed6cfbbcee4cbaac0b72beab7291044e4f)), closes [#11956](https://github.com/vuejs/core/issues/11956)
* **reactivity:** fix memory leak from dep instances of garbage collected objects ([235ea47](https://github.com/vuejs/core/commit/235ea4772ed2972914cf142da8b7ac1fb04f7585)), closes [#11979](https://github.com/vuejs/core/issues/11979) [#11971](https://github.com/vuejs/core/issues/11971)
* **reactivity:** fix triggerRef call on ObjectRefImpl returned by toRef ([#11986](https://github.com/vuejs/core/issues/11986)) ([b030c8b](https://github.com/vuejs/core/commit/b030c8bc7327877efb98aa3d9a58eb287a6ff07a)), closes [#11982](https://github.com/vuejs/core/issues/11982)
* **scheduler:** ensure recursive jobs can't be queued twice ([#11955](https://github.com/vuejs/core/issues/11955)) ([d18d6aa](https://github.com/vuejs/core/commit/d18d6aa1b20dc57a8103c51ec4d61e8e53ed936d))
* **ssr:** don't render comments in TransitionGroup ([#11961](https://github.com/vuejs/core/issues/11961)) ([a2f6ede](https://github.com/vuejs/core/commit/a2f6edeb02faedbb673c4bc5c6a59d9a79a37d07)), closes [#11958](https://github.com/vuejs/core/issues/11958)
* **transition:** respect `duration` setting even when it is `0` ([#11967](https://github.com/vuejs/core/issues/11967)) ([f927a4a](https://github.com/vuejs/core/commit/f927a4ae6f7c453f70ba89498ee0c737dc9866fd))
* **types:** correct type inference of all-optional props ([#11644](https://github.com/vuejs/core/issues/11644)) ([9eca65e](https://github.com/vuejs/core/commit/9eca65ee9871d1ac878755afa9a3eb1b02030350)), closes [#11733](https://github.com/vuejs/core/issues/11733) [vuejs/language-tools#4704](https://github.com/vuejs/language-tools/issues/4704)
### Performance Improvements
* **hydration:** avoid observer if element is in viewport ([#11639](https://github.com/vuejs/core/issues/11639)) ([e075dfa](https://github.com/vuejs/core/commit/e075dfad5c7649c6045e3711687ec888e7aa1a39))
## [3.5.6](https://github.com/vuejs/core/compare/v3.5.5...v3.5.6) (2024-09-16)

View File

@ -1,6 +1,6 @@
{
"private": true,
"version": "3.5.6",
"version": "3.5.7",
"packageManager": "pnpm@9.10.0",
"type": "module",
"scripts": {

View File

@ -212,7 +212,8 @@ onMounted(() => {
@keydown.ctrl.s.prevent
@keydown.meta.s.prevent
:ssr="useSSRMode"
:autoSave="autoSave"
:model-value="autoSave"
:editorOptions="{ autoSaveText: false }"
:store="store"
:showCompileOutput="true"
:autoResize="true"

View File

@ -1,6 +1,6 @@
{
"name": "@vue/compiler-core",
"version": "3.5.6",
"version": "3.5.7",
"description": "@vue/compiler-core",
"main": "index.js",
"module": "dist/compiler-core.esm-bundler.js",

View File

@ -31,7 +31,7 @@ export const transformModel: DirectiveTransform = (dir, node, context) => {
// we assume v-model directives are always parsed
// (not artificially created by a transform)
const rawExp = exp.loc.source
const rawExp = exp.loc.source.trim()
const expString =
exp.type === NodeTypes.SIMPLE_EXPRESSION ? exp.content : rawExp

View File

@ -1,6 +1,6 @@
{
"name": "@vue/compiler-dom",
"version": "3.5.6",
"version": "3.5.7",
"description": "@vue/compiler-dom",
"main": "index.js",
"module": "dist/compiler-dom.esm-bundler.js",

View File

@ -1084,6 +1084,29 @@ return (_ctx, _cache) => {
}"
`;
exports[`SFC compile <script setup> > inlineTemplate mode > v-model w/ newlines codegen 1`] = `
"import { unref as _unref, isRef as _isRef, vModelText as _vModelText, withDirectives as _withDirectives, openBlock as _openBlock, createElementBlock as _createElementBlock } from "vue"
export default {
setup(__props) {
const count = ref(0)
return (_ctx, _cache) => {
return _withDirectives((_openBlock(), _createElementBlock("input", {
"onUpdate:modelValue": _cache[0] || (_cache[0] = $event => (_isRef(count) ? (count).value = $event : null))
}, null, 512 /* NEED_PATCH */)), [
[_vModelText,
_unref(count)
]
])
}
}
}"
`;
exports[`SFC compile <script setup> > inlineTemplate mode > with defineExpose() 1`] = `
"
export default {

View File

@ -472,6 +472,23 @@ describe('SFC compile <script setup>', () => {
assertCode(content)
})
test('v-model w/ newlines codegen', () => {
const { content } = compile(
`<script setup>
const count = ref(0)
</script>
<template>
<input v-model="
count
">
</template>
`,
{ inlineTemplate: true },
)
expect(content).toMatch(`_isRef(count) ? (count).value = $event : null`)
assertCode(content)
})
test('v-model should not generate ref assignment code for non-setup bindings', () => {
const { content } = compile(
`<script setup>

View File

@ -1,6 +1,6 @@
{
"name": "@vue/compiler-sfc",
"version": "3.5.6",
"version": "3.5.7",
"description": "@vue/compiler-sfc",
"main": "dist/compiler-sfc.cjs.js",
"module": "dist/compiler-sfc.esm-browser.js",

View File

@ -102,7 +102,7 @@ export function transformDestructuredProps(
return
}
const rootScope: Scope = {}
const rootScope: Scope = Object.create(null)
const scopeStack: Scope[] = [rootScope]
let currentScope: Scope = rootScope
const excludedIds = new WeakSet<Identifier>()

View File

@ -39,7 +39,7 @@ describe('transition-group', () => {
})
// #11514
test('with static tag + comment', () => {
test('with static tag + v-if comment', () => {
expect(
compile(
`<transition-group tag="ul"><div v-for="i in list"/><div v-if="false"></div></transition-group>`,
@ -60,6 +60,25 @@ describe('transition-group', () => {
`)
})
// #11958
test('with static tag + comment', () => {
expect(
compile(
`<transition-group tag="ul"><div v-for="i in list"/><!--test--></transition-group>`,
).code,
).toMatchInlineSnapshot(`
"const { ssrRenderAttrs: _ssrRenderAttrs, ssrRenderList: _ssrRenderList } = require("vue/server-renderer")
return function ssrRender(_ctx, _push, _parent, _attrs) {
_push(\`<ul\${_ssrRenderAttrs(_attrs)}>\`)
_ssrRenderList(_ctx.list, (i) => {
_push(\`<div></div>\`)
})
_push(\`</ul>\`)
}"
`)
})
test('with dynamic tag', () => {
expect(
compile(

View File

@ -1,6 +1,6 @@
{
"name": "@vue/compiler-ssr",
"version": "3.5.6",
"version": "3.5.7",
"description": "@vue/compiler-ssr",
"main": "dist/compiler-ssr.cjs.js",
"types": "dist/compiler-ssr.d.ts",

View File

@ -156,7 +156,7 @@ export function processChildren(
context: SSRTransformContext,
asFragment = false,
disableNestedFragments = false,
disableCommentAsIfAlternate = false,
disableComment = false,
): void {
if (asFragment) {
context.pushStringPart(`<!--[-->`)
@ -197,7 +197,9 @@ export function processChildren(
case NodeTypes.COMMENT:
// no need to escape comment here because the AST can only
// contain valid comments.
context.pushStringPart(`<!--${child.content}-->`)
if (!disableComment) {
context.pushStringPart(`<!--${child.content}-->`)
}
break
case NodeTypes.INTERPOLATION:
context.pushStringPart(
@ -207,12 +209,7 @@ export function processChildren(
)
break
case NodeTypes.IF:
ssrProcessIf(
child,
context,
disableNestedFragments,
disableCommentAsIfAlternate,
)
ssrProcessIf(child, context, disableNestedFragments, disableComment)
break
case NodeTypes.FOR:
ssrProcessFor(child, context, disableNestedFragments)

View File

@ -27,7 +27,7 @@ export function ssrProcessIf(
node: IfNode,
context: SSRTransformContext,
disableNestedFragments = false,
disableCommentAsIfAlternate = false,
disableComment = false,
): void {
const [rootBranch] = node.branches
const ifStatement = createIfStatement(
@ -56,7 +56,7 @@ export function ssrProcessIf(
}
}
if (!currentIf.alternate && !disableCommentAsIfAlternate) {
if (!currentIf.alternate && !disableComment) {
currentIf.alternate = createBlockStatement([
createCallExpression(`_push`, ['`<!---->`']),
])

View File

@ -1006,9 +1006,27 @@ describe('reactivity/computed', () => {
expect(serializeInner(root)).toBe(`<button>Step</button><p>Step 2</p>`)
})
it('manual trigger computed', () => {
test('manual trigger computed', () => {
const cValue = computed(() => 1)
triggerRef(cValue)
expect(cValue.value).toBe(1)
})
test('computed should remain live after losing all subscribers', () => {
const toggle = ref(true)
const state = reactive({
a: 1,
})
const p = computed(() => state.a + 1)
const pp = computed(() => {
return toggle.value ? p.value : 111
})
const { effect: e } = effect(() => pp.value)
e.stop()
expect(p.value).toBe(2)
state.a++
expect(p.value).toBe(3)
})
})

View File

@ -1,6 +1,6 @@
{
"name": "@vue/reactivity",
"version": "3.5.6",
"version": "3.5.7",
"description": "@vue/reactivity",
"main": "index.js",
"module": "dist/reactivity.esm-bundler.js",

View File

@ -82,6 +82,13 @@ export class Dep {
*/
subsHead?: Link
/**
* For object property deps cleanup
*/
target?: unknown = undefined
map?: KeyToDepMap = undefined
key?: unknown = undefined
constructor(public computed?: ComputedRefImpl | undefined) {
if (__DEV__) {
this.subsHead = undefined
@ -218,7 +225,8 @@ function addSub(link: Link) {
// which maintains a Set of subscribers, but we simply store them as
// raw Maps to reduce memory overhead.
type KeyToDepMap = Map<any, Dep>
const targetMap = new WeakMap<object, KeyToDepMap>()
export const targetMap: WeakMap<object, KeyToDepMap> = new WeakMap()
export const ITERATE_KEY: unique symbol = Symbol(
__DEV__ ? 'Object iterate' : '',
@ -249,6 +257,9 @@ export function track(target: object, type: TrackOpTypes, key: unknown): void {
let dep = depsMap.get(key)
if (!dep) {
depsMap.set(key, (dep = new Dep()))
dep.target = target
dep.map = depsMap
dep.key = key
}
if (__DEV__) {
dep.track({

View File

@ -1,7 +1,7 @@
import { extend, hasChanged } from '@vue/shared'
import type { ComputedRefImpl } from './computed'
import type { TrackOpTypes, TriggerOpTypes } from './constants'
import { type Link, globalVersion } from './dep'
import { type Link, globalVersion, targetMap } from './dep'
import { activeEffectScope } from './effectScope'
import { warn } from './warning'
@ -399,7 +399,7 @@ export function refreshComputed(computed: ComputedRefImpl): undefined {
}
}
function removeSub(link: Link) {
function removeSub(link: Link, fromComputed = false) {
const { dep, prevSub, nextSub } = link
if (prevSub) {
prevSub.nextSub = nextSub
@ -413,14 +413,24 @@ function removeSub(link: Link) {
// was previous tail, point new tail to prev
dep.subs = prevSub
}
if (__DEV__ && dep.subsHead === link) {
// was previous head, point new head to next
dep.subsHead = nextSub
}
if (!dep.subs && dep.computed) {
if (!dep.subs) {
// last subscriber removed
// if computed, unsubscribe it from all its deps so this computed and its
// value can be GCed
dep.computed.flags &= ~EffectFlags.TRACKING
for (let l = dep.computed.deps; l; l = l.nextDep) {
removeSub(l)
if (dep.computed) {
// if computed, unsubscribe it from all its deps so this computed and its
// value can be GCed
dep.computed.flags &= ~EffectFlags.TRACKING
for (let l = dep.computed.deps; l; l = l.nextDep) {
removeSub(l, true)
}
} else if (dep.map && !fromComputed) {
// property dep, remove it from the owner depsMap
dep.map.delete(dep.key)
if (!dep.map.size) targetMap.delete(dep.target!)
}
}
}

View File

@ -182,15 +182,18 @@ class RefImpl<T = any> {
* @see {@link https://vuejs.org/api/reactivity-advanced.html#triggerref}
*/
export function triggerRef(ref: Ref): void {
if (__DEV__) {
;(ref as unknown as RefImpl).dep.trigger({
target: ref,
type: TriggerOpTypes.SET,
key: 'value',
newValue: (ref as unknown as RefImpl)._value,
})
} else {
;(ref as unknown as RefImpl).dep.trigger()
// ref may be an instance of ObjectRefImpl
if ((ref as unknown as RefImpl).dep) {
if (__DEV__) {
;(ref as unknown as RefImpl).dep.trigger({
target: ref,
type: TriggerOpTypes.SET,
key: 'value',
newValue: (ref as unknown as RefImpl)._value,
})
} else {
;(ref as unknown as RefImpl).dep.trigger()
}
}
}

View File

@ -517,6 +517,45 @@ describe('scheduler', () => {
await nextTick()
})
test('jobs can be re-queued after an error', async () => {
const err = new Error('test')
let shouldThrow = true
const job1: SchedulerJob = vi.fn(() => {
if (shouldThrow) {
shouldThrow = false
throw err
}
})
job1.id = 1
const job2: SchedulerJob = vi.fn()
job2.id = 2
queueJob(job1)
queueJob(job2)
try {
await nextTick()
} catch (e: any) {
expect(e).toBe(err)
}
expect(
`Unhandled error during execution of scheduler flush`,
).toHaveBeenWarned()
expect(job1).toHaveBeenCalledTimes(1)
expect(job2).toHaveBeenCalledTimes(0)
queueJob(job1)
queueJob(job2)
await nextTick()
expect(job1).toHaveBeenCalledTimes(2)
expect(job2).toHaveBeenCalledTimes(1)
})
test('should prevent self-triggering jobs by default', async () => {
let count = 0
const job = () => {
@ -558,6 +597,113 @@ describe('scheduler', () => {
expect(count).toBe(5)
})
test('recursive jobs can only be queued once non-recursively', async () => {
const job: SchedulerJob = vi.fn()
job.id = 1
job.flags = SchedulerJobFlags.ALLOW_RECURSE
queueJob(job)
queueJob(job)
await nextTick()
expect(job).toHaveBeenCalledTimes(1)
})
test('recursive jobs can only be queued once recursively', async () => {
let recurse = true
const job: SchedulerJob = vi.fn(() => {
if (recurse) {
queueJob(job)
queueJob(job)
recurse = false
}
})
job.id = 1
job.flags = SchedulerJobFlags.ALLOW_RECURSE
queueJob(job)
await nextTick()
expect(job).toHaveBeenCalledTimes(2)
})
test(`recursive jobs can't be re-queued by other jobs`, async () => {
let recurse = true
const job1: SchedulerJob = () => {
if (recurse) {
// job2 is already queued, so this shouldn't do anything
queueJob(job2)
recurse = false
}
}
job1.id = 1
const job2: SchedulerJob = vi.fn(() => {
if (recurse) {
queueJob(job1)
queueJob(job2)
}
})
job2.id = 2
job2.flags = SchedulerJobFlags.ALLOW_RECURSE
queueJob(job2)
await nextTick()
expect(job2).toHaveBeenCalledTimes(2)
})
test('jobs are de-duplicated correctly when calling flushPreFlushCbs', async () => {
let recurse = true
const job1: SchedulerJob = vi.fn(() => {
queueJob(job3)
queueJob(job3)
flushPreFlushCbs()
})
job1.id = 1
job1.flags = SchedulerJobFlags.PRE
const job2: SchedulerJob = vi.fn(() => {
if (recurse) {
// job2 does not allow recurse, so this shouldn't do anything
queueJob(job2)
// job3 is already queued, so this shouldn't do anything
queueJob(job3)
recurse = false
}
})
job2.id = 2
job2.flags = SchedulerJobFlags.PRE
const job3: SchedulerJob = vi.fn(() => {
if (recurse) {
queueJob(job2)
queueJob(job3)
// The jobs are already queued, so these should have no effect
queueJob(job2)
queueJob(job3)
}
})
job3.id = 3
job3.flags = SchedulerJobFlags.ALLOW_RECURSE | SchedulerJobFlags.PRE
queueJob(job1)
await nextTick()
expect(job1).toHaveBeenCalledTimes(1)
expect(job2).toHaveBeenCalledTimes(1)
expect(job3).toHaveBeenCalledTimes(2)
})
// #1947 flushPostFlushCbs should handle nested calls
// e.g. app.mount inside app.mount
test('flushPostFlushCbs', async () => {

View File

@ -1,6 +1,6 @@
{
"name": "@vue/runtime-core",
"version": "3.5.6",
"version": "3.5.7",
"description": "@vue/runtime-core",
"main": "index.js",
"module": "dist/runtime-core.esm-bundler.js",

View File

@ -209,11 +209,13 @@ export function defineComponent<
? TypeEmitsToOptions<TypeEmits>
: RuntimeEmitsOptions,
InferredProps = unknown extends TypeProps
? string extends RuntimePropsKeys
? ComponentObjectPropsOptions extends RuntimePropsOptions
? {}
: ExtractPropTypes<RuntimePropsOptions>
: { [key in RuntimePropsKeys]?: any }
? keyof TypeProps extends never
? string extends RuntimePropsKeys
? ComponentObjectPropsOptions extends RuntimePropsOptions
? {}
: ExtractPropTypes<RuntimePropsOptions>
: { [key in RuntimePropsKeys]?: any }
: TypeProps
: TypeProps,
TypeRefs extends Record<string, unknown> = {},
TypeEl extends Element = any,

View File

@ -125,7 +125,9 @@ type InferPropType<T, NullAsAny = true> = [T] extends [null]
: InferPropType<U, false>
: [T] extends [Prop<infer V, infer D>]
? unknown extends V
? IfAny<V, V, D>
? keyof V extends never
? IfAny<V, V, D>
: V
: V
: T

View File

@ -26,6 +26,16 @@ export const hydrateOnIdle: HydrationStrategyFactory<number> =
return () => cancelIdleCallback(id)
}
function elementIsVisibleInViewport(el: Element) {
const { top, left, bottom, right } = el.getBoundingClientRect()
// eslint-disable-next-line no-restricted-globals
const { innerHeight, innerWidth } = window
return (
((top > 0 && top < innerHeight) || (bottom > 0 && bottom < innerHeight)) &&
((left > 0 && left < innerWidth) || (right > 0 && right < innerWidth))
)
}
export const hydrateOnVisible: HydrationStrategyFactory<
IntersectionObserverInit
> = opts => (hydrate, forEach) => {
@ -37,7 +47,15 @@ export const hydrateOnVisible: HydrationStrategyFactory<
break
}
}, opts)
forEach(el => ob.observe(el))
forEach(el => {
if (!(el instanceof Element)) return
if (elementIsVisibleInViewport(el)) {
hydrate()
ob.disconnect()
return false
}
ob.observe(el)
})
return () => ob.disconnect()
}
@ -85,14 +103,20 @@ export const hydrateOnInteraction: HydrationStrategyFactory<
return teardown
}
export function forEachElement(node: Node, cb: (el: Element) => void): void {
export function forEachElement(
node: Node,
cb: (el: Element) => void | false,
): void {
// fragment
if (isComment(node) && node.data === '[') {
let depth = 1
let next = node.nextSibling
while (next) {
if (next.nodeType === DOMNodeTypes.ELEMENT) {
cb(next as Element)
const result = cb(next as Element)
if (result === false) {
break
}
} else if (isComment(next)) {
if (next.data === ']') {
if (--depth === 0) break

View File

@ -162,7 +162,9 @@ export function flushPreFlushCbs(
cb.flags! &= ~SchedulerJobFlags.QUEUED
}
cb()
cb.flags! &= ~SchedulerJobFlags.QUEUED
if (!(cb.flags! & SchedulerJobFlags.ALLOW_RECURSE)) {
cb.flags! &= ~SchedulerJobFlags.QUEUED
}
}
}
}
@ -239,7 +241,9 @@ function flushJobs(seen?: CountMap) {
job.i,
job.i ? ErrorCodes.COMPONENT_UPDATE : ErrorCodes.SCHEDULER,
)
job.flags! &= ~SchedulerJobFlags.QUEUED
if (!(job.flags! & SchedulerJobFlags.ALLOW_RECURSE)) {
job.flags! &= ~SchedulerJobFlags.QUEUED
}
}
}
} finally {

View File

@ -1,6 +1,6 @@
{
"name": "@vue/runtime-dom",
"version": "3.5.6",
"version": "3.5.7",
"description": "@vue/runtime-dom",
"main": "index.js",
"module": "dist/runtime-dom.esm-bundler.js",

View File

@ -344,7 +344,7 @@ function whenTransitionEnds(
}
}
if (explicitTimeout) {
if (explicitTimeout != null) {
return setTimeout(resolveIfNotStale, explicitTimeout)
}

View File

@ -1,6 +1,6 @@
{
"name": "@vue/server-renderer",
"version": "3.5.6",
"version": "3.5.7",
"description": "@vue/server-renderer",
"main": "index.js",
"module": "dist/server-renderer.esm-bundler.js",

View File

@ -1,6 +1,6 @@
{
"name": "@vue/shared",
"version": "3.5.6",
"version": "3.5.7",
"description": "internal utils shared across @vue packages",
"main": "index.js",
"module": "dist/shared.esm-bundler.js",

View File

@ -1,6 +1,6 @@
{
"name": "@vue/compat",
"version": "3.5.6",
"version": "3.5.7",
"description": "Vue 3 compatibility build for Vue 2",
"main": "index.js",
"module": "dist/vue.runtime.esm-bundler.js",

View File

@ -11,9 +11,12 @@
<script>
const rootMargin = location.search.match(/rootMargin=(\d+)/)?.[1] ?? 0
const isFragment = location.search.includes('?fragment')
const isVIf = location.search.includes('?v-if')
if (isFragment) {
document.getElementById('app').innerHTML =
`<!--[--><!--[--><span>one</span><!--]--><button>0</button><span>two</span><!--]-->`
} else if (isVIf) {
document.getElementById('app').innerHTML = `<!---->`
}
window.isHydrated = false
@ -24,6 +27,7 @@
ref,
onMounted,
hydrateOnVisible,
createCommentVNode,
} = Vue
const Comp = {
@ -39,7 +43,9 @@
{ onClick: () => count.value++ },
count.value,
)
if (isFragment) {
if (isVIf) {
return createCommentVNode('v-if', true)
} else if (isFragment) {
return [[h('span', 'one')], button, h('span', 'two')]
} else {
return button

View File

@ -65,6 +65,17 @@ describe('async component hydration strategies', () => {
await assertHydrationSuccess()
})
test('visible (root v-if) should not throw error', async () => {
const spy = vi.fn()
const currentPage = page()
currentPage.on('pageerror', spy)
await goToCase('visible', '?v-if')
await page().waitForFunction(() => window.isRootMounted)
expect(await page().evaluate(() => window.isHydrated)).toBe(false)
expect(spy).toBeCalledTimes(0)
currentPage.off('pageerror', spy)
})
test('media query', async () => {
await goToCase('media')
await page().waitForFunction(() => window.isRootMounted)

View File

@ -1,6 +1,6 @@
{
"name": "vue",
"version": "3.5.6",
"version": "3.5.7",
"description": "The progressive JavaScript framework for building modern web UI.",
"main": "index.js",
"module": "dist/vue.runtime.esm-bundler.js",