npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

metalsmith-simple-pagination

v0.1.0

Published

A simple pagination plugin for Metalsmith that creates paginated directories from a source directory

Readme

metalsmith-simple-pagination

A simple pagination plugin for Metalsmith that creates paginated directories from a source directory of similar files, with pagination metadata compatible with metalsmith-pagination.

metalsmith:plugin npm: version license: MIT coverage ESM/CommonJS Known Vulnerabilities

Features

  • Creates paginated directories from a source directory with a configurable number of files per page
  • Generates clean pagination URLs for both permalink and non-permalink styles
  • Provides pagination metadata compatible with metalsmith-pagination
  • Customizable sorting by any metadata property, including nested properties
  • Preserves all file metadata while adding pagination references
  • Works seamlessly with blog posts and similar collections of files
  • Supports both ESM and CommonJS module formats

Installation

npm install metalsmith-simple-pagination

Usage

This plugin follows the standard Metalsmith plugin pattern and can be used both with ESM and CommonJS.

ESM (preferred)

import metalsmith from 'metalsmith';
import simplePagination from 'metalsmith-simple-pagination';

metalsmith(__dirname)
  .use(
    simplePagination({
      directory: 'blog', // Directory containing files to paginate
      perPage: 10, // Number of posts per page
      sortBy: 'date', // Sort posts by this property (e.g., date or post.date)
      reverse: true, // Sort in descending order (newest first)
      firstIndexFile: 'blog.md', // First page will update metadata of this file
    })
  )
  .build((err) => {
    if (err) throw err;
    console.log('Build complete!');
  });

CommonJS

const metalsmith = require('metalsmith');
const simplePagination = require('metalsmith-simple-pagination');

metalsmith(__dirname)
  .use(
    simplePagination({
      directory: 'blog', // Directory containing files to paginate
      perPage: 10, // Number of posts per page
      sortBy: 'date', // Sort posts by this property (e.g., date or post.date)
      reverse: true, // Sort in descending order (newest first)
      firstIndexFile: 'blog.md', // First page will update metadata of this file
    })
  )
  .build((err) => {
    if (err) throw err;
    console.log('Build complete!');
  });

Options

| Option | Type | Default | Description | | -------------- | ------- | ----------------- | ----------------------------------------------------------- | | directory | String | 'blog' | Directory containing files to paginate | | perPage | Number | 10 | Number of files per page | | sortBy | String | 'date' | Property to sort by (e.g., 'date' or 'post.date') | | reverse | Boolean | true | Whether to reverse the sort order (true = newest first) | | outputDir | String | ':directory/:num' | Directory pattern for output (supports :directory and :num) | | indexLayout | String | 'blog-index.njk' | Layout to use for index pages | | firstIndexFile | String | 'blog.md' | Name of first page file (e.g., 'blog.md') | | usePermalinks | Boolean | true | Whether to use permalinks-style URLs (/blog/ vs /blog.html) |

Examples

Basic Usage

import Metalsmith from 'metalsmith';
import simplePagination from 'metalsmith-simple-pagination';

Metalsmith(__dirname)
  .source('./src')
  .destination('./build')
  .use(simplePagination())
  .build((err) => {
    if (err) throw err;
    console.log('Build complete!');
  });

With Options

import Metalsmith from 'metalsmith';
import simplePagination from 'metalsmith-simple-pagination';

Metalsmith(__dirname)
  .source('./src')
  .destination('./build')
  .use(
    simplePagination({
      directory: 'articles',
      perPage: 5,
      sortBy: 'publishDate',
      reverse: true,
      outputDir: ':directory/page/:num',
      indexLayout: 'article-list.njk',
      firstIndexFile: 'articles.md',
    })
  )
  .build((err) => {
    if (err) throw err;
    console.log('Articles paginated!');
  });

Advanced Usage with Nested Property Sorting

import Metalsmith from 'metalsmith';
import simplePagination from 'metalsmith-simple-pagination';

Metalsmith(__dirname)
  .source('./src')
  .destination('./build')
  .use(
    simplePagination({
      directory: 'posts',
      perPage: 8,
      sortBy: 'post.metadata.publishedAt', // Sort by nested property
      reverse: true,
      outputDir: 'blog/page/:num',
      usePermalinks: false,
      firstIndexFile: 'index.md',
    })
  )
  .build((err) => {
    if (err) throw err;
    console.log('Posts paginated with nested sorting!');
  });

How It Works

This plugin provides a simple way to paginate a collection of files (like blog posts) into separate pages. Here's what it does:

  1. Sources files: Finds all files in the specified directory
  2. Sorts files: Sorts them by the specified property (e.g., date)
  3. Groups files: Creates groups based on the perPage setting
  4. Creates pages: For each group:
    • Creates a new directory following the outputDir pattern
    • Moves the files to this directory
    • Adds pagination metadata
    • Creates an index.html file with the pagination information

First Page Handling

For the first page, the plugin:

  1. Moves the first perPage files to the root of your directory (e.g., /blog/)
  2. Updates the specified firstIndexFile (e.g., blog.md) with pagination metadata

Generated Metadata

Each paginated file will have these additional properties:

  • originalPath: The original file path before pagination
  • pageNumber: The page number this file appears on
  • totalPages: Total number of pages in the pagination

Each page's index file will have this pagination metadata:

{
  pagination: {
    name: 'blog',           // The directory name
    num: 2,                 // Current page number
    pages: 5,               // Total number of pages
    files: [...],           // Array of file metadata for this page
    next: '/blog/3',        // URL to next page (null if last page)
    previous: '/blog',      // URL to previous page (null if first page)
    first: '/blog',         // URL to first page
    last: '/blog/5'         // URL to last page
  },
  pageFiles: [...],         // Same as pagination.files (for backward compatibility)
  date: [Date object],      // Most recent date from files on this page
  layout: 'blog-index.njk', // Layout template for the index page
}

Example Project Structure

Before pagination:

src/
├── blog/
│   ├── etiam-porta-sem-malesuada-magna-mollis-euismod.md
│   ├── curabitur-blandit-empus-porttitor.md
│   ├── cras-mattis-consectetur-purus.md
│   ├── ipsum-cras-ullamcorper-fringilla.md
│   └── duis-mollis-est-non-commodo-uctus.md
└── blog.md  // Index page for the blog

After pagination (with perPage = 2):

build/
├── blog/
│   ├── index.md        // First page with pagination metadata
│   ├── 2/
│   │   └── index.html  // Pagination metadata for page 2
│   ├── 3/
│   │   └── index.html  // Pagination metadata for page 3
│   ├── etiam-porta-sem-malesuada-magna-mollis-euismod/
│   │   └── index.md    // Individual post
│   ├── curabitur-blandit-empus-porttitor/
│   │   └── index.md    // Individual post
│   ├── cras-mattis-consectetur-purus/
│   │   └── index.md    // Individual post
│   ├── ipsum-cras-ullamcorper-fringilla/
│   │   └── index.md    // Individual post
│   └── duis-mollis-est-non-commodo-uctus/
│       └── index.md    // Individual post

At this point the generated index files (2/index.html and 3/index.html)will be empty but their metadata will be populated.

Test Coverage

This plugin maintains high test coverage to ensure reliability. Current test coverage is displayed in the badge at the top of this README.

To run tests locally:

npm test

To view coverage details:

npm run coverage

Debug

This plugin uses Metalsmith's debug functionality. To enable debug logs, set the DEBUG environment variable:

metalsmith.env('DEBUG', 'metalsmith-simple-pagination')

CLI Usage

To use this plugin with the Metalsmith CLI, add it to your metalsmith.json file:

{
  "plugins": {
    "metalsmith-simple-pagination": {
      "directory": "blog",
      "perPage": 10,
      "sortBy": "date",
      "reverse": true,
      "firstIndexFile": "blog.md"
    }
  }
}

License

MIT