mdbook-content-loader 0.1.4

Injects content-collections.json into mdBook pages as a global variable
Documentation

mdbook-content-loader

Zero-runtime-fetch content collections for mdBook

Injects your content-collections.json (generated by mdbook-content-collections) directly into every HTML page as window.CONTENT_COLLECTIONSno network request, no path hacks, works offline.

By default, the data is injected on your landing page (index.md), which is usually where your “Latest posts” or home layout lives. You can optionally enable the old behavior and inject it on every page via a config flag.

This gives you true Astro/Zola-style content collections inside mdBook: instant, reliable access to posts, blog entries, notes, changelogs — anywhere in your theme.


Why this exists (and why you want it)

The original mdbook-content-collections example used fetch('content-collections.json') in the browser.

That works… until it doesn’t:

Problem With fetch() With mdbook-content-loader
Extra HTTP request Yes No
Broken in file:// / offline mode Yes Works perfectly
Fragile URL construction Yes No path logic needed
Flash of empty content Yes Instant
Fails silently on 404 Yes Build fails early
Works on GitHub Pages / custom domains Sometimes Always

This crate fixes all of that — permanently.


What you get

A single global, available immediately on every page:

<script>
  window.CONTENT_COLLECTIONS = { ...ready to use... }
</script>
window.CONTENT_COLLECTIONS = {
  entries: [
    /* all published posts, sorted newest first */
  ],
  collections: {
    posts: [
      /* fallback collection */
    ],
    blog: [
      /* frontmatter: collection: blog */
    ],
    notes: [
      /* ... */
    ],
    // ... any collection name you use
  },
  generated_at: "2025-11-28T10:00:00Z",
};

Each entry has the full shape from mdbook-content-collections:

{
  path: "blog/my-post.md",
  title: "My Great Post",
  date: "2025-11-27T00:00:00Z",
  author?: string,
  description?: string,
  collection?: string,
  tags: string[],
  draft: false,
  preview_html: "<p>First paragraph <strong>rendered</strong>...</p>"
}
  • Drafts are filtered out automatically

  • Everything is sorted newest -> oldest

  • No runtime parsing, fetching, or error handling needed

Installation

cargo install mdbook-content-loader
# If not installed, install mdbook-content-collections
# cargo install mdbook-content-collections

Setup

Add the following to your book.toml:

[preprocessor.content-collections]
# Generates content-collections.json

[preprocessor.content-loader]
command = "mdbook-content-loader"
after = ["content-collections"]   # make sure JSON is generated first

# Behavior:
# - default: inject window.CONTENT_COLLECTIONS only into index.md
# - set inject_all = true to inject into every chapter
# inject_all = true

The after key ensures the JSON exists before this loader runs, and inject_all is an optional boolean that restores the old “every page” behavior. mdBook exposes this table under [preprocessor.content-loader] to the preprocessor via PreprocessorContext, which is where this flag is read.

Usage in your theme

Drop this anywhere in theme/index.hbs (or any .hbs file):

<div id="latest-posts"></div>

<script>
  if (!window.CONTENT_COLLECTIONS) {
    console.warn("mdbook-content-loader: data not loaded");
  } else {
    const posts =
      window.CONTENT_COLLECTIONS.collections.blog ||
      window.CONTENT_COLLECTIONS.collections.posts ||
      [];

    const list = document.getElementById("latest-posts");
    const ul = document.createElement("ul");

    posts.slice(0, 5).forEach((post) => {
      const li = document.createElement("li");
      li.innerHTML = `
        <h3><a href="$$ {post.path.replace(/\.md $$/, '.html')}">${post.title}</a></h3>
        ${post.date ? `<time>${new Date(post.date).toISOString().slice(0, 10)}</time>` : ""}
        <div class="preview">${post.preview_html}</div>
      `;
      ul.appendChild(li);
    });

    list.appendChild(ul);
  }
</script>

Want a sidebar? Tag cloud? Search index? Related posts? Just read from window.CONTENT_COLLECTIONS.

Common patterns

// Latest 5 blog posts
window.CONTENT_COLLECTIONS.collections.blog?.slice(0, 5);

// All posts (any collection)
window.CONTENT_COLLECTIONS.entries;

// Posts with tag "rust"
window.CONTENT_COLLECTIONS.entries.filter((p) => p.tags.includes("rust"));

Data Shape

Same as mdbook-content-collections, plus:

  • collections: grouped + sorted by collection name

  • generated_at: when the data was build

  • All draft: true entries removed

See: mdbook-content-collections

License

Apache 2.0