iOS: inserting any `createReactBlockSpec` block freezes the tab (infinite mutation⇄re-render loop; no `ignoreMutation` seam to fix it)
維護者通常 1 天內回覆
還沒有人認領這個 Issue。
評估
- 難度
- 4/5
- 預估耗時
- 3-5 天
- 新手友好度
- 55/100
- Issue 類型
- 缺陷
- 描述清晰度
- 基本清楚
- 活躍度
- 活躍
- 技術堆疊
- react, typescript
研究方向
Start at createReactBlockSpec and its ReactNodeViewRenderer(component, { className: "bn-react-node-view-renderer" }) call, then inspect how TipTap orders options.ignoreMutation and its mobile branch. Reproduce with touch emulation, a Mac-containing user agent, and a focused custom React block. Done means insertion no longer enters the synchronous mutation/re-render loop while native blocks and the mobile-keyboard behavior remain unaffected.
由索引模型根據 Issue 內容生成。
描述
Summary
On iOS/iPadOS Safari, inserting a custom React block (createReactBlockSpec) into the editor while it is focused locks the main thread in an infinite loop. The tab freezes with no exception and no console output; iOS then kills it. Native blocks (paragraph, quote, heading…) are unaffected.
Verified on @blocknote/[email protected] and still present in the code of 0.54.0 (with @tiptap/[email protected] / 3.30.2).
Mechanism
@tiptap/core's NodeView.ignoreMutation has an iOS/Android branch (added for ueberdosis/tiptap#1971):
if (this.dom.contains(mutation.target) && mutation.type === "childList"
&& (isiOS() || isAndroid()) && this.editor.isFocused) {
const changedNodes = [...mutation.addedNodes, ...mutation.removedNodes];
if (changedNodes.every((node) => node.isContentEditable)) return false; // "do NOT ignore"
}
this.dom is the whole node view, so React mounting the block's own rendered content inside it also matches:
- React mounts the block component inside the node view →
childListmutation, added nodes contentEditable ignoreMutationreturnsfalse→ ProseMirror redraws the node view- React remounts → another
childListmutation → back to 2, forever
The loop is synchronous and reschedules in a microtask (processRootScheduleInMicrotask → flushSyncWorkAcrossRoots_impl → performSyncWorkOnRoot), so the thread never yields. A CPU profile at the freeze is dominated by appendChild/removeChild, ignoreMutation, and the React node-view teardown/rebuild cycle.
Why users can't work around it
TipTap consults this.options.ignoreMutation before the iOS branch — so a per-node-view override would fix it cleanly. But @blocknote/react hardcodes the renderer options:
ReactNodeViewRenderer(component, { className: "bn-react-node-view-renderer" })
createReactBlockSpec exposes no way to pass ignoreMutation through (same gap as ueberdosis/tiptap#1538). The only fix available today is patching @tiptap/core (we ship patch-package narrowing the branch's this.dom to this.contentDOM, which preserves the mobile-keyboard fix the branch exists for while excluding node-view chrome).
Reproduction (no device needed)
TipTap's isiOS() is platform ∈ {iPad, iPhone, iPod, …} || (navigator.userAgent.includes("Mac") && "ontouchend" in document) — so Chrome/Chromium with touch emulation enabled and any Mac-containing UA reproduces it exactly (e.g. CDP Emulation.setTouchEmulationEnabled or DevTools device toolbar):
- Editor with any
createReactBlockSpecblock registered, touch emulation on - Focus the editor, open the slash menu, insert the React block (keyboard Enter suffices — no tap involved)
- Main thread wedges:
1+1in the console never evaluates
Neither viewport width nor the mobile UA matters; touch capability alone flips isiOS()'s second clause. On a real iPhone navigator.platform === "iPhone" makes it unconditional.
Ask
Either:
- forward an
ignoreMutationoption fromcreateReactBlockSpecthrough toReactNodeViewRenderer, or - have BlockNote's renderer supply a default
ignoreMutationthat ignores mutations originating from the React-rendered part of the node view (everything outsidecontentDOM).
Happy to PR either direction if you have a preference. (We're also filing the underlying this.dom vs this.contentDOM question with TipTap, but BlockNote exposing the seam is what lets consumers fix this without vendor patches.)
- 主要語言
- TypeScript
- 星號
- 10.2k
- 分支
- 772
- 平均合併
- 6 天 21 小時
- 30 天內合併 PR
- 26
環境準備
從這裡開始
- 先讀完整個 Issue,再讀專案的貢獻指南。
- 在 Issue 下留言說明你要接手 —— 這能避免兩個人做同樣的事。
- Fork 儲存庫,在一個分支上完成修改。
- 送出 Pull Request,並在描述裡引用這個 Issue 編號。
TypeCellOS/BlockNote 的其他 Issue
-
難度 2/5 1-3 小時 新手友好度 82/100
TypeCellOS/BlockNote#2949 · 1 則留言 ·
維護者通常 1 天內回覆
-
a11y
難度 2/5 1-3 小時 新手友好度 68/100
TypeCellOS/BlockNote#2855 ·
維護者通常 1 天內回覆
-
a11y
難度 2/5 1-3 小時 新手友好度 62/100
TypeCellOS/BlockNote#2829 · 1 則留言 ·
維護者通常 1 天內回覆
-
a11y
難度 2/5 1-3 小時 新手友好度 72/100
TypeCellOS/BlockNote#2824 ·
維護者通常 1 天內回覆
-
a11y
難度 2/5 1-3 小時 新手友好度 68/100
TypeCellOS/BlockNote#2811 ·
維護者通常 1 天內回覆
查看 TypeCellOS/BlockNote 的全部 Issue
相似的 Issue
-
resources
難度 2/5 1-3 小時 新手友好度 72/100
railmapgen/rmg-palette#2445 ·
維護者通常 1 天內回覆
-
難度 2/5 1-3 小時 新手友好度 88/100
danielmiessler/LifeOS#2242 ·
維護者通常 5 天內回覆
-
good first issue hacktoberfest help wanted translation
難度 2/5 1-3 小時 新手友好度 84/100
維護者通常 1 天內回覆
-
難度 2/5 1-3 小時 新手友好度 78/100
callstackincubator/appduct#129 ·
維護者通常 1 天內回覆
-
難度 1/5 1-3 小時 新手友好度 88/100