]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
chore: Merge branch 'main' into minor
authorEvan You <evan@vuejs.org>
Wed, 17 Jul 2024 09:32:31 +0000 (17:32 +0800)
committerEvan You <evan@vuejs.org>
Wed, 17 Jul 2024 09:32:31 +0000 (17:32 +0800)
42 files changed:
1  2 
CHANGELOG.md
package.json
packages/compiler-core/__tests__/codegen.spec.ts
packages/compiler-core/__tests__/transforms/__snapshots__/cacheStatic.spec.ts.snap
packages/compiler-core/__tests__/transforms/cacheStatic.spec.ts
packages/compiler-core/package.json
packages/compiler-core/src/ast.ts
packages/compiler-core/src/codegen.ts
packages/compiler-core/src/transform.ts
packages/compiler-core/src/transforms/cacheStatic.ts
packages/compiler-core/src/transforms/transformElement.ts
packages/compiler-core/src/transforms/transformExpression.ts
packages/compiler-core/src/transforms/vFor.ts
packages/compiler-core/src/transforms/vIf.ts
packages/compiler-dom/__tests__/transforms/__snapshots__/stringifyStatic.spec.ts.snap
packages/compiler-dom/__tests__/transforms/vOn.spec.ts
packages/compiler-sfc/__tests__/__snapshots__/compileScript.spec.ts.snap
packages/compiler-sfc/__tests__/__snapshots__/templateTransformAssetUrl.spec.ts.snap
packages/compiler-sfc/__tests__/__snapshots__/templateTransformSrcset.spec.ts.snap
packages/compiler-sfc/package.json
packages/compiler-sfc/src/compileScript.ts
packages/compiler-sfc/src/script/definePropsDestructure.ts
packages/reactivity/__tests__/computed.spec.ts
packages/reactivity/__tests__/shallowReactive.spec.ts
packages/reactivity/src/collectionHandlers.ts
packages/reactivity/src/ref.ts
packages/runtime-core/__tests__/apiWatch.spec.ts
packages/runtime-core/__tests__/hydration.spec.ts
packages/runtime-core/__tests__/rendererOptimizedMode.spec.ts
packages/runtime-core/src/component.ts
packages/runtime-core/src/componentEmits.ts
packages/runtime-core/src/componentProps.ts
packages/runtime-core/src/customFormatter.ts
packages/runtime-core/src/errorHandling.ts
packages/runtime-core/src/hmr.ts
packages/runtime-core/src/hydration.ts
packages/runtime-core/src/renderer.ts
packages/runtime-core/src/scheduler.ts
packages/runtime-core/src/vnode.ts
packages/server-renderer/src/render.ts
packages/shared/src/toDisplayString.ts
packages/vue-compat/package.json

diff --cc CHANGELOG.md
Simple merge
diff --cc package.json
index 7dbd2117a956f678b6d431daa653e45bf40f9b10,e4fa3447529442c20b3e609886ebf10eeb3c539c..3397c9d939490f7626084baaebaba7983914477a
@@@ -1,7 -1,7 +1,7 @@@
  {
    "private": true,
 -  "version": "3.4.32",
 +  "version": "3.5.0-alpha.2",
-   "packageManager": "pnpm@9.3.0",
+   "packageManager": "pnpm@9.5.0",
    "type": "module",
    "scripts": {
      "dev": "node scripts/dev.js",
index 307cbbc8dcff1e972ad8dc2a3a8ed99e9d60ea9d,7724d507cb2a0d3cd66c2d2a430e5f62cfe3432f..34386ce6930b81eeae3d9aec3a967a10b838ca44
@@@ -437,10 -437,10 +437,10 @@@ describe('compiler: codegen', () => 
      expect(code).toMatchSnapshot()
    })
  
-   test('CacheExpression w/ isVNode: true', () => {
+   test('CacheExpression w/ isVOnce: true', () => {
      const { code } = generate(
        createRoot({
 -        cached: 1,
 +        cached: [],
          codegenNode: createCacheExpression(
            1,
            createSimpleExpression(`foo`, false),
index fc1446df5e233bd6dab1a235eecb0261d5663a46,ef3e2b8f4d69f9c73a3a982b28c0ee46b11ce184..8d0305ee3540f7926e5eae0303bd292c2b54a5d9
@@@ -7,9 -13,7 +7,9 @@@ return function render(_ctx, _cache) 
    with (_ctx) {
      const { createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue
  
 -    return (_openBlock(), _createElementBlock("div", null, _hoisted_2))
 +    return (_openBlock(), _createElementBlock("div", null, _cache[0] || (_cache[0] = [
-       _createElementVNode("div", { key: "foo" }, null, -1 /* CACHED */)
++      _createElementVNode("div", { key: "foo" }, null, -1 /* HOISTED */)
 +    ])))
    }
  }"
  `;
@@@ -21,16 -34,7 +21,16 @@@ return function render(_ctx, _cache) 
    with (_ctx) {
      const { createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue
  
 -    return (_openBlock(), _createElementBlock("div", null, _hoisted_2))
 +    return (_openBlock(), _createElementBlock("div", null, _cache[0] || (_cache[0] = [
 +      _createElementVNode("p", null, [
 +        _createElementVNode("span"),
 +        _createElementVNode("span")
-       ], -1 /* CACHED */),
++      ], -1 /* HOISTED */),
 +      _createElementVNode("p", null, [
 +        _createElementVNode("span"),
 +        _createElementVNode("span")
-       ], -1 /* CACHED */)
++      ], -1 /* HOISTED */)
 +    ])))
    }
  }"
  `;
@@@ -42,11 -54,7 +42,11 @@@ return function render(_ctx, _cache) 
    with (_ctx) {
      const { createCommentVNode: _createCommentVNode, createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue
  
 -    return (_openBlock(), _createElementBlock("div", null, _hoisted_2))
 +    return (_openBlock(), _createElementBlock("div", null, _cache[0] || (_cache[0] = [
 +      _createElementVNode("div", null, [
 +        _createCommentVNode("comment")
-       ], -1 /* CACHED */)
++      ], -1 /* HOISTED */)
 +    ])))
    }
  }"
  `;
@@@ -56,13 -64,17 +56,13 @@@ exports[`compiler: cacheStatic transfor
  
  return function render(_ctx, _cache) {
    with (_ctx) {
 -    const { createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue
 +    const { createElementVNode: _createElementVNode, createTextVNode: _createTextVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue
  
 -    return (_openBlock(), _createElementBlock("div", null, _hoisted_3))
 +    return (_openBlock(), _createElementBlock("div", null, _cache[0] || (_cache[0] = [
-       _createElementVNode("span", null, null, -1 /* CACHED */),
++      _createElementVNode("span", null, null, -1 /* HOISTED */),
 +      _createTextVNode("foo"),
-       _createElementVNode("div", null, null, -1 /* CACHED */)
++      _createElementVNode("div", null, null, -1 /* HOISTED */)
 +    ])))
    }
  }"
  `;
@@@ -74,9 -92,7 +74,9 @@@ return function render(_ctx, _cache) 
    with (_ctx) {
      const { createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue
  
 -    return (_openBlock(), _createElementBlock("div", null, _hoisted_2))
 +    return (_openBlock(), _createElementBlock("div", null, _cache[0] || (_cache[0] = [
-       _createElementVNode("span", { class: "inline" }, "hello", -1 /* CACHED */)
++      _createElementVNode("span", { class: "inline" }, "hello", -1 /* HOISTED */)
 +    ])))
    }
  }"
  `;
@@@ -145,11 -161,16 +145,11 @@@ exports[`compiler: cacheStatic transfor
  
  return function render(_ctx, _cache) {
    with (_ctx) {
 -    const { toDisplayString: _toDisplayString, normalizeClass: _normalizeClass, createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue
 +    const { toDisplayString: _toDisplayString, createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue
  
 -    return (_openBlock(), _createElementBlock("div", null, [
 -      _createElementVNode("span", _hoisted_1, _toDisplayString(_ctx.bar), 1 /* TEXT */)
 -    ]))
 +    return (_openBlock(), _createElementBlock("div", null, _cache[0] || (_cache[0] = [
-       _createElementVNode("span", null, "foo " + _toDisplayString(1) + " " + _toDisplayString(true), -1 /* CACHED */)
++      _createElementVNode("span", null, "foo " + _toDisplayString(1) + " " + _toDisplayString(true), -1 /* HOISTED */)
 +    ])))
    }
  }"
  `;
@@@ -161,9 -188,7 +161,9 @@@ return function render(_ctx, _cache) 
    with (_ctx) {
      const { toDisplayString: _toDisplayString, createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue
  
 -    return (_openBlock(), _createElementBlock("div", null, _hoisted_2))
 +    return (_openBlock(), _createElementBlock("div", null, _cache[0] || (_cache[0] = [
-       _createElementVNode("span", { foo: 0 }, _toDisplayString(1), -1 /* CACHED */)
++      _createElementVNode("span", { foo: 0 }, _toDisplayString(1), -1 /* HOISTED */)
 +    ])))
    }
  }"
  `;
@@@ -173,15 -198,15 +173,15 @@@ exports[`compiler: cacheStatic transfor
  
  return function render(_ctx, _cache) {
    with (_ctx) {
 -    const { toDisplayString: _toDisplayString, createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue
 +    const { renderList: _renderList, Fragment: _Fragment, openBlock: _openBlock, createElementBlock: _createElementBlock, createElementVNode: _createElementVNode } = _Vue
  
 -    return (_openBlock(), _createElementBlock("div", null, _hoisted_2))
 +    return (_openBlock(), _createElementBlock("div", null, [
 +      (_openBlock(true), _createElementBlock(_Fragment, null, _renderList(1, (i) => {
 +        return (_openBlock(), _createElementBlock("div", null, [...(_cache[0] || (_cache[0] = [
-           _createElementVNode("span", { class: "hi" }, null, -1 /* CACHED */)
++          _createElementVNode("span", { class: "hi" }, null, -1 /* HOISTED */)
 +        ]))]))
 +      }), 256 /* UNKEYED_FRAGMENT */))
 +    ]))
    }
  }"
  `;
@@@ -215,9 -227,7 +215,9 @@@ return function render(_ctx, _cache) 
      const _directive_foo = _resolveDirective("foo")
  
      return (_openBlock(), _createElementBlock("div", null, [
 -      _withDirectives((_openBlock(), _createElementBlock("svg", null, _hoisted_2)), [
 +      _withDirectives((_openBlock(), _createElementBlock("svg", null, _cache[0] || (_cache[0] = [
-         _createElementVNode("path", { d: "M2,3H5.5L12" }, null, -1 /* CACHED */)
++        _createElementVNode("path", { d: "M2,3H5.5L12" }, null, -1 /* HOISTED */)
 +      ]))), [
          [_directive_foo]
        ])
      ]))
@@@ -397,15 -401,9 +397,15 @@@ const _hoisted_1 = 
  
  return function render(_ctx, _cache) {
    with (_ctx) {
 -    const { openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue
 +    const { createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock, createCommentVNode: _createCommentVNode } = _Vue
  
 -    return (_openBlock(), _createElementBlock("div"))
 +    return (_openBlock(), _createElementBlock("div", null, [
 +      ok
 +        ? (_openBlock(), _createElementBlock("div", _hoisted_1, _cache[0] || (_cache[0] = [
-             _createElementVNode("span", null, null, -1 /* CACHED */)
++            _createElementVNode("span", null, null, -1 /* HOISTED */)
 +          ])))
 +        : _createCommentVNode("v-if", true)
 +    ]))
    }
  }"
  `;
@@@ -422,9 -424,7 +422,9 @@@ return function render(_ctx, _cache) 
  
      return (_openBlock(), _createElementBlock("div", null, [
        (_openBlock(true), _createElementBlock(_Fragment, null, _renderList(list, (i) => {
 -        return (_openBlock(), _createElementBlock("div", _hoisted_1, _hoisted_3))
 +        return (_openBlock(), _createElementBlock("div", _hoisted_1, _cache[0] || (_cache[0] = [
-           _createElementVNode("span", null, null, -1 /* CACHED */)
++          _createElementVNode("span", null, null, -1 /* HOISTED */)
 +        ])))
        }), 256 /* UNKEYED_FRAGMENT */))
      ]))
    }
index 8cfe83838013886adc87b5f8b33981d674e809af,d5a34243bcaaf55960f896a0a60f26a14919f869..ab5ed7baedeae9b77c95c8d00988b50e83188e16
@@@ -731,37 -594,16 +731,37 @@@ describe('compiler: cacheStatic transfo
        expect(generate(root).code).toMatchSnapshot()
      })
  
 -    test('clone hoisted array children in HMR mode', () => {
 -      const root = transformWithHoist(`<div><span class="hi"></span></div>`, {
 -        hmr: true,
 -      })
 -      expect(root.hoists.length).toBe(2)
 -      expect(root.codegenNode).toMatchObject({
 +    test('clone hoisted array children in v-for + HMR mode', () => {
 +      const root = transformWithCache(
 +        `<div><div v-for="i in 1"><span class="hi"></span></div></div>`,
 +        {
 +          hmr: true,
 +        },
 +      )
 +      expect(root.cached.length).toBe(1)
 +      const forBlockCodegen = (
 +        (root.children[0] as ElementNode).children[0] as ForNode
 +      ).codegenNode
 +      expect(forBlockCodegen).toMatchObject({
 +        type: NodeTypes.VNODE_CALL,
 +        tag: FRAGMENT,
 +        props: undefined,
          children: {
 -          content: '[..._hoisted_2]',
 +          type: NodeTypes.JS_CALL_EXPRESSION,
 +          callee: RENDER_LIST,
          },
-         patchFlag: genFlagText(PatchFlags.UNKEYED_FRAGMENT),
++        patchFlag: PatchFlags.UNKEYED_FRAGMENT,
        })
 +      const innerBlockCodegen = forBlockCodegen!.children.arguments[1]
 +      expect(innerBlockCodegen.returns).toMatchObject({
 +        type: NodeTypes.VNODE_CALL,
 +        tag: `"div"`,
 +        children: cachedChildrenArrayMatcher(
 +          ['span'],
 +          true /* needArraySpread */,
 +        ),
 +      })
 +      expect(generate(root).code).toMatchSnapshot()
      })
    })
  })
Simple merge
index 2dec11b0291018927ced62cee7ccc9784774a825,bbbb7f8a19dbc7fd3ad49476f917d037280f2f46..3d2ef05dcfbba8124855cbf99b9e4ef58350de6d
@@@ -330,9 -330,8 +330,9 @@@ export interface VNodeCall extends Nod
      | SlotsExpression // component slots
      | ForRenderListExpression // v-for fragment call
      | SimpleExpressionNode // hoisted
 +    | CacheExpression // cached
      | undefined
-   patchFlag: string | undefined
+   patchFlag: PatchFlags | undefined
    dynamicProps: string | SimpleExpressionNode | undefined
    directives: DirectiveArguments | undefined
    isBlock: boolean
index 779106d489016a78d6b533c9eec6577e8cf784a1,b6535c5cef9505ece39098e6f17c1ce22bbccfa9..2798ce989da7433ee8c466f19ee6583facc4da92
@@@ -993,8 -1045,8 +1022,8 @@@ function genCacheExpression(node: Cache
    }
    push(`_cache[${node.index}] = `)
    genNode(node.value, context)
 -  if (node.isVOnce) {
 +  if (needPauseTracking) {
-     push(`,`)
+     push(`).cacheIndex = ${node.index},`)
      newline()
      push(`${helper(SET_BLOCK_TRACKING)}(1),`)
      newline()
index 6b425b6931523658b7804321c10cbecb7a5aa18b,5942b73097b07c53b4ee7799a5b0d7a8d78b53fb..6ffd624ff53388c34765c402c44e8dd0f9d4d75d
@@@ -74,10 -69,10 +74,9 @@@ function walk
          ? ConstantTypes.NOT_CONSTANT
          : getConstantType(child, context)
        if (constantType > ConstantTypes.NOT_CONSTANT) {
 -        if (constantType >= ConstantTypes.CAN_HOIST) {
 -          ;(child.codegenNode as VNodeCall).patchFlag = PatchFlags.HOISTED
 -          child.codegenNode = context.hoist(child.codegenNode!)
 -          hoistedCount++
 +        if (constantType >= ConstantTypes.CAN_CACHE) {
-           ;(child.codegenNode as VNodeCall).patchFlag =
-             PatchFlags.CACHED + (__DEV__ ? ` /* CACHED */` : ``)
++          ;(child.codegenNode as VNodeCall).patchFlag = PatchFlags.CACHED
 +          toCache.push(child)
            continue
          }
        } else {
index ef0c54d34ef9aec7de952d9772d7adc28d7a607c,57d880a03f6e13ebe1e4949fd5186c5aa3667297..f55c27a9c6e976ca23d78a87e2502b3d8c637ade
@@@ -20,36 -19,23 +20,36 @@@ return function render(_ctx, _cache) 
  }"
  `;
  
 -exports[`stringify static html > should bail on bindings that are hoisted but not stringifiable 1`] = `
 +exports[`stringify static html > should bail for <option> elements with number values 1`] = `
  "const { createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
  
 -const _hoisted_1 = /*#__PURE__*/_createElementVNode("div", null, [
 -  /*#__PURE__*/_createElementVNode("span", { class: "foo" }, "foo"),
 -  /*#__PURE__*/_createElementVNode("span", { class: "foo" }, "foo"),
 -  /*#__PURE__*/_createElementVNode("span", { class: "foo" }, "foo"),
 -  /*#__PURE__*/_createElementVNode("span", { class: "foo" }, "foo"),
 -  /*#__PURE__*/_createElementVNode("span", { class: "foo" }, "foo"),
 -  /*#__PURE__*/_createElementVNode("img", { src: _imports_0_ })
 -], -1 /* HOISTED */)
 -const _hoisted_2 = [
 -  _hoisted_1
 -]
 +return function render(_ctx, _cache) {
 +  return (_openBlock(), _createElementBlock("div", null, _cache[0] || (_cache[0] = [
 +    _createElementVNode("select", null, [
 +      _createElementVNode("option", { value: 1 }),
 +      _createElementVNode("option", { value: 1 }),
 +      _createElementVNode("option", { value: 1 }),
 +      _createElementVNode("option", { value: 1 }),
 +      _createElementVNode("option", { value: 1 })
-     ], -1 /* CACHED */)
++    ], -1 /* HOISTED */)
 +  ])))
 +}"
 +`;
 +
 +exports[`stringify static html > should bail on bindings that are cached but not stringifiable 1`] = `
 +"const { createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
  
  return function render(_ctx, _cache) {
 -  return (_openBlock(), _createElementBlock("div", null, _hoisted_2))
 +  return (_openBlock(), _createElementBlock("div", null, _cache[0] || (_cache[0] = [
 +    _createElementVNode("div", null, [
 +      _createElementVNode("span", { class: "foo" }, "foo"),
 +      _createElementVNode("span", { class: "foo" }, "foo"),
 +      _createElementVNode("span", { class: "foo" }, "foo"),
 +      _createElementVNode("span", { class: "foo" }, "foo"),
 +      _createElementVNode("span", { class: "foo" }, "foo"),
 +      _createElementVNode("img", { src: _imports_0_ })
-     ], -1 /* CACHED */)
++    ], -1 /* HOISTED */)
 +  ])))
  }"
  `;
  
index c746a21ffaee77be0ce1396edf9649c17e5410ae,b557919cb9696d244fbb6f0f10144cbd48cd485e..e175cc0a8744b482e1400243afdf0e5b690f4541
@@@ -861,7 -863,7 +861,7 @@@ export default 
  return (_ctx, _cache) => {
    return (_openBlock(), _createElementBlock(_Fragment, null, [
      _createElementVNode("div", null, _toDisplayString(count.value), 1 /* TEXT */),
-     _cache[0] || (_cache[0] = _createElementVNode("div", null, "static", -1 /* CACHED */))
 -    _hoisted_1
++    _cache[0] || (_cache[0] = _createElementVNode("div", null, "static", -1 /* HOISTED */))
    ], 64 /* STABLE_FRAGMENT */))
  }
  }
index 18ec05da2b574ad66d9c47a1cfdd02331f67dc69,6af4115efb06ee5e266dd1210a3524711773de85..85ae6194a705198ba6b676f5cccf1cbb6473d664
@@@ -41,8 -41,10 +41,8 @@@ const _hoisted_1 = _imports_0 + '#fragm
  
  export function render(_ctx, _cache) {
    return (_openBlock(), _createElementBlock(_Fragment, null, [
-     _cache[0] || (_cache[0] = _createElementVNode("use", { href: _hoisted_1 }, null, -1 /* CACHED */)),
-     _cache[1] || (_cache[1] = _createElementVNode("use", { href: _hoisted_1 }, null, -1 /* CACHED */))
 -    _hoisted_2,
 -    _hoisted_3
++    _cache[0] || (_cache[0] = _createElementVNode("use", { href: _hoisted_1 }, null, -1 /* HOISTED */)),
++    _cache[1] || (_cache[1] = _createElementVNode("use", { href: _hoisted_1 }, null, -1 /* HOISTED */))
    ], 64 /* STABLE_FRAGMENT */))
  }"
  `;
index 0469ffaba88655cd95429cc95d7b27883eed6fd4,8aaba811404f01e1f2cb7d1833e4836f67865f7f..81cdb51b9cae1311a4b8c82c91eb7f9f8d281859
@@@ -10,8 -10,10 +10,8 @@@ const _hoisted_2 = _imports_0 + ' 1x, 
  
  export function render(_ctx, _cache) {
    return (_openBlock(), _createElementBlock(_Fragment, null, [
-     _cache[0] || (_cache[0] = _createElementVNode("img", { srcset: _hoisted_1 }, null, -1 /* CACHED */)),
-     _cache[1] || (_cache[1] = _createElementVNode("img", { srcset: _hoisted_2 }, null, -1 /* CACHED */))
 -    _hoisted_3,
 -    _hoisted_4
++    _cache[0] || (_cache[0] = _createElementVNode("img", { srcset: _hoisted_1 }, null, -1 /* HOISTED */)),
++    _cache[1] || (_cache[1] = _createElementVNode("img", { srcset: _hoisted_2 }, null, -1 /* HOISTED */))
    ], 64 /* STABLE_FRAGMENT */))
  }"
  `;
@@@ -32,54 -34,66 +32,54 @@@ const _hoisted_8 = "/logo.png" + ', ' 
  
  export function render(_ctx, _cache) {
    return (_openBlock(), _createElementBlock(_Fragment, null, [
 -    _hoisted_9,
 -    _hoisted_10,
 -    _hoisted_11,
 -    _hoisted_12,
 -    _hoisted_13,
 -    _hoisted_14,
 -    _hoisted_15,
 -    _hoisted_16,
 -    _hoisted_17,
 -    _hoisted_18,
 -    _hoisted_19,
 -    _hoisted_20
 +    _cache[0] || (_cache[0] = _createElementVNode("img", {
 +      src: "./logo.png",
 +      srcset: ""
-     }, null, -1 /* CACHED */)),
++    }, null, -1 /* HOISTED */)),
 +    _cache[1] || (_cache[1] = _createElementVNode("img", {
 +      src: "./logo.png",
 +      srcset: _hoisted_1
-     }, null, -1 /* CACHED */)),
++    }, null, -1 /* HOISTED */)),
 +    _cache[2] || (_cache[2] = _createElementVNode("img", {
 +      src: "./logo.png",
 +      srcset: _hoisted_2
-     }, null, -1 /* CACHED */)),
++    }, null, -1 /* HOISTED */)),
 +    _cache[3] || (_cache[3] = _createElementVNode("img", {
 +      src: "./logo.png",
 +      srcset: _hoisted_3
-     }, null, -1 /* CACHED */)),
++    }, null, -1 /* HOISTED */)),
 +    _cache[4] || (_cache[4] = _createElementVNode("img", {
 +      src: "./logo.png",
 +      srcset: _hoisted_4
-     }, null, -1 /* CACHED */)),
++    }, null, -1 /* HOISTED */)),
 +    _cache[5] || (_cache[5] = _createElementVNode("img", {
 +      src: "./logo.png",
 +      srcset: _hoisted_5
-     }, null, -1 /* CACHED */)),
++    }, null, -1 /* HOISTED */)),
 +    _cache[6] || (_cache[6] = _createElementVNode("img", {
 +      src: "./logo.png",
 +      srcset: _hoisted_6
-     }, null, -1 /* CACHED */)),
++    }, null, -1 /* HOISTED */)),
 +    _cache[7] || (_cache[7] = _createElementVNode("img", {
 +      src: "./logo.png",
 +      srcset: _hoisted_7
-     }, null, -1 /* CACHED */)),
++    }, null, -1 /* HOISTED */)),
 +    _cache[8] || (_cache[8] = _createElementVNode("img", {
 +      src: "/logo.png",
 +      srcset: "/logo.png, /logo.png 2x"
-     }, null, -1 /* CACHED */)),
++    }, null, -1 /* HOISTED */)),
 +    _cache[9] || (_cache[9] = _createElementVNode("img", {
 +      src: "https://example.com/logo.png",
 +      srcset: "https://example.com/logo.png, https://example.com/logo.png 2x"
-     }, null, -1 /* CACHED */)),
++    }, null, -1 /* HOISTED */)),
 +    _cache[10] || (_cache[10] = _createElementVNode("img", {
 +      src: "/logo.png",
 +      srcset: _hoisted_8
-     }, null, -1 /* CACHED */)),
++    }, null, -1 /* HOISTED */)),
 +    _cache[11] || (_cache[11] = _createElementVNode("img", {
 +      src: "data:image/png;base64,i",
 +      srcset: "data:image/png;base64,i 1x, data:image/png;base64,i 2x"
-     }, null, -1 /* CACHED */))
++    }, null, -1 /* HOISTED */))
    ], 64 /* STABLE_FRAGMENT */))
  }"
  `;
  exports[`compiler sfc: transform srcset > transform srcset w/ base 1`] = `
  "import { createElementVNode as _createElementVNode, Fragment as _Fragment, openBlock as _openBlock, createElementBlock as _createElementBlock } from "vue"
  
 -const _hoisted_1 = /*#__PURE__*/_createElementVNode("img", {
 -  src: "./logo.png",
 -  srcset: ""
 -}, null, -1 /* HOISTED */)
 -const _hoisted_2 = /*#__PURE__*/_createElementVNode("img", {
 -  src: "./logo.png",
 -  srcset: "/foo/logo.png"
 -}, null, -1 /* HOISTED */)
 -const _hoisted_3 = /*#__PURE__*/_createElementVNode("img", {
 -  src: "./logo.png",
 -  srcset: "/foo/logo.png 2x"
 -}, null, -1 /* HOISTED */)
 -const _hoisted_4 = /*#__PURE__*/_createElementVNode("img", {
 -  src: "./logo.png",
 -  srcset: "/foo/logo.png 2x"
 -}, null, -1 /* HOISTED */)
 -const _hoisted_5 = /*#__PURE__*/_createElementVNode("img", {
 -  src: "./logo.png",
 -  srcset: "/foo/logo.png, /foo/logo.png 2x"
 -}, null, -1 /* HOISTED */)
 -const _hoisted_6 = /*#__PURE__*/_createElementVNode("img", {
 -  src: "./logo.png",
 -  srcset: "/foo/logo.png 2x, /foo/logo.png"
 -}, null, -1 /* HOISTED */)
 -const _hoisted_7 = /*#__PURE__*/_createElementVNode("img", {
 -  src: "./logo.png",
 -  srcset: "/foo/logo.png 2x, /foo/logo.png 3x"
 -}, null, -1 /* HOISTED */)
 -const _hoisted_8 = /*#__PURE__*/_createElementVNode("img", {
 -  src: "./logo.png",
 -  srcset: "/foo/logo.png, /foo/logo.png 2x, /foo/logo.png 3x"
 -}, null, -1 /* HOISTED */)
 -const _hoisted_9 = /*#__PURE__*/_createElementVNode("img", {
 -  src: "/logo.png",
 -  srcset: "/logo.png, /logo.png 2x"
 -}, null, -1 /* HOISTED */)
 -const _hoisted_10 = /*#__PURE__*/_createElementVNode("img", {
 -  src: "https://example.com/logo.png",
 -  srcset: "https://example.com/logo.png, https://example.com/logo.png 2x"
 -}, null, -1 /* HOISTED */)
 -const _hoisted_11 = /*#__PURE__*/_createElementVNode("img", {
 -  src: "/logo.png",
 -  srcset: "/logo.png, /foo/logo.png 2x"
 -}, null, -1 /* HOISTED */)
 -const _hoisted_12 = /*#__PURE__*/_createElementVNode("img", {
 -  src: "data:image/png;base64,i",
 -  srcset: "data:image/png;base64,i 1x, data:image/png;base64,i 2x"
 -}, null, -1 /* HOISTED */)
 -
  export function render(_ctx, _cache) {
    return (_openBlock(), _createElementBlock(_Fragment, null, [
 -    _hoisted_1,
 -    _hoisted_2,
 -    _hoisted_3,
 -    _hoisted_4,
 -    _hoisted_5,
 -    _hoisted_6,
 -    _hoisted_7,
 -    _hoisted_8,
 -    _hoisted_9,
 -    _hoisted_10,
 -    _hoisted_11,
 -    _hoisted_12
 +    _cache[0] || (_cache[0] = _createElementVNode("img", {
 +      src: "./logo.png",
 +      srcset: ""
-     }, null, -1 /* CACHED */)),
++    }, null, -1 /* HOISTED */)),
 +    _cache[1] || (_cache[1] = _createElementVNode("img", {
 +      src: "./logo.png",
 +      srcset: "/foo/logo.png"
-     }, null, -1 /* CACHED */)),
++    }, null, -1 /* HOISTED */)),
 +    _cache[2] || (_cache[2] = _createElementVNode("img", {
 +      src: "./logo.png",
 +      srcset: "/foo/logo.png 2x"
-     }, null, -1 /* CACHED */)),
++    }, null, -1 /* HOISTED */)),
 +    _cache[3] || (_cache[3] = _createElementVNode("img", {
 +      src: "./logo.png",
 +      srcset: "/foo/logo.png 2x"
-     }, null, -1 /* CACHED */)),
++    }, null, -1 /* HOISTED */)),
 +    _cache[4] || (_cache[4] = _createElementVNode("img", {
 +      src: "./logo.png",
 +      srcset: "/foo/logo.png, /foo/logo.png 2x"
-     }, null, -1 /* CACHED */)),
++    }, null, -1 /* HOISTED */)),
 +    _cache[5] || (_cache[5] = _createElementVNode("img", {
 +      src: "./logo.png",
 +      srcset: "/foo/logo.png 2x, /foo/logo.png"
-     }, null, -1 /* CACHED */)),
++    }, null, -1 /* HOISTED */)),
 +    _cache[6] || (_cache[6] = _createElementVNode("img", {
 +      src: "./logo.png",
 +      srcset: "/foo/logo.png 2x, /foo/logo.png 3x"
-     }, null, -1 /* CACHED */)),
++    }, null, -1 /* HOISTED */)),
 +    _cache[7] || (_cache[7] = _createElementVNode("img", {
 +      src: "./logo.png",
 +      srcset: "/foo/logo.png, /foo/logo.png 2x, /foo/logo.png 3x"
-     }, null, -1 /* CACHED */)),
++    }, null, -1 /* HOISTED */)),
 +    _cache[8] || (_cache[8] = _createElementVNode("img", {
 +      src: "/logo.png",
 +      srcset: "/logo.png, /logo.png 2x"
-     }, null, -1 /* CACHED */)),
++    }, null, -1 /* HOISTED */)),
 +    _cache[9] || (_cache[9] = _createElementVNode("img", {
 +      src: "https://example.com/logo.png",
 +      srcset: "https://example.com/logo.png, https://example.com/logo.png 2x"
-     }, null, -1 /* CACHED */)),
++    }, null, -1 /* HOISTED */)),
 +    _cache[10] || (_cache[10] = _createElementVNode("img", {
 +      src: "/logo.png",
 +      srcset: "/logo.png, /foo/logo.png 2x"
-     }, null, -1 /* CACHED */)),
++    }, null, -1 /* HOISTED */)),
 +    _cache[11] || (_cache[11] = _createElementVNode("img", {
 +      src: "data:image/png;base64,i",
 +      srcset: "data:image/png;base64,i 1x, data:image/png;base64,i 2x"
-     }, null, -1 /* CACHED */))
++    }, null, -1 /* HOISTED */))
    ], 64 /* STABLE_FRAGMENT */))
  }"
  `;
@@@ -159,54 -186,66 +159,54 @@@ const _hoisted_9 = _imports_1 + ', ' + 
  
  export function render(_ctx, _cache) {
    return (_openBlock(), _createElementBlock(_Fragment, null, [
 -    _hoisted_10,
 -    _hoisted_11,
 -    _hoisted_12,
 -    _hoisted_13,
 -    _hoisted_14,
 -    _hoisted_15,
 -    _hoisted_16,
 -    _hoisted_17,
 -    _hoisted_18,
 -    _hoisted_19,
 -    _hoisted_20,
 -    _hoisted_21
 +    _cache[0] || (_cache[0] = _createElementVNode("img", {
 +      src: "./logo.png",
 +      srcset: ""
-     }, null, -1 /* CACHED */)),
++    }, null, -1 /* HOISTED */)),
 +    _cache[1] || (_cache[1] = _createElementVNode("img", {
 +      src: "./logo.png",
 +      srcset: _hoisted_1
-     }, null, -1 /* CACHED */)),
++    }, null, -1 /* HOISTED */)),
 +    _cache[2] || (_cache[2] = _createElementVNode("img", {
 +      src: "./logo.png",
 +      srcset: _hoisted_2
-     }, null, -1 /* CACHED */)),
++    }, null, -1 /* HOISTED */)),
 +    _cache[3] || (_cache[3] = _createElementVNode("img", {
 +      src: "./logo.png",
 +      srcset: _hoisted_3
-     }, null, -1 /* CACHED */)),
++    }, null, -1 /* HOISTED */)),
 +    _cache[4] || (_cache[4] = _createElementVNode("img", {
 +      src: "./logo.png",
 +      srcset: _hoisted_4
-     }, null, -1 /* CACHED */)),
++    }, null, -1 /* HOISTED */)),
 +    _cache[5] || (_cache[5] = _createElementVNode("img", {
 +      src: "./logo.png",
 +      srcset: _hoisted_5
-     }, null, -1 /* CACHED */)),
++    }, null, -1 /* HOISTED */)),
 +    _cache[6] || (_cache[6] = _createElementVNode("img", {
 +      src: "./logo.png",
 +      srcset: _hoisted_6
-     }, null, -1 /* CACHED */)),
++    }, null, -1 /* HOISTED */)),
 +    _cache[7] || (_cache[7] = _createElementVNode("img", {
 +      src: "./logo.png",
 +      srcset: _hoisted_7
-     }, null, -1 /* CACHED */)),
++    }, null, -1 /* HOISTED */)),
 +    _cache[8] || (_cache[8] = _createElementVNode("img", {
 +      src: "/logo.png",
 +      srcset: _hoisted_8
-     }, null, -1 /* CACHED */)),
++    }, null, -1 /* HOISTED */)),
 +    _cache[9] || (_cache[9] = _createElementVNode("img", {
 +      src: "https://example.com/logo.png",
 +      srcset: "https://example.com/logo.png, https://example.com/logo.png 2x"
-     }, null, -1 /* CACHED */)),
++    }, null, -1 /* HOISTED */)),
 +    _cache[10] || (_cache[10] = _createElementVNode("img", {
 +      src: "/logo.png",
 +      srcset: _hoisted_9
-     }, null, -1 /* CACHED */)),
++    }, null, -1 /* HOISTED */)),
 +    _cache[11] || (_cache[11] = _createElementVNode("img", {
 +      src: "data:image/png;base64,i",
 +      srcset: "data:image/png;base64,i 1x, data:image/png;base64,i 2x"
-     }, null, -1 /* CACHED */))
++    }, null, -1 /* HOISTED */))
    ], 64 /* STABLE_FRAGMENT */))
  }"
  `;
Simple merge
index fbe321dcaeeef25f7d4e50d2f369f29b85a331b3,20faa18a323e4903c1b7ef638f8b03d770971fc2..08b034f79f1bf94ef28bdedcb0d906c799384ab9
@@@ -577,333 -615,26 +577,349 @@@ describe('reactivity/computed', () => 
  
      v.value += ' World'
      await nextTick()
 -    expect(serializeInner(root)).toBe('Hello World World World World')
 -    expect(COMPUTED_SIDE_EFFECT_WARN).toHaveBeenWarned()
 +    expect(serializeInner(root)).toBe('Hello World World World')
 +    // expect(COMPUTED_SIDE_EFFECT_WARN).toHaveBeenWarned()
 +  })
 +
 +  test('should not trigger if value did not change', () => {
 +    const src = ref(0)
 +    const c = computed(() => src.value % 2)
 +    const spy = vi.fn()
 +    effect(() => {
 +      spy(c.value)
 +    })
 +    expect(spy).toHaveBeenCalledTimes(1)
 +    src.value = 2
 +
 +    // should not trigger
 +    expect(spy).toHaveBeenCalledTimes(1)
 +
 +    src.value = 3
 +    src.value = 5
 +    // should trigger because latest value changes
 +    expect(spy).toHaveBeenCalledTimes(2)
 +  })
 +
 +  test('chained computed trigger', () => {
 +    const effectSpy = vi.fn()
 +    const c1Spy = vi.fn()
 +    const c2Spy = vi.fn()
 +
 +    const src = ref(0)
 +    const c1 = computed(() => {
 +      c1Spy()
 +      return src.value % 2
 +    })
 +    const c2 = computed(() => {
 +      c2Spy()
 +      return c1.value + 1
 +    })
 +
 +    effect(() => {
 +      effectSpy(c2.value)
 +    })
 +
 +    expect(c1Spy).toHaveBeenCalledTimes(1)
 +    expect(c2Spy).toHaveBeenCalledTimes(1)
 +    expect(effectSpy).toHaveBeenCalledTimes(1)
 +
 +    src.value = 1
 +    expect(c1Spy).toHaveBeenCalledTimes(2)
 +    expect(c2Spy).toHaveBeenCalledTimes(2)
 +    expect(effectSpy).toHaveBeenCalledTimes(2)
 +  })
 +
 +  test('chained computed avoid re-compute', () => {
 +    const effectSpy = vi.fn()
 +    const c1Spy = vi.fn()
 +    const c2Spy = vi.fn()
 +
 +    const src = ref(0)
 +    const c1 = computed(() => {
 +      c1Spy()
 +      return src.value % 2
 +    })
 +    const c2 = computed(() => {
 +      c2Spy()
 +      return c1.value + 1
 +    })
 +
 +    effect(() => {
 +      effectSpy(c2.value)
 +    })
 +
 +    expect(effectSpy).toHaveBeenCalledTimes(1)
 +    src.value = 2
 +    src.value = 4
 +    src.value = 6
 +    expect(c1Spy).toHaveBeenCalledTimes(4)
 +    // c2 should not have to re-compute because c1 did not change.
 +    expect(c2Spy).toHaveBeenCalledTimes(1)
 +    // effect should not trigger because c2 did not change.
 +    expect(effectSpy).toHaveBeenCalledTimes(1)
 +  })
 +
 +  test('chained computed value invalidation', () => {
 +    const effectSpy = vi.fn()
 +    const c1Spy = vi.fn()
 +    const c2Spy = vi.fn()
 +
 +    const src = ref(0)
 +    const c1 = computed(() => {
 +      c1Spy()
 +      return src.value % 2
 +    })
 +    const c2 = computed(() => {
 +      c2Spy()
 +      return c1.value + 1
 +    })
 +
 +    effect(() => {
 +      effectSpy(c2.value)
 +    })
 +
 +    expect(effectSpy).toHaveBeenCalledTimes(1)
 +    expect(effectSpy).toHaveBeenCalledWith(1)
 +    expect(c2.value).toBe(1)
 +
 +    expect(c1Spy).toHaveBeenCalledTimes(1)
 +    expect(c2Spy).toHaveBeenCalledTimes(1)
 +
 +    src.value = 1
 +    // value should be available sync
 +    expect(c2.value).toBe(2)
 +    expect(c2Spy).toHaveBeenCalledTimes(2)
 +  })
 +
 +  test('sync access of invalidated chained computed should not prevent final effect from running', () => {
 +    const effectSpy = vi.fn()
 +    const c1Spy = vi.fn()
 +    const c2Spy = vi.fn()
 +
 +    const src = ref(0)
 +    const c1 = computed(() => {
 +      c1Spy()
 +      return src.value % 2
 +    })
 +    const c2 = computed(() => {
 +      c2Spy()
 +      return c1.value + 1
 +    })
 +
 +    effect(() => {
 +      effectSpy(c2.value)
 +    })
 +    expect(effectSpy).toHaveBeenCalledTimes(1)
 +
 +    src.value = 1
 +    // sync access c2
 +    c2.value
 +    expect(effectSpy).toHaveBeenCalledTimes(2)
 +  })
 +
 +  it('computed should force track in untracked zone', () => {
 +    const n = ref(0)
 +    const spy1 = vi.fn()
 +    const spy2 = vi.fn()
 +
 +    let c: ComputedRef
 +    effect(() => {
 +      spy1()
 +      pauseTracking()
 +      n.value
 +      c = computed(() => n.value + 1)
 +      // access computed now to force refresh
 +      c.value
 +      effect(() => spy2(c.value))
 +      n.value
 +      resetTracking()
 +    })
 +
 +    expect(spy1).toHaveBeenCalledTimes(1)
 +    expect(spy2).toHaveBeenCalledTimes(1)
 +
 +    n.value++
 +    // outer effect should not trigger
 +    expect(spy1).toHaveBeenCalledTimes(1)
 +    // inner effect should trigger
 +    expect(spy2).toHaveBeenCalledTimes(2)
 +  })
 +
 +  // not recommended behavior, but needed for backwards compatibility
 +  // used in VueUse asyncComputed
 +  it('computed side effect should be able trigger', () => {
 +    const a = ref(false)
 +    const b = ref(false)
 +    const c = computed(() => {
 +      a.value = true
 +      return b.value
 +    })
 +    effect(() => {
 +      if (a.value) {
 +        b.value = true
 +      }
 +    })
 +    expect(b.value).toBe(false)
 +    // accessing c triggers change
 +    c.value
 +    expect(b.value).toBe(true)
 +    expect(c.value).toBe(true)
 +  })
 +
 +  it('chained computed should work when accessed before having subs', () => {
 +    const n = ref(0)
 +    const c = computed(() => n.value)
 +    const d = computed(() => c.value + 1)
 +    const spy = vi.fn()
 +
 +    // access
 +    d.value
 +
 +    let dummy
 +    effect(() => {
 +      spy()
 +      dummy = d.value
 +    })
 +    expect(spy).toHaveBeenCalledTimes(1)
 +    expect(dummy).toBe(1)
 +
 +    n.value++
 +    expect(spy).toHaveBeenCalledTimes(2)
 +    expect(dummy).toBe(2)
 +  })
 +
 +  // #10236
 +  it('chained computed should still refresh after owner component unmount', async () => {
 +    const a = ref(0)
 +    const spy = vi.fn()
 +
 +    const Child = {
 +      setup() {
 +        const b = computed(() => a.value + 1)
 +        const c = computed(() => b.value + 1)
 +        // access
 +        c.value
 +        onUnmounted(() => spy(c.value))
 +        return () => {}
 +      },
 +    }
 +
 +    const show = ref(true)
 +    const Parent = {
 +      setup() {
 +        return () => (show.value ? h(Child) : null)
 +      },
 +    }
 +
 +    render(h(Parent), nodeOps.createElement('div'))
 +
 +    a.value++
 +    show.value = false
 +
 +    await nextTick()
 +    expect(spy).toHaveBeenCalledWith(3)
 +  })
 +
 +  // case: radix-vue `useForwardExpose` sets a template ref during mount,
 +  // and checks for the element's closest form element in a computed.
 +  // the computed is expected to only evaluate after mount.
 +  it('computed deps should only be refreshed when the subscribing effect is run, not when scheduled', async () => {
 +    const calls: string[] = []
 +    const a = ref(0)
 +    const b = computed(() => {
 +      calls.push('b eval')
 +      return a.value + 1
 +    })
 +
 +    const App = {
 +      setup() {
 +        onMounted(() => {
 +          calls.push('mounted')
 +        })
 +        return () =>
 +          h(
 +            'div',
 +            {
 +              ref: () => (a.value = 1),
 +            },
 +            b.value,
 +          )
 +      },
 +    }
 +
 +    render(h(App), nodeOps.createElement('div'))
 +
 +    await nextTick()
 +    expect(calls).toMatchObject(['b eval', 'mounted', 'b eval'])
 +  })
 +
 +  it('should chained computeds keep reactivity when computed effect happens', async () => {
 +    const v = ref('Hello')
 +    const c = computed(() => {
 +      v.value += ' World'
 +      return v.value
 +    })
 +    const d = computed(() => c.value)
 +    const e = computed(() => d.value)
 +    const Comp = {
 +      setup: () => {
 +        return () => d.value + ' | ' + e.value
 +      },
 +    }
 +    const root = nodeOps.createElement('div')
 +
 +    render(h(Comp), root)
 +    await nextTick()
 +    expect(serializeInner(root)).toBe('Hello World | Hello World')
 +
 +    v.value += ' World'
 +    await nextTick()
 +    expect(serializeInner(root)).toBe(
 +      'Hello World World World | Hello World World World',
 +    )
 +  })
 +
 +  it('should keep dirty level when side effect computed value changed', () => {
 +    const v = ref(0)
 +    const c = computed(() => {
 +      v.value += 1
 +      return v.value
 +    })
 +    const d = computed(() => {
 +      return { d: c.value }
 +    })
 +
 +    const Comp = {
 +      setup: () => {
 +        return () => {
 +          return [d.value.d, d.value.d]
 +        }
 +      },
 +    }
 +
 +    const root = nodeOps.createElement('div')
 +    render(h(Comp), root)
 +
 +    expect(d.value.d).toBe(1)
 +    expect(serializeInner(root)).toBe('11')
    })
  
 -    expect(COMPUTED_SIDE_EFFECT_WARN).toHaveBeenWarned()
+   it('should be recomputed without being affected by side effects', () => {
+     const v = ref(0)
+     const c1 = computed(() => {
+       v.value = 1
+       return 0
+     })
+     const c2 = computed(() => {
+       return v.value + ',' + c1.value
+     })
+     expect(c2.value).toBe('0,0')
+     v.value = 1
+     expect(c2.value).toBe('1,0')
++    // expect(COMPUTED_SIDE_EFFECT_WARN).toHaveBeenWarned()
+   })
    it('debug: onTrigger (ref)', () => {
      let events: DebuggerEvent[] = []
      const onTrigger = vi.fn((e: DebuggerEvent) => {
index 9e05ee48002e8f6ed05a7b595a5542ce64d78398,c39e3ed48cdfb832a40e669222a0dee98808c47e..79ec333dd0348771561c0f98d8d1cdd98642d318
@@@ -1,5 -1,16 +1,12 @@@
- import { type Target, toRaw, toReactive, toReadonly } from './reactive'
+ import {
++  type Target,
+   isReadonly,
+   isShallow,
+   toRaw,
+   toReactive,
+   toReadonly,
+ } from './reactive'
 -import {
 -  ITERATE_KEY,
 -  MAP_KEY_ITERATE_KEY,
 -  track,
 -  trigger,
 -} from './reactiveEffect'
 +import { ITERATE_KEY, MAP_KEY_ITERATE_KEY, track, trigger } from './dep'
  import { ReactiveFlags, TrackOpTypes, TriggerOpTypes } from './constants'
  import { capitalize, hasChanged, hasOwn, isMap, toRawType } from '@vue/shared'
  import { warn } from './warning'
Simple merge
index 556ab75209bab97be4f9223aae8267eeda96558a,e0b49a5e7eb9fb1e9f5fec70b7623afd53aa780f..f4d5eba9a9aef3cf527f71bb6f249a34a431adf5
@@@ -959,4 -965,271 +965,271 @@@ describe('renderer: optimized mode', (
      // should successfully unmount without error
      expect(inner(root)).toBe(`<!---->`)
    })
 -                          PatchFlags.HOISTED,
+   // #10870
+   test('should bail manually rendered compiler slots for both mount and update', async () => {
+     // only reproducible in prod
+     __DEV__ = false
+     function Outer(_: any, { slots }: any) {
+       return slots.default()
+     }
+     const Mid = {
+       render(ctx: any) {
+         return (
+           openBlock(),
+           createElementBlock('div', null, [renderSlot(ctx.$slots, 'default')])
+         )
+       },
+     }
+     const state1 = ref(true)
+     const state2 = ref(true)
+     const App = {
+       render() {
+         return (
+           openBlock(),
+           createBlock(Outer, null, {
+             default: withCtx(() => [
+               createVNode(
+                 Mid,
+                 { foo: state2.value },
+                 {
+                   default: withCtx(() => [
+                     createElementVNode('div', null, [
+                       createElementVNode('div', null, [
+                         state2.value
+                           ? (openBlock(),
+                             createElementBlock(
+                               'div',
+                               {
+                                 key: 0,
+                                 id: 'if',
+                                 foo: state1.value,
+                               },
+                               null,
+                               8 /* PROPS */,
+                               ['foo'],
+                             ))
+                           : createCommentVNode('v-if', true),
+                       ]),
+                     ]),
+                   ]),
+                   _: 1 /* STABLE */,
+                 },
+                 8 /* PROPS */,
+                 ['foo'],
+               ),
+             ]),
+             _: 1 /* STABLE */,
+           })
+         )
+       },
+     }
+     const app = createApp(App)
+     app.config.errorHandler = vi.fn()
+     try {
+       app.mount(root)
+       state1.value = false
+       await nextTick()
+       state2.value = false
+       await nextTick()
+     } finally {
+       __DEV__ = true
+       expect(app.config.errorHandler).not.toHaveBeenCalled()
+     }
+   })
+   // #11336
+   test('should bail manually rendered compiler slots for both mount and update (2)', async () => {
+     // only reproducible in prod
+     __DEV__ = false
+     const n = ref(0)
+     function Outer(_: any, { slots }: any) {
+       n.value // track
+       return slots.default()
+     }
+     const Mid = {
+       render(ctx: any) {
+         return (
+           openBlock(),
+           createElementBlock('div', null, [renderSlot(ctx.$slots, 'default')])
+         )
+       },
+     }
+     const show = ref(false)
+     const App = {
+       render() {
+         return (
+           openBlock(),
+           createBlock(Outer, null, {
+             default: withCtx(() => [
+               createVNode(Mid, null, {
+                 default: withCtx(() => [
+                   createElementVNode('div', null, [
+                     show.value
+                       ? (openBlock(),
+                         createElementBlock('div', { key: 0 }, '1'))
+                       : createCommentVNode('v-if', true),
+                     createElementVNode('div', null, '2'),
+                     createElementVNode('div', null, '3'),
+                   ]),
+                   createElementVNode('div', null, '4'),
+                 ]),
+                 _: 1 /* STABLE */,
+               }),
+             ]),
+             _: 1 /* STABLE */,
+           })
+         )
+       },
+     }
+     const app = createApp(App)
+     app.config.errorHandler = vi.fn()
+     try {
+       app.mount(root)
+       // force Outer update, which will assign new slots to Mid
+       // we want to make sure the compiled slot flag doesn't accidentally
+       // get assigned again
+       n.value++
+       await nextTick()
+       show.value = true
+       await nextTick()
+     } finally {
+       __DEV__ = true
+       expect(app.config.errorHandler).not.toHaveBeenCalled()
+     }
+   })
+   test('diff slot and slot fallback node', async () => {
+     const Comp = {
+       props: ['show'],
+       setup(props: any, { slots }: SetupContext) {
+         return () => {
+           return (
+             openBlock(),
+             createElementBlock('div', null, [
+               renderSlot(slots, 'default', { hide: !props.show }, () => [
+                 (openBlock(),
+                 (block = createElementBlock(
+                   Fragment,
+                   { key: 0 },
+                   [createTextVNode('foo')],
+                   PatchFlags.STABLE_FRAGMENT,
+                 ))),
+               ]),
+             ])
+           )
+         }
+       },
+     }
+     const show = ref(true)
+     const app = createApp({
+       render() {
+         return (
+           openBlock(),
+           createBlock(
+             Comp,
+             { show: show.value },
+             {
+               default: withCtx(({ hide }: { hide: boolean }) => [
+                 !hide
+                   ? (openBlock(),
+                     createElementBlock(
+                       Fragment,
+                       { key: 0 },
+                       [
+                         createCommentVNode('comment'),
+                         createElementVNode(
+                           'div',
+                           null,
+                           'bar',
++                          PatchFlags.CACHED,
+                         ),
+                       ],
+                       PatchFlags.STABLE_FRAGMENT,
+                     ))
+                   : createCommentVNode('v-if', true),
+               ]),
+               _: SlotFlags.STABLE,
+             },
+             PatchFlags.PROPS,
+             ['show'],
+           )
+         )
+       },
+     })
+     app.mount(root)
+     expect(inner(root)).toBe('<div><!--comment--><div>bar</div></div>')
+     expect(block).toBe(null)
+     show.value = false
+     await nextTick()
+     expect(inner(root)).toBe('<div>foo</div>')
+     show.value = true
+     await nextTick()
+     expect(inner(root)).toBe('<div><!--comment--><div>bar</div></div>')
+   })
+   test('should not take unmount children fast path if children contain cached nodes', async () => {
+     const show = ref(true)
+     const spyUnmounted = vi.fn()
+     const Child = {
+       setup() {
+         onUnmounted(spyUnmounted)
+         return () => createVNode('div', null, 'Child')
+       },
+     }
+     const app = createApp({
+       render(_: any, cache: any) {
+         return show.value
+           ? (openBlock(),
+             createBlock('div', null, [
+               createVNode('div', null, [
+                 cache[0] ||
+                   (setBlockTracking(-1),
+                   ((cache[0] = createVNode('div', null, [
+                     createVNode(Child),
+                   ])).cacheIndex = 0),
+                   setBlockTracking(1),
+                   cache[0]),
+               ]),
+             ]))
+           : createCommentVNode('v-if', true)
+       },
+     })
+     app.mount(root)
+     expect(inner(root)).toBe(
+       '<div><div><div><div>Child</div></div></div></div>',
+     )
+     show.value = false
+     await nextTick()
+     expect(inner(root)).toBe('<!--v-if-->')
+     expect(spyUnmounted).toHaveBeenCalledTimes(1)
+     show.value = true
+     await nextTick()
+     expect(inner(root)).toBe(
+       '<div><div><div><div>Child</div></div></div></div>',
+     )
+     // should unmount again, this verifies previous cache was properly cleared
+     show.value = false
+     await nextTick()
+     expect(inner(root)).toBe('<!--v-if-->')
+     expect(spyUnmounted).toHaveBeenCalledTimes(2)
+   })
  })
index eb80d02afb6b3b7f0c371cf19e41832c1379a221,b6589b922277b87b0125e5b018487cbb66c48f7b..7221cf6ee57dac3a94d412250b43c701e28d54ba
@@@ -29,7 -28,7 +29,8 @@@ import 
    compatModelEmit,
    compatModelEventPrefix,
  } from './compat/componentVModel'
 +import type { ComponentTypeEmits } from './apiSetupHelpers'
+ import { getModelModifiers } from './helpers/useModel'
  
  export type ObjectEmitsOptions = Record<
    string,
index d983999b213e070ff731f9fe7b35b30aced1c90c,d243db5bffd0e0ec356915c975942bd50db8a1d2..8eb0cfcc64719f589e080d06686813616f07ee7a
@@@ -23,7 -23,7 +23,8 @@@ export enum ErrorCodes 
    FUNCTION_REF,
    ASYNC_COMPONENT_LOADER,
    SCHEDULER,
+   COMPONENT_UPDATE,
 +  APP_UNMOUNT_CLEANUP,
  }
  
  export const ErrorTypeStrings: Record<LifecycleHooks | ErrorCodes, string> = {
    [ErrorCodes.APP_WARN_HANDLER]: 'app warnHandler',
    [ErrorCodes.FUNCTION_REF]: 'ref function',
    [ErrorCodes.ASYNC_COMPONENT_LOADER]: 'async component loader',
-   [ErrorCodes.SCHEDULER]:
-     'scheduler flush. This is likely a Vue internals bug. ' +
-     'Please open an issue at https://github.com/vuejs/core .',
+   [ErrorCodes.SCHEDULER]: 'scheduler flush',
+   [ErrorCodes.COMPONENT_UPDATE]: 'component update',
 +  [ErrorCodes.APP_UNMOUNT_CLEANUP]: 'app unmount cleanup function',
  }
  
  export type ErrorTypes = LifecycleHooks | ErrorCodes
@@@ -111,9 -109,7 +111,9 @@@ export function handleError
    type: ErrorTypes,
    throwInDev = true,
  ) {
-   const contextVNode = instance && instance.vnode
+   const contextVNode = instance ? instance.vnode : null
 +  const { errorHandler, throwUnhandledErrorInProduction } =
 +    (instance && instance.appContext.config) || EMPTY_OBJ
    if (instance) {
      let cur = instance.parent
      // the exposed instance is the render proxy to keep it consistent with 2.x
index 56aa3c64b157e00084f524d4892726e2198df6e7,5a4a95705b0ba093244b2fde55d97f84d0862434..e5c16b7077bb3fab3a7d3baba60a4cd1f563614b
@@@ -137,10 -144,11 +143,10 @@@ function reload(id: string, newComp: HM
        // 4. Force the parent instance to re-render. This will cause all updated
        // components to be unmounted and re-mounted. Queue the update so that we
        // don't end up forcing the same parent to re-render multiple times.
 -      instance.parent.effect.dirty = true
        queueJob(() => {
          instance.parent!.update()
-         // #6930 avoid infinite recursion
-         hmrDirtyComponents.delete(oldComp)
+         // #6930, #11248 avoid infinite recursion
+         dirtyInstances.delete(instance)
        })
      } else if (instance.appContext.reload) {
        // root instance mounted via createApp() has a reload method
index b52ac9e45ba8ffef176746f104e7b1eb92285131,db674f987d81eefaaecf4f191991c91c3ddb3f4a..4452407c2a8f4541be2450c4403bbd2c210194fd
@@@ -1580,15 -1534,20 +1539,16 @@@ function baseCreateRenderer
      }
  
      // create reactive effect for rendering
 -    const effect = (instance.effect = new ReactiveEffect(
 -      componentUpdateFn,
 -      NOOP,
 -      () => queueJob(update),
 -      instance.scope, // track it in component's effect scope
 -    ))
 -
 -    const update: SchedulerJob = (instance.update = () => {
 -      if (effect.dirty) {
 -        effect.run()
 -      }
 -    })
 -    update.i = instance
 -    update.id = instance.uid
 +    instance.scope.on()
 +    const effect = (instance.effect = new ReactiveEffect(componentUpdateFn))
 +    instance.scope.off()
 +
 +    const update = (instance.update = effect.run.bind(effect))
 +    const job: SchedulerJob = (instance.job = effect.runIfDirty.bind(effect))
++    job.i = instance
 +    job.id = instance.uid
 +    effect.scheduler = () => queueJob(job)
 +
      // allowRecurse
      // #1801, #2043 component render effects should allow recursive updates
      toggleRecurse(instance, true)
index 1c42b1779eae72dc2c8355432f6677663b980cd9,c1f9d4c9141ecfbef4f402767845e8bfbdc9d243..cf730195dbc566e233c0bd40e8c0efe06b259140
@@@ -250,8 -239,11 +249,12 @@@ function flushJobs(seen?: CountMap) 
          if (__DEV__ && check(job)) {
            continue
          }
-         callWithErrorHandling(job, null, ErrorCodes.SCHEDULER)
+         callWithErrorHandling(
+           job,
+           job.i,
+           job.i ? ErrorCodes.COMPONENT_UPDATE : ErrorCodes.SCHEDULER,
+         )
 +        job.flags! &= ~SchedulerJobFlags.QUEUED
        }
      }
    } finally {
Simple merge
index 2ee406a9d9799b400937399d0b659dacb563f0af,6d6948bc5d25b160acbc696821f692eaf1c5c3ab..b23cf766a5c802e88c2324578b411e9e05074c0c
@@@ -1,4 -1,3 +1,5 @@@
++// enums are compiled away via custom transform so no real dependency here
 +import { ReactiveFlags } from '@vue/reactivity'
  import {
    isArray,
    isFunction,
    objectToString,
  } from './general'
  
 -  return !!(val && val.__v_isRef === true)
+ // can't use isRef here since @vue/shared has no deps
+ const isRef = (val: any): val is { value: unknown } => {
++  return !!(val && val[ReactiveFlags.IS_REF] === true)
+ }
  /**
   * For converting {{ interpolation }} values to displayed strings.
   * @private
Simple merge