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

@nera-static/plugin-one-page

v3.0.1

Published

A plugin for Nera static site generator to merge content from multiple markdown pages into single output pages. Perfect for landing pages and one-page layouts.

Readme

@nera-static/plugin-one-page

Test npm version

A plugin for the Nera static site generator to merge content from multiple markdown pages into a single output page. Ideal for landing pages and long-form content.

✨ Features

  • Merge content from multiple .md files into one HTML page
  • Define content order and anchor IDs per section
  • Auto-generate an anchor from a section's first <h1> when none is given
  • Optional tag and attribute wrappers for each section
  • Configurable via frontmatter and optional config/one-page.yaml
  • No templates to publish and no configuration file required

🚀 Installation

Install the plugin in the root of your Nera project:

npm install @nera-static/plugin-one-page

Nera detects the plugin automatically and applies it during the build. There is nothing to publish and no configuration file to create — the defaults below are used when config/one-page.yaml is absent.

⚙️ Configuration

Frontmatter keys

Set these in the frontmatter of the pages you want to merge into another page:

| Key | Required | Default | Purpose | |---|---|---|---| | add_to_page | yes | — | href of the page to merge this content into | | add_to_page_order | no | 1 | Sort position within the target page | | anchor_id | no | slug of the first <h1> | id of the anchor placed before the section | | content_wrapper_tag | no | section | Element wrapping the section; '' emits no wrapper | | content_wrapper_attributes | no | none | Attributes set on the wrapper element |

add_to_page: /index.html
add_to_page_order: 1
anchor_id: custom-anchor
content_wrapper_tag: section
content_wrapper_attributes:
  - attribute: class
    value: section-class

content_wrapper_attributes may also be written as a plain mapping, which is often shorter:

content_wrapper_attributes:
  class: section-class
  data-role: banner

Attribute values are HTML-escaped, so a value containing quotes cannot break out of the attribute. A value that is neither a list nor a mapping is ignored with a console warning rather than failing the build, and list entries without an attribute key are skipped.

Quote any value containing a colon. value: background-color: red; is invalid YAML — the build logs ❌ Failed to process page and drops that page entirely, exiting 0. Write value: 'background-color: red;'.

add_to_page must match the target's href exactly

The value is compared literally against the target page's meta.href, which Nera builds as a root-relative path with a leading / and an .html extension:

| Source file | href to target | |---|---| | pages/index.md | /index.html | | pages/de/index.md | /de/index.html |

index.html without the leading slash, or a typo, merges nothing. Since v3.0.0 this logs a warning naming the unresolved target; before that it failed silently.

Anchor IDs

When anchor_id is not set, the anchor is derived from the section's first <h1>. Headings below <h1> are ignored, and a section with no <h1> gets no anchor at all.

The slug rule is slugify() from @nera-static/plugin-utils, shared with @nera-static/plugin-tags so tag slugs and anchors agree. It lowercases, expands ß to ss, strips diacritics, replaces every remaining run of non-alphanumerics with a single -, and trims leading and trailing hyphens:

| Heading | Anchor | |---|---| | About Our Company | about-our-company | | Über uns | uber-uns | | Qué hacemos | que-hacemos | | Straße | strasse |

A heading that contains no Latin letters or digits (日本語, !!!) slugifies to nothing, so no anchor is emitted — set anchor_id explicitly for those.

Anchor IDs are a public contract. Visitors bookmark them and your own CSS and scripts select them, so this rule only changes in a major version.

Optional global configuration

Create config/one-page.yaml to rename the frontmatter keys the plugin looks for. The values below are the defaults, so this file is only needed if you want different key names:

property_name: add_to_page
order_property: add_to_page_order
anchor_id_property: anchor_id
content_wrapper_tag_property: content_wrapper_tag
content_wrapper_attributes_property: content_wrapper_attributes

The file is re-read on every build, so changes take effect during npm run dev without restarting.

🧩 Usage

Example directory structure

pages/
├── index.md
├── service.md
├── prices.md
└── about-us.md

Sample frontmatter

index.md — the target page

---
title: Home
layout: layouts/default.pug
---

Welcome to our company.

service.md

---
title: Service
add_to_page: /index.html
add_to_page_order: 1
anchor_id: service-section
---

Content for service

prices.md

---
title: Prices
add_to_page: /index.html
add_to_page_order: 2
anchor_id: prices
content_wrapper_tag: div
content_wrapper_attributes:
  class: price-wrapper
---

Prices content

about-us.md

---
title: About Us
add_to_page: /index.html
add_to_page_order: 3
content_wrapper_attributes:
  style: 'background-color: red;'
---

# About Our Company

About content goes here.

Merged pages still render on their own

This plugin adds content to the target page; it does not remove the source pages. A merged page keeps rendering as its own page if it defines layout in its frontmatter — Nera skips any page without one. The examples above omit layout from service.md, prices.md and about-us.md, which is what makes them merge-only. Add layout if you also want them reachable at their own URL.

📊 Generated Output

Merged sections are appended after the target page's own content, in add_to_page_order order. Markdown is already rendered to HTML before this plugin runs, so section bodies arrive wrapped in <p>, and any heading in the source — including the <h1> an anchor was derived from — is part of the merged content.

Output of /index.html for the example above, verbatim:

<p>Welcome to our company.</p>


<section>
<a id="service-section"></a>
<p>Content for service</p>

</section>

<div class="price-wrapper">
<a id="prices"></a>
<p>Prices content</p>

</div>

<section style="background-color: red;">
<a id="about-our-company"></a>
<h1>About Our Company</h1>
<p>About content goes here.</p>

</section>

🧪 Development

npm install
npx vitest run
npm run lint

npm test starts Vitest in watch mode; use npx vitest run for a single pass. Tests use Vitest and validate:

  • Merging behavior, section order, and placement relative to the target content
  • Anchor ID generation, slugification, and defaults
  • Wrapper tag rendering, attributes, and escaping
  • Config overrides, the missing-config fallback, and malformed input

🤝 Contributing

Issues and pull requests are welcome. See the Nera contributing guide for plugin development, the hook contract, and local setup.

For this repo specifically:

  • npx vitest run and npm run lint must pass (npm test is watch mode).
  • Bump the version and update CHANGELOG.md in the same commit as the change.
  • The anchor IDs and wrapper markup this plugin emits are a public contract — visitors link to the anchors and users style the wrappers from their own CSS, so changing what either produces is a major bump.
  • Releases publish from CI on a pushed v* tag. Never run npm publish.

🧑‍💻 Author

Michael Becker
https://github.com/seebaermichi

🔗 Links

🧩 Compatibility

  • Nera: v4.1.0+ — a baseline, not a requirement. This plugin uses no generator feature above the 4.x line and ships no templates, so there is no Pug basedir dependency and nothing that needs v4.2.0 or v4.3.0.
  • Node.js: >= 20.18.1 — required by cheerio, this plugin's runtime dependency
  • Plugin Utils: ^1.4.0 — getConfig() and slugify(), which is the shared implementation of the anchor slug rule below
  • Plugin API: exports getMetaData(), which rewrites page content

📦 License

MIT