From 352bc88c1bd2fda09c61ab17ea1a5967ffcd7bc0 Mon Sep 17 00:00:00 2001
From: Evan You <evan@vuejs.org>
Date: Fri, 15 Nov 2024 17:20:59 +0800
Subject: [PATCH] fix(custom-element): avoid triggering mutationObserver when
 relecting props

close #12214
close #12215
---
 .../__tests__/customElement.spec.ts           | 32 +++++++++++++++++++
 packages/runtime-dom/src/apiCustomElement.ts  |  3 ++
 2 files changed, 35 insertions(+)

diff --git a/packages/runtime-dom/__tests__/customElement.spec.ts b/packages/runtime-dom/__tests__/customElement.spec.ts
index 6b9f7d1391e..df438d47eee 100644
--- a/packages/runtime-dom/__tests__/customElement.spec.ts
+++ b/packages/runtime-dom/__tests__/customElement.spec.ts
@@ -396,6 +396,38 @@ describe('defineCustomElement', () => {
       expect(e.value).toBe('hi')
     })
 
+    // #12214
+    test('Boolean prop with default true', async () => {
+      const E = defineCustomElement({
+        props: {
+          foo: {
+            type: Boolean,
+            default: true,
+          },
+        },
+        render() {
+          return String(this.foo)
+        },
+      })
+      customElements.define('my-el-default-true', E)
+      container.innerHTML = `<my-el-default-true></my-el-default-true>`
+      const e = container.childNodes[0] as HTMLElement & { foo: any },
+        shadowRoot = e.shadowRoot as ShadowRoot
+      expect(shadowRoot.innerHTML).toBe('true')
+      e.foo = undefined
+      await nextTick()
+      expect(shadowRoot.innerHTML).toBe('true')
+      e.foo = false
+      await nextTick()
+      expect(shadowRoot.innerHTML).toBe('false')
+      e.foo = null
+      await nextTick()
+      expect(shadowRoot.innerHTML).toBe('null')
+      e.foo = ''
+      await nextTick()
+      expect(shadowRoot.innerHTML).toBe('true')
+    })
+
     test('support direct setup function syntax with extra options', () => {
       const E = defineCustomElement(
         props => {
diff --git a/packages/runtime-dom/src/apiCustomElement.ts b/packages/runtime-dom/src/apiCustomElement.ts
index 6ddaf897130..aeeaeec9b9f 100644
--- a/packages/runtime-dom/src/apiCustomElement.ts
+++ b/packages/runtime-dom/src/apiCustomElement.ts
@@ -505,6 +505,8 @@ export class VueElement
       }
       // reflect
       if (shouldReflect) {
+        const ob = this._ob
+        ob && ob.disconnect()
         if (val === true) {
           this.setAttribute(hyphenate(key), '')
         } else if (typeof val === 'string' || typeof val === 'number') {
@@ -512,6 +514,7 @@ export class VueElement
         } else if (!val) {
           this.removeAttribute(hyphenate(key))
         }
+        ob && ob.observe(this, { attributes: true })
       }
     }
   }