You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A deep-dive into how Analog can achieve world-class markdown rendering performance by adopting native parsers, streaming architectures, and modern component-driven authoring formats.
Status Update (Mar 25, 2026)
This proposal has materially advanced on alpha over the last two weeks.
Merged into alpha: PR #2156 (experimental md4x renderer pipeline) and PR #2157 (content DevTools panel) are no longer speculative; they landed on alpha on Mar 23 and are included in the v3.0.0-alpha.15 line.
Supporting foundations also merged: PR #2148 (schema validation), PR #2149 (typed server primitives), PR #2150 (Shiki/platform cleanup), PR #2144 (Vite+OXC library pipeline), PR #2141 (Nitro dev rebuild watcher), PR #2138 (artifact leak fix), PR #2125 (typed file routes + JSON-LD + Standard Schema), and PR #2176 (typed route path utilities and validation error handling).
Alpha has broadened beyond content alone: the branch also absorbed Nitro v3/h3 v2, Vite 8/Rolldown alignment, Tailwind v4+, Vite+Rolldown-based Angular library builds, cross-platform build fixes, and Dagger-backed CI. That matters because md4x is now landing into a platform that already modernized its build, routing, and validation story.
The remaining gap is narrower now: the meaningful unfinished work is not “can md4x fit into Analog?” but “how do we wire the last facade/default behaviors and validate parity confidently enough to flip the default?”
Table of Contents
Current State: Analog's Content Pipeline
The Performance Gap
md4x: The Native C Parser That Changes Everything
astro-md4x: Proof That Drop-In Native Parsing Works
MDC (Markdown Components): The Authoring Future
Streaming & LLM-Ready Rendering
Architecture Proposal: analog-md4x
Other Tools Worth Watching
Benchmark Targets
Migration Strategy
Addendum: Additional Features and DX Opportunities
1. Current State: Analog's Content Pipeline
Analog's content system follows a marked-based, build-time discovery, lazy runtime loading architecture:
Follow-up validation/path handling work tightens the typed routing surface that content features can plug into
Key insight: The ContentRenderer abstract class (packages/content/src/lib/content-renderer.ts) is already a clean interface with render(content) returning { content, toc }. A new Md4xContentRendererService can be added without modifying any existing code. The file loading pipeline (CONTENT_FILE_LOADER, contentFileResource) is fully renderer-agnostic. None of the PRs above are blockers for the md4x work — they are helpful but independent.
Already Implemented on alpha
The following have been built, merged, and are already part of the current alpha branch:
Floating panel showing parse time, renderer name, TOC, content stats
10 new tests, all @experimental
What's Remaining
No merged analog() facade integration yet — content.renderer: 'md4x' is still not wired into the platform plugin
No MDX support — can't embed Angular components via JSX syntax (MDC is the alternative path)
No AST access exposed to consumers — md4x's parseAST() is used internally but not yet surfaced as a public API
No cross-build persistence caching — transform cache exists but no disk persistence between builds
No dual-render CI parity validation — marked vs md4x output comparison script not yet built
2. The Performance Gap
The difference between JavaScript-based markdown parsers and native implementations is staggering:
JS markdown pipeline vs md4x (C/NAPI)
Operation
JS pipeline
md4x (NAPI)
Speedup
Simple render
~8.2K ops/s
~443K ops/s
54x
Complex document
~670 ops/s
~49K ops/s
73x
Frontmatter parse
~4.5K ops/s
~155K ops/s
34x
Processor init
~1.8M ops/s
~11.8M ops/s
6.5x
(Benchmarks from astro-md4x comparing @astrojs/markdown-remark (remark/unified-based JS pipeline) vs md4x. Direct marked-vs-md4x benchmarks would differ but the order of magnitude is representative.)
md4x vs markdown-it
Operation
markdown-it
md4x (NAPI)
md4x (WASM)
Medium render
21.41 µs
3.32 µs
5.76 µs
Speedup
baseline
6.4x
3.7x
For a content-heavy Analog site with 500+ markdown files, this translates from multi-second builds to sub-second builds for the markdown phase alone.
3. md4x: The Native C Parser That Changes Everything
unjs/md4x is the most compelling advancement in the markdown tooling space. Built on mity/md4c (a C99 CommonMark parser), compiled with Zig, and distributed as both NAPI and WASM binaries.
This maps perfectly to Analog's hybrid SSR/CSR architecture.
2. Multiple Output Formats
import{renderToHtml,parseAST,parseMeta}from'md4x/napi';consthtml=renderToHtml(markdown);// HTML stringconstast=parseAST(markdown);// ComarkTree (traversable)constmeta=parseMeta(markdown);// { frontmatter, headings }
Each call is a separate native parse (not a single shared parse), but they are all fast enough that calling both renderToHtml + parseMeta is still dramatically cheaper than a single marked.parse().
3. Efficient Parsing Architecture
The underlying md4c parser uses a callback-driven approach rather than building a full intermediate AST in C. md4x wraps this with JS-level allocations for the output, so memory usage is not truly constant, but it is significantly lower than pure-JS parsers for large documents.
4. Built-In MDC (Comark) Support
::alert{type="warning"}
This is a warning with **bold** text.
#title
Custom Title
::
Native component syntax support — no plugins, no overhead.
5. Built-In Frontmatter (via libyaml)
No separate front-matter or gray-matter dependency. YAML parsing happens at the C level.
6. Markdown Healing for LLM Streams
import{heal}from'md4x/napi';// Fixes incomplete markdown from streaming AI outputheal('**bold text without closing');// → '**bold text without closing**'// Or render with healing in one passrenderToHtml(partial,{heal: true});
7. GFM + Extensions Out of the Box
Tables, task lists, strikethrough, alerts, LaTeX math, wiki links, underline, inline attributes — all native, zero plugin overhead.
4. astro-md4x: Proof That Drop-In Native Parsing Works
pi0/astro-md4x demonstrates that replacing a framework's entire markdown pipeline with md4x is viable and produces dramatic results:
API compatible: Same createMarkdownProcessor() interface
50-70x faster rendering with a single native dependency
GitHub-slugger compatible heading IDs
Lessons for Analog
Compatibility layer works — md4x can sit behind an existing API surface
Incremental adoption — start with build-time rendering, expand to runtime
Feature gaps are manageable — syntax highlighting and remark/rehype plugins are the main gaps, both solvable
5. MDC (Markdown Components): The Authoring Future
MDC (Markdown Components) — implemented in md4x under the name Comark — is a compelling authoring advancement over MDX. While MDX requires JSX knowledge and a full compiler pipeline, MDC extends standard markdown syntax with component capabilities.
MDC vs MDX vs Plain Markdown
Feature
Markdown
MDX
MDC
Learning curve
Low
High (JSX)
Low (markdown-native)
Component support
None
Full JSX
Block + inline components
Props
N/A
JSX attributes
{key="value"} syntax
Slots
N/A
Children
Named #slot syntax
Parser complexity
Low
Very high (needs SWC/Babel)
Moderate
Build perf
Fast
Slow (JS transpilation)
Fast (native in md4x)
Framework coupling
None
React-heavy
Framework-agnostic
MDC Syntax Examples
Block Components:
::card{icon="rocket" title="Performance"}
md4x renders markdown **73x faster** than traditional JS parsers.
#footer
Built with native C and distributed as WASM.
::
Inline Components:
Press the :button[Submit]{color="primary"} button to continue.
Nested Components:
::grid{cols=2}
:::card
Left column content
:::
:::card
Right column content
:::
::
Why MDC is Perfect for Angular/Analog
No JSX transpilation — keeps the build pipeline simple
Template-friendly — MDC's attribute syntax maps cleanly to Angular inputs
Progressive — valid markdown with or without component rendering
Native in md4x — zero plugin overhead for parsing
6. Streaming & LLM-Ready Rendering
The heal() function in md4x opens up a class of features that no JS parser currently offers:
Real-Time AI Content Rendering
// In an Analog API route or server actionimport{renderToHtml,heal}from'md4x/napi';exportdefaultdefineEventHandler(async(event)=>{conststream=awaitcallLLM(prompt);returnnewReadableStream({asyncstart(controller){letbuffer='';forawait(constchunkofstream){buffer+=chunk;consthtml=renderToHtml(buffer,{heal: true});controller.enqueue(html);}controller.close();},});});
Healing Performance
Input Size
md4x (NAPI)
remend (JS)
Speedup
Small
703 ns
3.71 µs
5.3x
Medium
4.14 µs
47.8 µs
11.5x
Large
95.1 µs
10.95 ms
115x
7. Architecture Proposal: analog-md4x
Phase 1: Build-Time Native Parsing
Replace marked with md4x/napi for all build-time markdown processing.
tinyglobby (discover files)
→ md4x/napi parseMeta() (frontmatter + headings in one pass)
→ md4x/napi renderToHtml() (markdown → HTML)
→ Shiki (syntax highlighting via custom highlighter hook)
→ Angular DI tokens
Impact: 50-70x faster content builds. Zero API changes for users.
Phase 2: Runtime WASM Rendering
For CSR/lazy-loaded content, ship md4x/wasm (~100KB gzip) instead of marked (~40KB).
// Already implemented in PR #2156 as Md4xWasmContentRendererServiceprovideContent(withMd4xWasmRenderer());
Impact: 3-6x faster client-side rendering. The ~100KB WASM binary replaces marked + all its plugins.
Phase 3: MDC Component Bridge
Map MDC AST nodes to Angular components at render time.
The md4x AST output for ::alert{type="warning"} produces structured JSON nodes (["alert", { "type": "warning" }, ...]) that the MdcRendererDirective walks and maps to Angular component instantiation — no JSX compiler needed.
Phase 4: Streaming Content
Leverage heal() for:
AI-generated content pages — render as tokens arrive
Collaborative editing — live preview of incomplete markdown
Progressive SSR — stream HTML chunks as markdown sections are parsed
Alerts, containers, KaTeX, tabs, task lists, and more. 100% test coverage.
9. Benchmark Targets
What "amazing" looks like for Analog's content pipeline:
Build-Time Goals (estimated, not benchmarked against Analog specifically)
Metric
Estimated (marked)
Target (md4x)
Expected improvement
100 files parse + render
~150ms
~3ms
~50x
500 files parse + render
~750ms
~15ms
~50x
Frontmatter extraction (500 files)
~110ms
~3ms
~35x
TOC generation (500 files)
separate pass
included in parse
2x (eliminated)
Cold processor init
~550ns
~85ns
~6.5x
These estimates are extrapolated from the astro-md4x benchmarks and md4x's published per-document numbers. Actual Analog performance should be measured after integration.
Runtime Goals (CSR, estimated)
Metric
Estimated (marked)
Target (md4x/wasm)
Expected improvement
Single page render
~120µs
~20µs
~6x
Bundle size (parser)
~40KB + plugins
~100KB (all-in-one)
parity*
First render (cold)
parse + highlight
cached HTML via TransferState
0ms (hydration)
*md4x WASM is larger but replaces marked + front-matter + marked-gfm-heading-id + marked-highlight, netting roughly equivalent total size with more capability.
These PRs provide complementary infrastructure. The md4x renderer (PR #2156) was built independently, but alpha now already includes the surrounding pieces needed for the next stage:
Step 1: Add md4x as an Alternative Renderer (Non-Breaking) — DONE (PR #2156)
The ContentRenderer abstract class was already a clean interface. Md4xContentRendererService and Md4xWasmContentRendererService implement it without modifying any existing code.
provideContent(withMd4xRenderer());// NAPI (server)provideContent(withMd4xWasmRenderer());// WASM (browser)provideContent(withMd4xRenderer({heal: true}));// with streaming healprovideContent(withMd4xRenderer({highlighter: fn}));// with Shiki hook
md4x/napi for build-time, md4x/wasm for runtime — both implemented
marked remains default — md4x is opt-in via provider swap
withMdcComponents() and MdcRendererDirective are implemented. The directive walks md4x's ComarkTree, matches component names to the registry, and instantiates Angular components via ViewContainerRef.createComponent().
streamMarkdown() is implemented. It works standalone with any ReadableStream<string> input:
// In a Nitro API route (h3)import{streamMarkdown}from'@analogjs/content';exportdefaultdefineEventHandler(async(event)=>{constllmStream=getAIStream(event);returnstreamMarkdown(llmStream,{heal: true});});
With PR #2149 merged, streamMarkdown can also be used inside defineServerRoute handlers for typed server-side streaming.
Step 4: Default to md4x
After validation across the ecosystem, make md4x the default renderer and deprecate the marked path. The main prerequisites that still need explicit follow-through are platform facade wiring and dual-render parity validation.
Summary
The path to "amazing" markdown rendering in Analog is clearer now than when this issue was opened. Phase 1-3 are built and merged, and several adjacent router/platform pieces also landed on alpha:
analog() facade integration — wire content.renderer: 'md4x' into the platform plugin so users don't need to touch provideContent() directly
Dual-render CI validation — build tools/scripts/validate-md4x-parity.mts to compare marked vs md4x output across all workspace markdown files
Exploit the newly merged routing stack — connect md4x content flows more directly with the typed file-route / JSON-LD / server-route work now on alpha
Content Collections — schema-per-directory with build-time validation (StandardSchema + md4x)
Default to md4x — after CI parity validation passes, switch the default renderer
The combination of md4x's native performance, MDC's elegant component syntax, and Analog's Angular-powered rendering still creates an opportunity to build the fastest, most developer-friendly content pipeline in the meta-framework space. The important difference now is that much of the enabling work is already merged on alpha, so the roadmap is no longer hypothetical; it is mostly about finishing integration, parity validation, and a safe default switch.
11. Addendum: Additional Features and DX Opportunities
Added after analyzing the merged alpha work and the recent pull requests that landed around it.
Content Collections with Per-Collection Schemas
StandardSchema validation (PR #2148) + md4x = validated, typed, blazing-fast content collections. Define a schema per collection directory and fail the build when any file has invalid frontmatter — the Analog equivalent of Astro's content collections.
Now that PR #2148 is merged, md4x's native libyaml frontmatter output can feed into the parseRawContentFileAsync(raw, schema) pipeline. The schema validates at C-speed parsing + JS-speed validation, which is the optimal split.
Incremental Content Builds
md4x's SAX-style parsing + the dev-server file watcher from PR #2141 = only re-parse changed files. The Nitro rebuild watcher already watches src/server/ for changes; extending it to src/content/ would trigger md4x re-renders for only the modified files instead of the full content directory.
Combined with Nx's task caching (already configured for content builds), this could achieve sub-100ms incremental content rebuilds for sites with thousands of markdown files.
Dual-Render CI Validation
Before switching the default renderer from marked to md4x, run both in CI and diff the HTML output:
This provides confidence to maintainers that the switch is safe, and catches edge cases in GFM extensions, heading ID generation, or HTML entity handling before users hit them.
The basic bridge is implemented: MdcRendererDirective walks the md4x ComarkTree, matches component names to the MDC_COMPONENTS registry, and instantiates Angular components via ViewContainerRef.createComponent() with MDC attributes bound as inputs via setInput().
::product-card{id="42" featured=true}
Check out this product!
::
Future enhancement: The current implementation binds attributes as strings via setInput(). A future iteration could use Angular's input() signal metadata to coerce types (e.g., featured=true → boolean) and validate required inputs at render time.
On the client, an Angular component consumes the SSE stream and renders the healed HTML in real-time. This enables:
AI blog post drafting with instant preview
Documentation generation from code comments
Content translation with streaming side-by-side comparison
The heal() performance (703ns for small inputs, 4.14µs for medium) is fast enough for 60fps rendering of streaming content.
Edge-Rendered Content with md4x/WASM
md4x's WASM build (~100KB gzip) runs in Cloudflare Workers, Deno Deploy, and Vercel Edge Functions — environments without Node.js native module support. This enables:
Content-at-the-edge — render markdown to HTML at the CDN edge, eliminating origin round-trips for content pages
Dynamic content personalization — render different markdown variants per user segment at the edge
Preview deployments — render draft content in edge functions without a full Node.js server
Combined with Analog's existing Nitro presets for Cloudflare and Vercel, this is a natural extension of the deployment story.
Markdown Language Server Protocol (LSP) Integration
md4x's AST output enables building a markdown LSP that understands Analog's content conventions:
Frontmatter autocomplete — driven by the StandardSchema definitions from content collections
MDC component completion — suggest registered components from withMdcComponents()
Route link validation — verify [link](/blog/post) targets exist in the file-based routes
Live error squiggles — frontmatter validation errors appear inline in the editor
This would work as a VS Code extension or any LSP-compatible editor, using the same schema definitions that validate at build time.
Content Caching with ETag-Based Invalidation
md4x's deterministic rendering (same input = same output, always) enables aggressive HTTP caching. Since md4x doesn't expose a hash function, a standard Node.js hash (e.g., crypto.createHash('sha256')) on the raw markdown provides an ETag:
Status Update (Mar 25, 2026)
This proposal has materially advanced on
alphaover the last two weeks.alpha: PR #2156 (experimental md4x renderer pipeline) and PR #2157 (content DevTools panel) are no longer speculative; they landed onalphaon Mar 23 and are included in thev3.0.0-alpha.15line.Table of Contents
1. Current State: Analog's Content Pipeline
Analog's content system follows a marked-based, build-time discovery, lazy runtime loading architecture:
Current Stack
Related Merged PRs on
alphaSeveral recently merged PRs now provide infrastructure that is useful (though not strictly required) for the md4x integration:
Key insight: The
ContentRendererabstract class (packages/content/src/lib/content-renderer.ts) is already a clean interface withrender(content)returning{ content, toc }. A newMd4xContentRendererServicecan be added without modifying any existing code. The file loading pipeline (CONTENT_FILE_LOADER,contentFileResource) is fully renderer-agnostic. None of the PRs above are blockers for the md4x work — they are helpful but independent.Already Implemented on
alphaThe following have been built, merged, and are already part of the current
alphabranch:feat(content): add experimental md4x content rendering pipelinewithMd4xRenderer()— NAPI renderer (50-70x faster, server/build-time)withMd4xWasmRenderer()— WASM renderer (~100KB, 3-6x faster, browser/CSR)withMdcComponents()+MdcRendererDirective— MDC component bridge for AngularstreamMarkdown()— streaming markdown-to-HTML withheal()for AI content@experimentalfeat(content): add experimental content DevTools browser panelcontentDevToolsPlugin()— Vite plugin, dev-onlyDevToolsContentRenderer+withContentDevTools()— instrumented renderer wrapper@experimentalWhat's Remaining
analog()facade integration yet —content.renderer: 'md4x'is still not wired into the platform pluginparseAST()is used internally but not yet surfaced as a public API2. The Performance Gap
The difference between JavaScript-based markdown parsers and native implementations is staggering:
JS markdown pipeline vs md4x (C/NAPI)
(Benchmarks from astro-md4x comparing
@astrojs/markdown-remark(remark/unified-based JS pipeline) vs md4x. Direct marked-vs-md4x benchmarks would differ but the order of magnitude is representative.)md4x vs markdown-it
For a content-heavy Analog site with 500+ markdown files, this translates from multi-second builds to sub-second builds for the markdown phase alone.
3. md4x: The Native C Parser That Changes Everything
unjs/md4x is the most compelling advancement in the markdown tooling space. Built on mity/md4c (a C99 CommonMark parser), compiled with Zig, and distributed as both NAPI and WASM binaries.
Why md4x Matters for Analog
1. Dual Runtime Strategy
This maps perfectly to Analog's hybrid SSR/CSR architecture.
2. Multiple Output Formats
Each call is a separate native parse (not a single shared parse), but they are all fast enough that calling both
renderToHtml+parseMetais still dramatically cheaper than a singlemarked.parse().3. Efficient Parsing Architecture
The underlying md4c parser uses a callback-driven approach rather than building a full intermediate AST in C. md4x wraps this with JS-level allocations for the output, so memory usage is not truly constant, but it is significantly lower than pure-JS parsers for large documents.
4. Built-In MDC (Comark) Support
Native component syntax support — no plugins, no overhead.
5. Built-In Frontmatter (via libyaml)
No separate
front-matterorgray-matterdependency. YAML parsing happens at the C level.6. Markdown Healing for LLM Streams
7. GFM + Extensions Out of the Box
Tables, task lists, strikethrough, alerts, LaTeX math, wiki links, underline, inline attributes — all native, zero plugin overhead.
4. astro-md4x: Proof That Drop-In Native Parsing Works
pi0/astro-md4x demonstrates that replacing a framework's entire markdown pipeline with md4x is viable and produces dramatic results:
"@astrojs/markdown-remark": "npm:astromd4x@latest"createMarkdownProcessor()interfaceLessons for Analog
5. MDC (Markdown Components): The Authoring Future
MDC (Markdown Components) — implemented in md4x under the name Comark — is a compelling authoring advancement over MDX. While MDX requires JSX knowledge and a full compiler pipeline, MDC extends standard markdown syntax with component capabilities.
MDC vs MDX vs Plain Markdown
MDC Syntax Examples
Block Components:
Inline Components:
Nested Components:
Why MDC is Perfect for Angular/Analog
6. Streaming & LLM-Ready Rendering
The
heal()function in md4x opens up a class of features that no JS parser currently offers:Real-Time AI Content Rendering
Healing Performance
7. Architecture Proposal: analog-md4x
Phase 1: Build-Time Native Parsing
Replace
markedwithmd4x/napifor all build-time markdown processing.Impact: 50-70x faster content builds. Zero API changes for users.
Phase 2: Runtime WASM Rendering
For CSR/lazy-loaded content, ship
md4x/wasm(~100KB gzip) instead ofmarked(~40KB).Impact: 3-6x faster client-side rendering. The ~100KB WASM binary replaces marked + all its plugins.
Phase 3: MDC Component Bridge
Map MDC AST nodes to Angular components at render time.
The md4x AST output for
::alert{type="warning"}produces structured JSON nodes (["alert", { "type": "warning" }, ...]) that theMdcRendererDirectivewalks and maps to Angular component instantiation — no JSX compiler needed.Phase 4: Streaming Content
Leverage
heal()for:8. Other Tools Worth Watching
Native/High-Performance Parsers
Syntax Highlighting
Content Authoring Frameworks
Component-in-Markdown Solutions
Markdown-it Plugin Ecosystem
9. Benchmark Targets
What "amazing" looks like for Analog's content pipeline:
Build-Time Goals (estimated, not benchmarked against Analog specifically)
These estimates are extrapolated from the astro-md4x benchmarks and md4x's published per-document numbers. Actual Analog performance should be measured after integration.
Runtime Goals (CSR, estimated)
*md4x WASM is larger but replaces marked + front-matter + marked-gfm-heading-id + marked-highlight, netting roughly equivalent total size with more capability.
DX Goals
10. Migration Strategy
Recently Merged Supporting Work
These PRs provide complementary infrastructure. The md4x renderer (PR #2156) was built independently, but
alphanow already includes the surrounding pieces needed for the next stage:Step 1: Add md4x as an Alternative Renderer (Non-Breaking) — DONE (PR #2156)
The
ContentRendererabstract class was already a clean interface.Md4xContentRendererServiceandMd4xWasmContentRendererServiceimplement it without modifying any existing code.Step 2: MDC Component Registration — DONE (PR #2156)
withMdcComponents()andMdcRendererDirectiveare implemented. The directive walks md4x'sComarkTree, matches component names to the registry, and instantiates Angular components viaViewContainerRef.createComponent().11 tests covering HTML elements, registered components, unregistered fallback, null/empty AST, attributes, and no-registry scenarios.
Step 3: Streaming Content API — DONE (PR #2156)
streamMarkdown()is implemented. It works standalone with anyReadableStream<string>input:With PR #2149 merged,
streamMarkdowncan also be used insidedefineServerRoutehandlers for typed server-side streaming.Step 4: Default to md4x
After validation across the ecosystem, make md4x the default renderer and deprecate the marked path. The main prerequisites that still need explicit follow-through are platform facade wiring and dual-render parity validation.
Summary
The path to "amazing" markdown rendering in Analog is clearer now than when this issue was opened. Phase 1-3 are built and merged, and several adjacent router/platform pieces also landed on
alpha:What's next:
analog()facade integration — wirecontent.renderer: 'md4x'into the platform plugin so users don't need to touchprovideContent()directlytools/scripts/validate-md4x-parity.mtsto compare marked vs md4x output across all workspace markdown filesalphaThe combination of md4x's native performance, MDC's elegant component syntax, and Analog's Angular-powered rendering still creates an opportunity to build the fastest, most developer-friendly content pipeline in the meta-framework space. The important difference now is that much of the enabling work is already merged on
alpha, so the roadmap is no longer hypothetical; it is mostly about finishing integration, parity validation, and a safe default switch.11. Addendum: Additional Features and DX Opportunities
Content Collections with Per-Collection Schemas
StandardSchema validation (PR #2148) + md4x = validated, typed, blazing-fast content collections. Define a schema per collection directory and fail the build when any file has invalid frontmatter — the Analog equivalent of Astro's content collections.
Now that PR #2148 is merged, md4x's native libyaml frontmatter output can feed into the
parseRawContentFileAsync(raw, schema)pipeline. The schema validates at C-speed parsing + JS-speed validation, which is the optimal split.Incremental Content Builds
md4x's SAX-style parsing + the dev-server file watcher from PR #2141 = only re-parse changed files. The Nitro rebuild watcher already watches
src/server/for changes; extending it tosrc/content/would trigger md4x re-renders for only the modified files instead of the full content directory.Combined with Nx's task caching (already configured for content builds), this could achieve sub-100ms incremental content rebuilds for sites with thousands of markdown files.
Dual-Render CI Validation
Before switching the default renderer from marked to md4x, run both in CI and diff the HTML output:
This provides confidence to maintainers that the switch is safe, and catches edge cases in GFM extensions, heading ID generation, or HTML entity handling before users hit them.
MDC-to-Angular Component Bridge with Signal-Based Props — Partially DONE (PR #2156)
The basic bridge is implemented:
MdcRendererDirectivewalks the md4xComarkTree, matches component names to theMDC_COMPONENTSregistry, and instantiates Angular components viaViewContainerRef.createComponent()with MDC attributes bound as inputs viasetInput().Maps to:
Future enhancement: The current implementation binds attributes as strings via
setInput(). A future iteration could use Angular'sinput()signal metadata to coerce types (e.g.,featured=true→boolean) and validate required inputs at render time.Content DevTools (Browser Panel) — DONE (PR #2157)
Implemented as
contentDevToolsPlugin()(Vite plugin,apply: 'serve'only) +DevToolsContentRenderer(instrumented wrapper) +withContentDevTools()provider. Currently shows:Future enhancements for the DevTools panel (not yet built):
AI Content Authoring with Live Preview
Combine md4x's
heal()function with the server actions from PR #2149 and the SSE infrastructure demonstrated in the analog-app demo:On the client, an Angular component consumes the SSE stream and renders the healed HTML in real-time. This enables:
The
heal()performance (703ns for small inputs, 4.14µs for medium) is fast enough for 60fps rendering of streaming content.Edge-Rendered Content with md4x/WASM
md4x's WASM build (~100KB gzip) runs in Cloudflare Workers, Deno Deploy, and Vercel Edge Functions — environments without Node.js native module support. This enables:
Combined with Analog's existing Nitro presets for Cloudflare and Vercel, this is a natural extension of the deployment story.
Markdown Language Server Protocol (LSP) Integration
md4x's AST output enables building a markdown LSP that understands Analog's content conventions:
withMdcComponents()[link](/blog/post)targets exist in the file-based routesThis would work as a VS Code extension or any LSP-compatible editor, using the same schema definitions that validate at build time.
Content Caching with ETag-Based Invalidation
md4x's deterministic rendering (same input = same output, always) enables aggressive HTTP caching. Since md4x doesn't expose a hash function, a standard Node.js hash (e.g.,
crypto.createHash('sha256')) on the raw markdown provides an ETag: