Skip to content

v0.51.0 - #9178

Merged
etrepum merged 1 commit into
mainfrom
0.51.0__release
Sep 17, 2026
Merged

v0.51.0#9178
etrepum merged 1 commit into
mainfrom
0.51.0__release

Conversation

@etrepum

@etrepum etrepum commented Sep 17, 2026

Copy link
Copy Markdown
Collaborator

v0.51.0 is a monthly release with one large new feature: nodes can now declare their JSON serialization as a schema on $config. This declarative schema is faster, safer, and more flexible than the hand-written methods. The metadata it provides enables a compact export option with all default values elided, the code generator that provides faster import and export for every node that lexical ships, a new @lexical/fast-check package for property-based tests, and it provides a path to future features that rely on knowing the structure of the nodes (e.g. additional codecs and dev tools).

This is a big step towards Lexical 1.0, the next few releases are expected to be focused on moving everything (including docs and examples) to the latest Extension and $config APIs and removing deprecated functionality. Two related changes in this release are that we are publishing ESM-only to npm now (cjs builds are still supported in the source tree), and LexicalComposer is deprecated for LexicalExtensionComposer. Expect anything @deprecated to be removed soon.

Breaking Changes

  • npm packages are ESM only. Every package declares "type": "module" and its exports map offers development / production / default conditions with no require branch; the CommonJS build remains in-tree only for Meta's www. Bundlers are unaffected. CommonJS code can require() the packages on Node.js 20.19+ (the builds have no top-level await), and older Node.js must use await import(...) — but a dependency the app also loads through require() can then exist twice, which breaks handing its objects to Lexical (yjs docs to @lexical/yjs, @preact/signals-core signals from @lexical/extension), so load those as ESM too. Metro bundles both builds unless you add the condition for Lexical's packages; see the module formats FAQ (#9127)
  • lexicalexportJSON may serialize the instance as-is. A property declared with withField is read straight off the node instead of through its accessor, so exportJSON no longer resolves getLatest() for you and a stale reference can write stale values (and a property whose accessor a subclass overrode still resolves, so one object can mix the two). Nothing inside Lexical is affected — the walk, the clipboard selection export and editorState.toJSON() all start from the node map — but call getLatest() yourself on a reference you kept across a mutation (#8602)
  • @lexical/code — the deprecated Prism re-exports are gone, along with the @lexical/code-prism dependency (so Prism no longer lands in a bundle that only imports @lexical/code). Import CODE_LANGUAGE_FRIENDLY_NAME_MAP, CODE_LANGUAGE_MAP, getCodeLanguageOptions, getCodeLanguages, getCodeThemeOptions, getLanguageFriendlyName, normalizeCodeLanguage (formerly also normalizeCodeLang), PrismTokenizer and registerCodeHighlighting from @lexical/code-prism (#9141)

Deprecations

  • @lexical/reactLexicalComposer is deprecated in favor of LexicalExtensionComposer and is expected to be removed in a future major. LexicalComposer cannot accept extensions, so any feature shipped as one is unreachable from an editor it builds; the migration is usually a two-line change (#9168, React extensions guide)

New APIs & Features

  • lexicalDeclarative serialization schemas (experimental). A node that uses $config declares its serialized properties once in the new json property, and that single declaration drives importJSON, updateFromJSON and exportJSON: nodeSchema, withField / withAccessors, and the value combinators (stringValue, numberValue, booleanValue, enumValue, arrayValue, objectValue, unionValue, rawValue, transformValue, nullable, optional, …). Every built-in node declares one, and most custom nodes now need no JSON serialization code at all. Output is unchanged by default (#8602, serialization docs).
  • lexicalCompact JSON export, opt-in via editorState.toJSON(true) or $withCompactExport(true, cb) (with $isCompactExport() for schema getters, plus $exportNodeJSON and the CompactSerializedEditorState / ParsableSerializedEditorState / LexicalParseJSON / SerializedPartial types). It omits properties equal to their schema default, properties the parser derives, and the deprecated version. The raw objects are well under half the legacy size — which matters for structured clones and worker messages — but after gzip the two are a wash. Both forms parse back to the same document; only a Lexical new enough to know the schemas can read the compact one, so keep writing the legacy form until every reader is upgraded (#8602)
  • @lexical/compilerGenerated serialization code. Every built-in node class ships straight-line serialization generated from its own schema at build time, producing byte-identical JSON to the schema-driven path that continues to serve custom nodes (#8602)
  • @lexical/fast-check — New package deriving fast-check arbitraries from those schemas: nodeArbitrary(NodeClass) generates exactly the serialized JSON a node's parser accepts, each property independently present or absent. Useful for the bugs fixtures hide, such as a property afterCloneFrom forgot to copy. fast-check is a peer dependency; getComposedSchemaFields in core inspects a class's schema without generating anything (#8602)
  • @lexical/extension — Published as subpath exports, one entry per extension (@lexical/extension/AutoFocusExtension, …), with compiler and lint enforcement of the source import convention. The barrel import is unchanged, and shared modules such as signals keep a single instance (#9161). This is primarily only useful as a consumer if you are not using tree-shaking.

Notable Fixes

Bundling, tree-shaking & types

  • A production import of only createCommand no longer retains the editor (#9121), and the remaining module-scope side effects that defeated tree-shaking are gone, with a bare-import residue check now run over every entry (#9124); extension editors build under loose-mode transpilation (#9134)
  • Flow: defineExtension was uncallable, making the extension types unusable (#9132); declarations can now express an extension with dependencies (#9176); modern variance keywords survive into the www stubs (#9154)

Selection & editing

  • No redundant selection-change command on Safari link selection (#9163); TextNode.setMode, setTextContent and isSimpleText read the latest state (#9162); $removeTextFromCaretRange no longer leaves a childless list or table as the root's only child (#9116); a text entity keeps the style and detail of the text it replaces (#9130); selection overlay listeners are notified when rectangles are removed (#9117)

Lists, tables & Markdown

  • Indenting between two nested lists no longer converts the second list's type (#9118); $mergeCells no longer keeps the empty paragraph of the target cell (#9122); text left outside a Markdown link keeps its format (#9131)

Playground & docs

  • Card/Review CSS placeholders are cleared reliably on paste in Safari (#9129) and releasing a CardNode drag no longer selects the node (#9135); new docs on Lexical being a singleton per app, and why a library must declare it as a peer dependency (#9125)

Plus the usual dependency updates across the rollup, shikijs, vitest, docusaurus/typedoc and flow/hermes groups.

What's Changed

New Contributors

Full Changelog: v0.50.0...v0.51.0

@vercel

vercel Bot commented Sep 17, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
lexical Ready Ready Preview Sep 17, 2026 3:31pm UTC
lexical-playground Ready Ready Preview Sep 17, 2026 3:31pm UTC

Request Review

@meta-cla meta-cla 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 Sep 17, 2026
@etrepum etrepum added the extended-tests Run extended e2e tests on a PR label Sep 17, 2026
@etrepum
etrepum marked this pull request as ready for review September 17, 2026 15:32
@etrepum
etrepum added this pull request to the merge queue Sep 17, 2026
Merged via the queue into main with commit c9aea68 Sep 17, 2026
55 checks passed
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. extended-tests Run extended e2e tests on a PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants