Back to Lexical

Mdast Editor (dev example)

dev-examples/mdast-editor/README.md

0.47.04.4 KB
Original Source

Mdast Editor (dev example)

A WYSIWYG Markdown editor with an editable Markdown source pane (synchronized in both directions, exercising import and export), built on the unreleased @lexical/mdast package — the micromark/mdast-based alternative to @lexical/markdown. It is a port of examples/markdown-editor, which is the same app built on the legacy bespoke implementation; comparing the two shows what the extension-first design removes.

bash
pnpm run start:dev-example mdast-editor

Because this example depends on unreleased workspace packages, the StackBlitz link opens the monorepo root and boots the example with the start:dev-example:mdast-editor script.

Deployed builds of every dev example are served from the lexical website at /dev-examples/<name>/ (this one at /dev-examples/mdast-editor/), including on every Cloudflare/Vercel deploy preview. To build them locally: pnpm run build && pnpm run build:dev-examples at the monorepo root, which outputs into packages/lexical-website/static/dev-examples/. These are built from the development artifacts on purpose — they are demos, and the development builds keep Lexical's full error messages.

What got simpler vs. examples/markdown-editor

The legacy example's MarkdownExtension.ts is ~240 lines; the equivalent MdastEditorExtension.ts here is example plumbing only (the preview signal and two toolbar commands), because @lexical/mdast ships extension-ready:

  • No transformer list to curate. Depending on MdastShortcutsExtension pulls in the CommonMark + GFM grammar and every node it needs.
  • No registerMarkdownShortcuts call. The extension registers the streaming shortcuts itself, driven by the same micromark grammar as document import.
  • No checklist workaround. The legacy example needed a custom text-match transformer (CHECK_LIST_ITEM, ~50 lines) so [ ] typed in an existing bullet item would convert; that behavior is built in.
  • No newline-handling configuration. shouldPreserveNewlines / mergeAdjacentNewlines don't exist; micromark parses CommonMark as-is and the original syntax is preserved on the nodes via NodeState.

It also does more: blockquotes, links, strikethrough, thematic breaks, and fenced code blocks round-trip out of the box (the legacy example's default set covered headings, lists, and inline formatting), and the code blocks are syntax-highlighted by adding CodeShikiExtension — highlighting composes with the Markdown machinery without any extra wiring.

Bundle size

The flip side of parsing with micromark is bundle weight. Build the production dist artifacts first, then run the comparison:

bash
pnpm run build-prod   # at the monorepo root
npm run size          # in this directory

It builds functionally-equivalent headless bundles — editor + markdown node set + typing shortcuts + import/export — one per implementation, from the production dist artifacts, and prints their sizes. All include the lexical core, so the deltas are the markdown machinery itself. Snapshot at the time of writing:

bundleminifiedmin+gzip
legacy @lexical/markdown287.3 kB77.3 kB
@lexical/mdast408.6 kB103.6 kB
@lexical/mdast (import only)393.5 kB99.9 kB
delta (full vs legacy)+121.4 kB+26.3 kB

Two packaging decisions keep the delta down:

  • The dist build keeps the micromark/mdast dependencies external, so the app bundler resolves them with browser export conditions (named character references decode through the DOM instead of shipping a ~36 kB entity table) and tree-shakes what's unused.
  • Import and export are separate extensions; the import-only row omits MdastExportExtension and with it most of mdast-util-to-markdown.

That ~26 kB (gzip) buys spec-compliant CommonMark + GFM parsing, a single grammar shared by import and typing shortcuts, and the micromark/mdast extension ecosystem (footnotes, frontmatter, directives, ...) as the path for new syntax.