Skip to content

[Feature request] Collections #184

@vralle

Description

@vralle

Feature request

What is motivation or use case for adding/changing the behavior?

Efficient mass generation of homogeneous pages (e.g., gallery albums) from content files with front matter is a common need. At present, each entry typically requires its own template wiring, manual sorting, and manual pagination, which is repetitive, error‑prone, and difficult to scale. A first‑class “collections” facility would automate this flow: point to a content directory, define a data schema, sorting and pagination rules, and obtain fully rendered entry pages plus index pages.

Example album entry in Markdown with front matter:

---
layout: @src/layouts/album.html
title: Album title
description: album description.
image: ./entry-image.png
image_alt: The best entry image
gallery:
  - image: ./image-1.png
    alt: image 1 description
  - image: ./image-2.png
    alt: image 2 description
meta:
  description: Album meta description.
  socialImage: ./album-social-image.png
tags:
  - Cool
  - Easy
  - Fast
publishDate: 2014-08-27 12:50:00
slug: album-1
---

Entry text

Describe the solution you'd like

Add integrated “collections” support to HtmlBundlerPlugin so the plugin can:

  • Scan a content directory and parse front matter from Markdown/HTML.
  • Generate entry pages using the layout declared in front matter.
  • Build collection index pages (with pagination) from a designated template.
  • Provide configurable sorting, pagination, data validation via a schema, and slug generation.
  • Optionally source entries from an external API (e.g., WordPress REST API) instead of local files.

Proposed configuration shape:

new HtmlBundlerPlugin({
  test: /\.html$/i,
  entry: {
   "gallery/index": {
     import: "src/pages/gallery/index.html",
     collection: {
        // Sorting for collection entries
        sort: (entries) => customSorting(entries),
        // Pagination: number per page or a custom function
        pagination: 10, // or (entries) => paginate(entries, { perPage: 10 })
        // Data source and processing rules
        content: {
          test: /\.md$/,
          path: "./src/content/gallery", // path to dir with entry files
          schema: (data) => customDataValidator(data), // e.g., zod
          slug: (entry) => customSlugFunction(entry), // default: derived from filename with limax
          layout: "@src/views/layout/album.html"
      },
      // Template context (illustrative):
      // collections.gallery.entries, collections.gallery.all, page.current, page.total, page.prev, page.next
    },
  },
});

Expected behavior:

  • A page is generated for each discovered entry file, using a path derived from slug (or filename).
  • The gallery index is rendered from the index template, e.g., /gallery/, with pagination at /gallery/page/2, /gallery/page/3, etc.
  • Template context includes:
    • collections.gallery.entries (entries for the current page),
    • collections.gallery.all (all entries, if needed),
    • page (current page number, total pages, prev/next links),
    • all front matter fields (title, image, tags, publishDate, etc.).
  • An external data source option enables static site generation directly from APIs (e.g., WordPress REST API) without intermediary scripts, bringing an experience comparable to Astro’s content collections and pagination.

Illustrative index template:

<!-- ./src/pages/gallery/index.html -->
<ul>
  <% for (const entry of collections.gallery.entries) { %>
    <li>
      <a href="/gallery/<%= entry.slug %>/"><%= entry.title %></a>
      <time datetime="<%= entry.publishDate %>"><%= entry.publishDate %></time>
    </li>
  <% } %>
</ul>

<nav>
  <% if (page.prev) { %><a href="<%= page.prev.href %>">Prev</a><% } %>
  <span>Page <%= page.current %> of <%= page.total %></span>
  <% if (page.next) { %><a href="<%= page.next.href %>">Next</a><% } %>
</nav>

Describe alternatives you've considered

  • Astro content collections with built‑in sorting and pagination; trade‑off: switching from the current Webpack‑based pipeline.
  • Custom scripts/loaders for parsing front matter, route generation, and pagination; trade‑off: bespoke maintenance and weaker integration with HtmlBundlerPlugin.
  • Static site generators (Gatsby/Next SSG/Nuxt/Eleventy); trade‑off: ecosystem change and migration overhead.
  • Manual lists, sorting, and pagination; trade‑off: time‑consuming, error‑prone, and hard to scale.

Appreciation for the useful project

  • After the feature is implemented, do not forget to give a star ⭐

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requesthelp wantedExtra attention is needed

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions