5.7 KiB
docmd Size Strategy Prior
Date: 2026-05-08
Source inspected:
https://github.com/docmd-io/docmd
shallow clone: /tmp/docmd-inspect
commit: 5238e5c9cc5cb87dce37e08ca9f6e1a9a5014b02
Question:
How does docmd accomplish smaller documentation-site payloads?
Short answer:
docmd's smaller payload is mostly an architecture choice, not a novel
compression algorithm.
It avoids a framework runtime, pre-renders Markdown to static HTML, ships a small vanilla JavaScript controller, minifies assets, keeps plugin assets conditional, and fetches heavier data such as search indexes only when needed.
Mechanisms
1. Static HTML Instead of Runtime Rendering
The generator reads Markdown / EJS files at build time, parses them, renders templates, and writes static HTML:
packages/core/src/engine/generator.ts
Relevant implementation shape:
read files in batches
process Markdown through @docmd/parser
render EJS templates
queue HTML writes
write rendered pages in parallel
Size effect:
content is already HTML
browser does not need React / Vue / Docusaurus-style hydration
navigation metadata does not need a large client state tree
2. Small Vanilla SPA Controller
The main client runtime is a hand-written browser script:
packages/ui/assets/js/docmd-main.js
Measured from source checkout:
docmd-main.js raw 25,544 bytes
docmd-main.js gzip 6,646 bytes
It handles:
event delegation
sidebar / TOC toggles
theme toggle
copy-code button
targeted SPA navigation
hover-intent prefetch
partial DOM swap
scroll spy
This is much smaller than shipping a full component runtime and hydration system.
3. Asset Minification With esbuild
Production builds minify copied CSS / JS assets unless config.minify === false:
packages/core/src/engine/assets.ts
Mechanism:
copy UI assets
copy theme assets
copy user assets
copy docs/assets
run esbuild.transform on .css and .js files
strip legal comments
prepend one small copyright banner
This is conventional but effective.
4. Plugin Assets Are Conditional
Plugins declare capabilities and expose assets through hooks:
packages/api/src/hooks.ts
packages/plugins/search/src/index.ts
Core plugins are loaded by default, but users can disable them:
plugins: {
search: false,
mermaid: false,
git: false
}
Size effect:
optional features can be removed without changing the renderer core
feature scripts are separate assets rather than one monolithic app bundle
5. Search Uses a Separate Index
The search plugin generates search-index.json after build:
packages/plugins/search/src/index.ts
Client behavior:
open search modal
fetch search-index.json
load MiniSearch index
render top results
The index is not embedded into every page's HTML. It is a separate fetch.
Hold:
MiniSearch itself is loaded as a CDN script when search is enabled
search is small-ish for content delivery, but not free
disable search for smallest possible initial payload
6. Manifest Instead of Network Probing for i18n
Build emits a tiny page-existence manifest for locales:
assets/js/docmd-i18n-manifest.js
The main script uses it for instant locale page checks instead of doing HEAD
requests for every switch.
Size effect:
small generated manifest replaces repeated network uncertainty
7. Parallelism Improves Build Time, Not Payload
The generator uses:
BATCH_SIZE = 64
WRITE_BATCH_SIZE = 128
This helps build speed:
parallel file reads
batched parse/render loop
parallel template rendering
parallel writes
parallel post-build hooks
But this does not directly make the deployed site smaller.
Local Size Measurements
From source files before production minification:
docmd-main.js raw= 25,544 gzip= 6,646
docmd-image-lightbox.js raw= 2,758 gzip= 1,005
docmd-api.js raw= 5,467 gzip= 1,873
docmd-i18n-strings.js raw= 6,827 gzip= 2,260
docmd-main.css raw= 61,286 gzip= 10,834
search-client.ts raw= 14,668 gzip= 4,553
Interpretation:
the core JS is genuinely small
CSS is the larger always-on local asset
search adds extra cost unless disabled
the README's ~18kb initial payload is plausible for compressed core assets,
but should be verified against a built production site and exact plugin config
Transferable Pattern for Research Stack
For ENE / TiddlyWiki / article surfaces:
pre-render pages or tiddler bundles
ship static HTML first
use a tiny vanilla controller for navigation / toggles
make search an external index, not embedded in every page
make heavy features plugins
emit manifests for routing / locale / existence checks
minify assets after copy
hash every generated asset and index
For compression theory:
docmd is not compressing content in a deep mathematical sense
it is reducing transferred state by choosing a sparse runtime model
This maps well to the local decision-diagram compression frame:
avoid shipping unnecessary branches
materialize only the route needed by the current page
keep optional capabilities as gated leaves
commit indexes and assets separately
Failure Rules
README payload number accepted without built-site measurement -> hold
parallel build described as payload compression -> invalid
plugin system treated as free -> invalid
search index embedded into every page -> avoid
framework-free interpreted as interactivity-free -> false
static HTML treated as non-updatable -> false