remark-gfm@4.0.1 · lil2 family · @itslil/lil2-remark-gfm

remark-gfm,
flat.

GitHub Flavored Markdown on the flat pipeline: autolink literals, footnotes, strikethrough, tables and task lists, with int token types, construct ids, identifiers and alignments.

npm install @itslil/lil2-remark-gfm
lil2 browser build versus minified upstream · Brotli-11 8.9%smaller

23,016 B upstream (Terser) → 20,971 B lil2

7.7% smallergzip-9 objective build
21.6% smallerraw objective build
0.39× the timeof upstream’s per call, Chromium 151.0.7922.34 (geometric mean)
3/3size cells smaller

Raw, gzip and Brotli each use a separate LilScript compilation targeting that objective; upstream is the smallest of Terser, esbuild and Oxc on the same API bundled for the browser.

A chat app · Playwright · phone CPUs

Streaming chats,
2.5× less CPU.

react-markdown 10.1.0 + remark-gfm, remark-math, rehype-katex → lil2 /full; main-thread time, Chromium 151
short chat (5 replies)average chat (20 replies)long chat (60 replies)
CPU while the replies stream, mid-tier phone (4×)7.1 s → 3.2 s 2.2×29.1 s → 11.5 s 2.5×1.3 min → 31.0 s 2.5×
CPU while the replies stream, low-end phone (6×)11.2 s → 4.7 s 2.4×45.9 s → 17.7 s 2.6×2.0 min → 47.4 s 2.5×
CPU while the replies stream, this machine1.6 s → 0.8 s 2.1×6.8 s → 2.7 s 2.5×17.6 s → 7.0 s 2.5×
updates slower than a frame (16.7 ms), low-end phone (6×)125 → 6 of 1,053671 → 6 of 4,6151,318 → 67 of 12,897
opening the saved chat, low-end phone (6×)417 ms → 317 ms 1.3×843 ms → 519 ms 1.6×1.77 s → 960 ms 1.8×

Measured through lil2-react-markdown, which this package is a layer of. LLM-style replies (lists, code, tables, math; about 2.5 KB each) streamed a few tokens at a time and rendered by React, finished messages memoized. Chrome's CPU throttling stands in for phones (4×: Lighthouse's mid-tier mobile; 6×: DevTools' low-end mobile); median of 2 runs, libraries alternating, fresh tab each. Every streamed update renders the same DOM as react-markdown (test/chat.test.mjs, Chromium and Firefox). Reproduce: npm run bench:chat.

lil2-micromark ✦ lil2-mdast-util-from-markdown ✦ lil2-mdast-util-to-hast ✦ lil2-remark-gfm ✦ lil2-remark-math ✦ lil2-rehype-katex ✦ lil2-remark-breaks ✦ lil2-react-markdown ✦ lil2-react-markdown + gfm ✦ lil2-react-markdown + gfm, math, KaTeX, breaks ✦ lil2-micromark ✦ lil2-mdast-util-from-markdown ✦ lil2-mdast-util-to-hast ✦ lil2-remark-gfm ✦ lil2-remark-math ✦ lil2-rehype-katex ✦ lil2-remark-breaks ✦ lil2-react-markdown ✦ lil2-react-markdown + gfm ✦ lil2-react-markdown + gfm, math, KaTeX, breaks

The lil2 family

This package,
then the stack.

Every layer of the react-markdown stack, rewritten bottom to top with ints for every id and enum and flat arrays for every tree. Each tab is one package: its size against minified upstream for each objective, its speed in real browsers, and the checks that its output equals upstream’s.

lil2-remark-gfm

GitHub Flavored Markdown on the flat pipeline: autolink literals, footnotes, strikethrough, tables and task lists, with int token types, construct ids, identifiers and alignments.

Rewritesremark-gfm@4.0.1 APIfromMarkdown(value, singleTilde) · markdownToHast(value, allowDangerousHtml) BehaviourSame mdast and hast as upstream on 1,453 documents (the whole GFM spec, cmark-gfm’s extension tests, edge cases, the CommonMark corpus), in Node and in Chromium and Firefox. Cells3 of 3 smaller

Both builds, in this page

Live
lab.

Left is markdown. Right is lil2-react-markdown/full rendering it as you type. Race times upstream remark-gfm against lil2 on the current text, both loaded here.

The output is rendered by the shipped browser build; the race runs each side for 400 ms after a warm-up.

Browser build · minified upstream

Three objectives.
Measured separately.

Raw74,981 B

21.6% smaller than original

Terser · 95,678 B
gzip-924,071 B

7.7% smaller than original

Terser · 26,065 B
Brotli-1120,971 B

8.9% smaller than original

Terser · 23,016 B
Current LilScript versus minified original
Compiler objectiveLilScriptOriginal minifiedOriginal minifierDifference
Raw74,981 B95,678 BTerser21.6% smaller
gzip-924,071 B26,065 BTerser7.7% smaller
Brotli-1120,971 B23,016 BTerser8.9% smaller

Each LilScript row comes from a separate compilation targeting that row’s objective. Raw is uncompressed JavaScript; gzip uses level 9; Brotli uses quality 11 and window 22. For each metric, the original is the smallest result among the minifiers below. No JavaScript minifier runs after LilScript.

Every artifact, measured with all three codecs
ArtifactRawgzip-9Brotli-11
LilScript · Raw objective74,981 B25,422 B22,032 B
LilScript · gzip-9 objective76,914 B24,071 B21,051 B
LilScript · Brotli-11 objective77,773 B24,038 B20,971 B
Original · Terser 5.51.295,678 B26,065 B23,016 B
Original · esbuild 0.28.198,155 B28,143 B24,862 B
Original · Oxc vite 8.2.196,112 B26,624 B23,455 B

Browser builds on both sides: lil2’s `browser` condition and upstream bundled by esbuild 0.28.1 with the browser condition (`export {fromMarkdown} from 'mdast-util-from-markdown'; export {gfm} from 'micromark-extension-gfm'; export {gfmFromMarkdown} from 'mdast-util-gfm'; export {toHast} from 'mdast-util-to-hast'`). Upstream: remark-gfm@4.0.1. No external runtime imports. CSS, fonts, type declarations and source maps are outside these JavaScript sizes.

Measurements, hashes and settings ↗ · Commands and build receipts ↗

Real browsers · identical output first

Speed.

Chromium 151.0.7922.34 · median per call, identical output checked first
DocumentUpstreamlil2Time
gfm13.600 ms5.350 ms0.39×
readme22.400 ms8.450 ms0.38×
load (import)5.8 ms6.0 ms1.03×
first call, cold57.0 ms46.2 ms0.81×
Firefox 153.0 · median per call, identical output checked first
DocumentUpstreamlil2Time
gfm27.000 ms12.000 ms0.44×
readme39.000 ms17.000 ms0.44×
load (import)13.0 ms13.0 ms1.00×
first call, cold73.0 ms50.0 ms0.68×

Playwright, one fresh browser context per lane; lanes interleave and alternate order every round. Upstream is the same API bundled from npm for the browser; lil2 is the shipped browser build. Load is the module import after the file is fetched; first call is the first document, cold.

Same machine · sequential builds

Build time.

Build wall time on the same machine
Output objectiveLilScript compilationOriginal bundling + minificationOriginal minifier
Raw18.86 s0.828 sTerser
gzip-918.86 s0.828 sTerser
Brotli-116.45 s0.828 sTerser

One fresh output build per objective and minifier, run sequentially. LilScript compilation includes optimization and objective scoring with persistent caches disabled and one worker. Original time includes Node startup, esbuild bundling of installed upstream ESM, and the named minifier. It excludes building the upstream package from its original TypeScript sources. Dependency installation, tests and final file compression are excluded on both sides. These are observations on a shared machine, not a build-speed guarantee.

AMD EPYC 7763 64-Core Processor · 8 logical CPUs · 15.6 GiB RAM · Linux 7.0.0-1014-azure · Node v20.19.0. Measured 2026-10-04. Exact commands and compiler identity ↗

Install

Typed, flat,
same output.

npm install @itslil/lil2-remark-gfm