@mzebley/mark-down
v1.2.2
Published
mark↓ core runtime and shared utilities
Downloads
545
Readme
mark↓ Core Runtime
(published as @mzebley/mark-down)
This package provides the framework-agnostic SnippetClient and supporting types used to fetch, cache, and render Markdown snippets at runtime. For a monorepo overview visit the root README.
Table of contents
- Installation
- Quick start
- Client options
- Working with snippets
- SSR and custom fetch functions
- Static sites / CDN usage
- Zero-build inline mode
- Testing & type safety
- Related packages
- Roadmap
Installation
Install the runtime alongside your application code:
npm install @mzebley/mark-downYou will also need a manifest file generated by the CLI. See the CLI documentation for steps to build snippets-index.json.
Quick start
import { SnippetClient } from "@mzebley/mark-down";
const client = new SnippetClient({
manifest: "/snippets-index.json",
});
const hero = await client.get("getting-started-welcome");
const components = await client.listByType("component");
console.log(hero.title);The client lazily loads the manifest when first needed, then fetches Markdown files on demand. Results are cached for the lifetime of the client instance.
Client options
SnippetClient accepts a single configuration object:
manifest(string | SnippetMeta[] | () => Promise<SnippetMeta[]>) – where to load the manifest. Provide a URL, an in-memory array, or an async factory.base(string) – optional base path prepended to relative snippet paths. The client infers the directory from the manifest URL when omitted.fetch((url: string) => Promise<Response | string>) – inject a custom fetch implementation. Use this for SSR, testing, or advanced caching.frontMatter(boolean, defaulttrue) – toggle YAML front-matter parsing.cache(boolean, defaulttrue) – enable or disable per-snippet and manifest memoisation.verbose(boolean) – log helpful warnings (for example, slug mismatches) during development.render((markdown: string) => string | Promise<string>) – override the defaultmarkedrenderer when you need custom HTML output.
All options are optional except manifest. Results are rendered with marked by default; override at the application level if you need a different Markdown pipeline.
Working with snippets
Commonly used APIs:
client.get(slug)– fetch a single snippet. ThrowsSnippetNotFoundErrorif the manifest does not include the slug.client.listAll()– return a copy of every manifest entry.client.listByType(type)/client.listByGroup(group)– targeted manifest filters.client.search({ type, group, tags, tagsMode })– multi-field search helper with tag matching.client.getHtml(slug)– convenience wrapper that resolves directly to HTML.client.invalidate()/client.invalidateSlug(slug)– clear caches to force refetching.
Metadata is preserved exactly as declared in front matter. Standard keys (slug, title, etc.) are copied onto SnippetMeta, additional properties live inside extra, and the resolved Snippet includes both rendered HTML and an optional raw Markdown string (without front matter) for advanced use cases.
SSR and custom fetch functions
The runtime runs in browsers, Node.js, or edge runtimes. For server-side rendering:
import fetch from "node-fetch";
import { SnippetClient } from "@mzebley/mark-down";
const client = new SnippetClient({
manifest: () => import("./snippets-index.json"),
fetch: (url) => fetch(url).then((response) => {
if (!response.ok) {
throw new Error(`Request failed with status ${response.status}`);
}
return response;
}),
});You can also pre-seed snippets by passing an array to manifest to avoid network requests entirely. When cache is disabled the client re-fetches both manifest and snippet payloads on every request.
Static sites / CDN usage
Need to run mark↓ inside a plain <script type="module"> context? Use the pre-bundled browser build published at dist/browser.js. It automatically polyfills the minimum Buffer APIs required by the runtime.
<script type="module">
import { SnippetClient } from "https://cdn.jsdelivr.net/npm/@mzebley/mark-down/dist/browser.js";
const client = new SnippetClient({ manifest: "./snippets-index.json" });
const hero = await client.get("marketing-hero");
document.querySelector("#hero").innerHTML = hero.html;
</script>As long as you host snippets-index.json (generated by the CLI) alongside your static assets, this bundle works without any additional tooling or manual Buffer shims.
Zero-build inline mode
Introduction
Need Markdown inside plain HTML without a manifest, build step, or Node runtime? mark↓ ships a lightweight inline helper that scans the DOM for raw Markdown, renders it with the same marked pipeline used by SnippetClient, and progressively enhances the page. Content stays inside the HTML you ship, so crawlers and no-JS users can still read the raw Markdown even before JavaScript runs.
Installation
Install the core package as usual:
npm install @mzebley/mark-downBundlers / ESM: import the inline helper directly.
import { enhanceInlineMarkdown } from "@mzebley/mark-down/inline";Static
<script>usage: include the prebuilt UMD bundle that exposeswindow.markDownInline.<script src="/node_modules/@mzebley/mark-down/dist/mark-down-inline.umd.js"></script> <script> document.addEventListener("DOMContentLoaded", () => { window.markDownInline.enhanceInlineMarkdown(); }); </script>
Host the UMD file yourself or load it from a CDN—no build tooling required.
Basic usage (happy path)
Write plain Markdown directly in your HTML. The helper finds [data-markdown] blocks by default.
<div data-markdown>
# Hello
This is inline markdown with no build step.
</div>
<script src="path/to/mark-down-inline.umd.js"></script>
<script>
document.addEventListener("DOMContentLoaded", function () {
window.markDownInline.enhanceInlineMarkdown();
});
</script>The Markdown text remains in the DOM for SEO while JavaScript enhances it to semantic HTML for users.
Advanced usage (power path with front matter)
You can optionally prepend YAML front matter to provide metadata for each block. Fields are parsed with the same utilities used by the manifest flow.
<div data-markdown>
---
slug: intro
title: Introduction
tags: [hero]
variant: lead
---
# Introduction
This block has metadata.
</div>slug→ setsid="intro"if no ID exists anddata-slug="intro", allowing deep links.title→ stored indata-titlefor TOC/index generation.tags→ serialized todata-tags="hero"(comma-separated when multiple) for light-weight client-side filtering.variant→ adds a class likemd-block--leadso you can theme specific sections.
You still get fully rendered HTML, but additional attributes unlock progressive enhancement such as TOCs or custom styling.
Options
Configure the helper per page:
enhanceInlineMarkdown({
selector?: string; // defaults to "[data-markdown]"
processFrontMatter?: boolean; // defaults to true
applyMetaToDom?: boolean; // defaults to true
});- Use
selectorto target different attributes or classes. - Disable
processFrontMatterwhen the block contains literal---fences that should stay visible. - Set
applyMetaToDomtofalseif you only care about rendered HTML and not DOM metadata.
SEO & progressive enhancement
- Raw Markdown lives directly in your HTML, so crawlers can index the text before scripts execute.
- Users without JavaScript still see readable Markdown; JavaScript simply upgrades it to semantic HTML, adds IDs, and decorates DOM attributes for richer UX.
- This inline mode is ideal for small/medium static pages or marketing sites. Larger doc sites should continue using the manifest-driven snippet system for better caching and composition.
Testing & type safety
- Use
SnippetMetaandSnippetTypeScript types to describe props and state in your application. - Mock the client by providing a manifest array or by stubbing the
fetchoption. - Run the workspace tests with
npm run test -- coreto exercise Vitest suites that cover caching, filtering, and Markdown conversion.
Related packages
- CLI – generate and watch manifests during development.
- Angular adapter – DI-aware provider, service, and component abstractions.
- React adapter – Hooks and components for React and Next.js applications.
Looking for a step-by-step walkthrough? Start from the Quick start guide in the root README.
Roadmap
- Tag-aware helpers – add
listByTagandlistByExtrafilters for common metadata structures. - Prefetch & hydration APIs – expose utilities for bundling snippets with static builds or preloading ahead of navigation.
- Search integration – optional fuzzy search index built from manifest data.
- Cache policies – allow LRU or time-based eviction strategies to better suit long-lived sessions.
