Skip to content

@lexical/utils -> registerNodesOfType#4099

Closed
zurfyx wants to merge 2 commits intomainfrom
register-nodes-of-type
Closed

@lexical/utils -> registerNodesOfType#4099
zurfyx wants to merge 2 commits intomainfrom
register-nodes-of-type

Conversation

@zurfyx
Copy link
Copy Markdown
Member

@zurfyx zurfyx commented Mar 10, 2023

$nodesOfType is an expensive function, it iterates all the tree. It turns out that people are abusing this function as a handy shortcut (as we have no better utility) which can have performance implications on long documents.

There's two types of misuse:

  1. For updates; people find it easier to use $nodesOfType than building more optimal tailored algorithm (via transform parent or making some hierarchy assumption).
  2. For reads; $nodesOfType is much easier to use than registerMutationListener when tracking nodes as a whole as the mutation listener requires you to build your own data storage, do the first pass and handle creation and deletion.

This PR addresses the second, simplifies the whole mechanism and makes it easier to fall onto the pit of success

  1. Forgetting the initial pass can cause a race condition
  2. Slightly similar but this is a common race condition that has previously given us trouble with the contenteditable flag
const nodes = $nodesOfType(FooNode);
useEffect(() => {
  return editor.registerNodeMutation(..);
  1. Tracking is verbose

Internal utilization reference https://fburl.com/diff/prwdmjw5

@facebook-github-bot facebook-github-bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Mar 10, 2023
@vercel
Copy link
Copy Markdown

vercel bot commented Mar 10, 2023

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated
lexical ✅ Ready (Inspect) Visit Preview 💬 Add your feedback Mar 10, 2023 at 11:43PM (UTC)
lexical-playground ✅ Ready (Inspect) Visit Preview 💬 Add your feedback Mar 10, 2023 at 11:43PM (UTC)

@github-actions
Copy link
Copy Markdown

size-limit report 📦

Path Size Loading time (3g) Running time (snapdragon) Total time
packages/lexical/dist/Lexical.js 26.85 KB (0%) 538 ms (0%) 153 ms (-1.96% 🔽) 690 ms
packages/lexical-rich-text/dist/LexicalRichText.js 37.79 KB (+0.3% 🔺) 756 ms (+0.3% 🔺) 92 ms (+8.78% 🔺) 848 ms
packages/lexical-plain-text/dist/LexicalPlainText.js 37.77 KB (+0.31% 🔺) 756 ms (+0.31% 🔺) 135 ms (+62.84% 🔺) 891 ms

return x.nodeType === 1;
}

export function registerNodesOfTypeListener(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like the idea, not sure about the name. Perhaps we can think of something better - let me dwell on it a bit.

Other thing - it's a bit weird to have this be the only listener not accessed through a LexicalEditor instance. Not a blocker, just calling out the inconsistency. Maybe it's fine because this is, in a sense, a "higher order" listener.

Copy link
Copy Markdown
Member Author

@zurfyx zurfyx Mar 11, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Other thing - it's a bit weird to have this be the only listener not accessed through a LexicalEditor instance

That's a fair point. My thinking process was that the Core is already pretty bloated. IMO MutationListeners is an advanced topic and something that only power users need. But no strong opinions on this

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm good with this - can you add a doc block at the top of the function? See examples in the recent docs PRs

}
}
if (newNodes !== null) {
nodes = newNodes;
Copy link
Copy Markdown
Collaborator

@fantactuka fantactuka Mar 14, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I understand why we reassign nodes here and whether it's needed at all. This var does not seem to be used as we only trigger listener with nodes of type that were added (newNodes)

Also, curious if users would expect this listener to be triggered with all nodes of type vs just newly added ones.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, fair point, I guess part of the behavior you inherit from the nodesOfType name but it makes sense that this is not what you would often expect from an observer. I guess that alternatively we can have a callback that returns (added: Set<NodeKey>, removed: Set<NodeKey>, nodes: Set<NodeKey>)

@thegreatercurve
Copy link
Copy Markdown
Contributor

@zurfyx Can this PR be merged? Or can you mark it as 0.12.0 if we want to introduce this as a breaking change?

@etrepum
Copy link
Copy Markdown
Collaborator

etrepum commented Aug 4, 2024

I think we might be able to abandon this, since #6357 basically covers the same use case and there's a cache for $nodesOfType such that the traversal of all nodes is only done once per read-only EditorState (via the internal getCachedTypeToNodeMap).

@potatowagon potatowagon added the stale-pr PRs that are closed due to staleness. Please reopen the PR if there are new updates label Oct 24, 2024
@github-actions
Copy link
Copy Markdown

Closing this PR due to staleness! If there are new updates, please reopen the PR.

@github-actions github-actions bot closed this Oct 24, 2024
@zurfyx zurfyx deleted the register-nodes-of-type branch February 28, 2025 18:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. stale-pr PRs that are closed due to staleness. Please reopen the PR if there are new updates

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants