docs/solutions/performance-issues/2026-04-04-mark-bundle-tax-comes-from-inactive-leaf-and-text-renderer-fan-out.md
The standalone editor benchmark exposed a red 10k bold lane even after the
earlier cheap-mark fast paths.
The deceptive part was that the mounted DOM was already basically the same as Slate:
10,000 <strong> nodes30,000 leaf nodes30,000 string nodes90,000 <span> nodesSo the extra runtime was not a "Plate mounts more DOM" story.
Current standalone rows on the rich benchmark lab:
86_mount-10k-bold-basic: Plate 585.90 ms, Slate 375.90 ms90_mount-10k-bold-single: Plate 424.50 ms, Slate 343.20 ms94_mount-10k-bold-direct: Plate 406.00 ms, Slate 333.90 msThat split says:
strikethrough alone before proving the shared mark path.Key the shared mark render pipes by active mark instead of visiting every mark renderer on every leaf/text node.
Kept cuts:
pluginRenderLeaf(...)Targeted regression coverage:
The new tests prove inactive leaf/text renderers are skipped instead of being invoked and returning the original children.
Before the cut:
pipeRenderLeaf(...) still walked every leaf renderer for every leafpipeRenderText(...) still walked every text renderer for every text nodeOn a 10k bold-only fixture, that means the basic mark bundle was paying for a
pile of irrelevant sibling mark work on every node even though only bold was
active.
After the cut, the cost splits cleanly:
The second kept cut moved those rows again:
48_mount-10k-marks-basic: about 1387 ms -> 1310 ms86_mount-10k-bold-basic: about 673 ms -> 597 ms90_mount-10k-bold-single: about 439 ms -> 428 msThe next kept cut stayed in the same shared pipes, but fixed a subtler bill:
That keeps plain leaves cheap while still removing the per-render
Object.keys(...).flatMap(...).sort(...) churn on marked leaves.
Focused reruns on the kept hybrid path landed here:
48_mount-10k-marks-basic: Plate 1244.70 ms, Slate 903.00 ms86_mount-10k-bold-basic: Plate 557.20 ms, Slate 335.60 ms90_mount-10k-bold-single: Plate 399.90 ms, Slate 342.50 ms91_mount-10k-italic-single: Plate 388.30 ms, Slate 349.90 ms93_mount-10k-strikethrough-single: Plate 439.80 ms, Slate 339.60 msWidening the decomposition to the remaining special marks showed that no single plugin was secretly causing the whole remaining wall:
98_mount-10k-code-basic: Plate 418.70 ms, Slate 387.00 ms100_mount-10k-subscript-basic: Plate 410.90 ms, Slate 382.80 ms102_mount-10k-superscript-basic: Plate 395.30 ms, Slate 384.20 msSo the remaining marks-basic lane is mostly the aggregate cost of many marked
leaves in the same workload, not one hidden special-mark disaster.
That gives a clean optimization order: