packages/lexical-website/docs/extensions/design.md
See also the initial PR #7706
Wherever possible, sensible defaults should be provided and it must be
possible to override them. This is why a Extension has the config property
which specifies the initial configuration.
Almost anything that you do with the editor or a legacy React plug-in should
just work. Upgrading to use a Extension should be a simple change.
Ideally, adding an extension should be two or three lines of code:
TypeScript goes a long way here, but it's only as good as the API design.
For example, splitting up the workflow for an Extension to have separate Config,
Init and Output types was something that evolved over time. In earlier
prototypes, Config was overloaded to maintain all of that state, but it
required a lot more runtime support and type assertions to check that
the state was properly initialized for that phase.
There's only so much that can be done to make readable error messages out of complex type expressions, so the API is designed to avoid them when possible. See also microsoft/TypeScript#23689.
These have many of the same constraints as this project, although of course are used for a very different purpose
This editor is based on Lexical, but provides its own mechanism for plugins based on a third party state management library. These plugins don't really expose any type-safe configuration.
Another Lexical based editor framework for use inside the Payload CMS. It also doesn't really expose type-safe configuration, but it does seem to have quite a lot of features and seems well-designed for laziness and SSR. Features are conceptually similar to Extensions.
This library is pretty much state of the art for type safety with a focus on composition and usability.
This package was originally prototyped as an entirely optional feature, as adoption increases it's expected that more of Lexical will directly depend on it.
The current theory is that it would require too much TypeScript
in order to carry around the list of all dependency names that
exist in the graph, and would likely add another type argument
to LexicalExtension.
The features that this blocks are:
init or register.RectProviderExtension provided by either
LexicalExtensionComposer or ReactPluginHost. An extension can implement this
at runtime in init or register.Generally speaking, all of these are already surfaced as runtime errors while building the editor with sufficient information to quickly track down the root cause.
This is a TODO, the infrastructure was designed with this in mind.
It's not quite clear what all of the use cases for nested Extension editors are, this is a TODO.
Having a known peer dependency that is used to declare SSR may help
guide future Extension development. In many cases there are decorator nodes
that have React dependencies that you do not want to (or can not) render
in an SSR context. For example, RSC can not be supported anywhere that
React.Context is used which is everywhere that React is currently used
in Lexical.
Another option would be to build separate entrypoints for the SSR use case, which is more of an RSC specific strategy, but we could encourage people to use those import conditions even in a Vanilla JS or some other bespoke SSR use case. That strategy may make it hard to support including both "headless" and "non-headless" in the same module.