Skip to content

Bundle size — measured, budgeted, reproducible

Measured 2026-07-05 · esbuild bundle+minify, target es2022, charset utf8 · identical method for every library. Reproduce: pnpm size and the snippet at the bottom.

Inkroom

Artifactminifiedgzipbrotli
@inkroom/editor JS (core + markdown engine + full UI + 10 locales)457.9KB138.4KB118.8KB
style.css (both themes, RTL)14.2KB3.4KB

DOMPurify (~9KB gzip), KaTeX, Mermaid and Shiki load as on-demand async chunks — they never sit in the initial payload.

Same method, same day: the alternatives

JS gzipCSS gzipTotal
Inkroom138.4KB3.4KB141.8KB
tui.editor 3.2.2 (what Inkroom replaces)171.9KB106.3KB278.2KB

Headless frameworks (TipTap, Lexical, Slate) are omitted from the table not out of charity but honesty: their number excludes the markdown parser, the toolbar, the dialogs, the table UI and the localization you would still have to ship. A fair comparison is your finished editor against Inkroom — and that number is the one above plus everything you build.

Where the bytes go

ShareComponent
~40%ProseMirror (view, model, transform, tables — the editing engine)
~28%micromark + mdast (a full CommonMark+GFM parser/serializer — the lossless guarantee lives here)
~22%Inkroom core + UI chrome
~5%10 bundled locales
~5%everything else

Budgets (CI-enforced)

  • brotli ≤ 120KB — the plan’s target, met on modern serving (every major CDN)
  • gzip ≤ 145KB — regression guard at today’s measurement +5%
  • CSS gzip ≤ 8KB

Honest note: the original internal target was 120KB gzip. A real CommonMark parser plus a production editing engine plus a complete UI has a floor, and we chose features over the number — then wrote the number down here instead of quietly editing history. Roadmap items that shrink gzip further: per-locale lazy loading (−4KB), viewport-scoped source highlighting.

Reproduce it yourself

import { build } from "esbuild";
import { gzipSync, brotliCompressSync } from "node:zlib";
const r = await build({
stdin: { contents: 'import Editor from "<package>"; console.log(Editor);', resolveDir: "." },
bundle: true, minify: true, format: "esm", target: "es2022", charset: "utf8", write: false,
});
const js = r.outputFiles[0].contents;
console.log((gzipSync(js, { level: 9 }).length / 1024).toFixed(1) + "KB gzip");