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

linkrel-ssg

v0.1.1

Published

A static site generator based on HTML includes.

Readme

linkrel-ssg

A static site generator based on HTML includes:

<link rel="include" href="./path/to/include.html">

Motivation

I've been writing websites for two decades, and yet to find anything that improves on the ergonomics of PHP. That doesn't mean I want to use PHP, but it does mean I'm reluctant to use anything that's significantly more complex to install or use.

I'd also like to generate static sites when possible, as this ensures stable, performant sites. But I have been dissatisfied with the assumptions built into other static site generators.

After two decades without a good low-abstraction tool, I wrote something that:

  • Is explicit rather than implicit.
    • No magic. All output is generated from explicit code in the source tree.
  • Reuses existing technologies (e.g. DOM parsing and semantics) as much as possible.
  • Uses composition over inheritance.
    • It should be easy to reuse templates but also simple to build a page with arbitrary contents and functionality.
  • Allows writing performant pages.
    • In particular, it should be easy to inline critical code (e.g. CSS that avoids a flash of unstyled content) but also to load shared code when that makes sense.

Features are built on semantic HTML that can be written like normal using your editor's HTML language features. In particular, the core functionality is provided by HTML includes, which are a very useful idea but are not coming to the web any time soon. In order to use something idiomatic and reasonably future-proof[^1], we use <link rel="include" …>.

Usage

import { Builder } from "linkrel-ssg"

const builder = new Builder({
  srcRoot: "./src/garron.net/",
  outputDir: "./dist/web/garron.net/"
});

// Build once
await builder.build();

// Watch for changes and serve locally
await builder.serve();

Includes

To include part of an HTML page with a fragment, use a <link> as follows:

<link rel="include" href="./relative/path/to/file.fragment">

This can be used both:

  • in the <head>, and
  • in the <body>.

Note that:

  • You can inline CSS by including a <style> tag in the fragment.

Note that these includes currently:

  • Are each inlined as a fragment, replacing the <link> tags that included it.
  • Are recursively evaluated. Each <link>'s href attribute is resolved relative to the file it appears in.
  • Do not accept any parameters. (To affect the styling of included content, use CSS.)
  • Do not support any kind of customization or interpolation.

Markdown

To render a section of Markdown, use a <pre> tag as follows:

<pre data-transform="markdown">
## This is is a [Markdown](https://commonmark.org/) header.
</pre>

Markdown may contain nested HTML (which is valid Markdown), but it will be round-tripped through the Markdown parser. Make sure that top-level HTML elements in the Markdown source are unindented. For example, this will probably do what you want:

<pre data-transform="markdown">
Here is some code:
<p><code>console.log("Hello world!");</code></p>
</pre>

By contrast, if you indent all the contents of <pre>, then all the contents will be interpreted as a big code block:

<pre data-transform="markdown">
    This line and the following line's source code will be displayed together on the rendered page.
    <p><code>console.log("Hello world!");</code></p>
</pre>

Nested HTML inside Markdown may itself contain nested Markdown, and so on (arbitrarily nested).

Substitute tags

Sometimes tags (e.g. <title>) can have special parsing semantics and must be represented as another tag for HTML child elements to be parsed. To process a tag as a generic element and then change its tag name at the end, use <substitute-tag>:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <substitute-tag data-tag="title">
      Home | <link rel="include" href="../.common.ssg/head/site-name.fragment">
    </substitute-tag>
  </head>
</html>

Non-features

For now:

  • No theming. (Bring your own, via CSS. Consider minimal-html-style.)
  • No automatic collation/indexing/blog management.
  • No automatic reload in dev.
  • No source code highlighting for code snippets.

Performance

Performance is currently poor. This is because linkrel-ssg is purely implemented in browserless JS using jsdom. This has an unfortunate amount of overhead, but avoids the cost of extra abstractions.

I'd love to do a rewrite in Rust at some point, but probably not until I need it for sufficient performance on my own website.