iOS: inserting any `createReactBlockSpec` block freezes the tab (infinite mutation⇄re-render loop; no `ignoreMutation` seam to fix it)
まだ誰も着手していません。
評価
- 難易度
- 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/react@0.51.4 and still present in the code of 0.54.0 (with @tiptap/core@3.26.1 / 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
- 平均マージ
- 3日 11時間
- マージ済み PR(30日)
- 17
コントリビューションガイド
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
TypeCellOS/BlockNote のほかの issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 84/100
TypeCellOS/BlockNote#3098 ·
-
needs-triage
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
TypeCellOS/BlockNote#3073 ·
-
needs-triage
難易度 2/5 1〜3時間 初心者へのやさしさ 85/100
TypeCellOS/BlockNote#3072 ·
-
難易度 2/5 1〜3時間 初心者へのやさしさ 82/100
TypeCellOS/BlockNote#2949 · コメント 1 件 ·
-
a11y
難易度 2/5 1〜3時間 初心者へのやさしさ 68/100
TypeCellOS/BlockNote#2855 ·
TypeCellOS/BlockNote の issue をすべて見る
似ている issue
-
clawsweeper:fix-shape-clear clawsweeper:queueable-fix clawsweeper:source-repro impact:ux-friction issue-rating: 🦞 diamond lobster no-stale P3
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
-
community first-timers-only good first issue hacktoberfest help wanted low hanging fruit up-for-grabs
難易度 1/5 1時間未満 初心者へのやさしさ 76/100
-
code-quality refactoring
難易度 2/5 1〜3時間 初心者へのやさしさ 84/100
github/gh-aw-firewall#8816 ·
-
integration:quickjs org:external priority:backlog topic:code-interpreter topic:middleware type:feature
難易度 2/5 1〜3時間 初心者へのやさしさ 74/100
langchain-ai/deepagents#6450 ·
-
難易度 1/5 1時間未満 初心者へのやさしさ 88/100
vercel/react-tweet#225 ·