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

possg

v0.1.7

Published

A very simple SSG for blog

Readme

possg

日本語

A simple SSG for blogs.

Features

  • import: bring in articles via a zip file or a folder
  • publish / unpublish: toggle an article between draft (staging) and published (content)
  • buildall: bulk-regenerate all articles after a template change
  • Tag feature: automatically generates filtered index pages from an article's frontmatter tags
  • All-articles list in JSON (alllist.json): written directly under staging/content every time the indexes are regenerated
  • Syntax highlighting for code blocks (highlight.js)
  • genviewer: generates HTML that lets you preview an article (zip file or folder) just by dragging and dropping it into the browser
  • geneditor: generates a self-contained article editor with a live preview (can also load an existing article and save back to it in its original format)
  • version: shows the current version of possg / possg-core

Installation (Provisional — Still Under Development)

Still under active development, so things will keep changing!

1. Install possg

npm install -g possg

This makes the possg command available (possg-core is also installed automatically as a dependency).

If the command runs, you're all set:

possg

Usage:
  possg init <target dir>
  possg createroute
  possg import <zip|folder>
  possg publish <key>
  possg unpublish <key>
  possg remove <key>
  possg removeall
  possg buildall
  possg genviewer [-static]
  possg geneditor [-static] [-title <title>]
  possg version

If you want to contribute (working from source)

If you want to try modifying the possg / possg-core code directly, you can use npm link to have your local source referenced directly.

git clone https://github.com/tadfmac/possg-core.git
cd possg-core
npm i
npm link .
cd ..

git clone https://github.com/tadfmac/possg.git
cd possg
npm link possg-core
npm i
npm link .
cd ..

2. Set Up Your Environment

Set up a working directory. Here we'll create one called work as an example.

mkdir work
cd work
possg init .

This generates some of the files you need inside work (config.mjs / template/ / customfunc/ / db/ / examples/, etc.).

3. Edit config.mjs

Configure blog-related settings such as the title. Configure the folder paths where content gets generated, and so on (see possg-core's README for the available settings).

possg createroute

Running this additionally generates the directories configured in config.mjs.

4. Generate .env and Start the Web Server (Optional)

If you want to use possg's built-in web server, do the following extra setup.

The staging root is protected by a basic-auth password. Set this up in .env.

cd possg
touch .env

Save .env with content like this:

BASIC_USER=<username>
BASIC_PASS=<password>

Then start the server with:

cd work
npm i
npm start

possg can also be used as a plain HTML file generator. In that case, host the generated files yourself on any web server that can serve static files, such as httpdocs.

5. Edit the Template

Sample versions of the following files are placed under /template.

  • content-template.ejs — the article page template
  • index-template.ejs — the index page template
  • possg.css — the stylesheet loaded by both templates above (the URL it's loaded from is set via CSS_URL in config.mjs)
  • possg.js — the script that powers the code block's copy button (loaded from the URL set via JS_URL)

Customize these as you like. possg/template/ is the master copy, and it gets copied into each app's template/ at init time (it isn't kept in sync automatically after that, so if you want to change both, you'll need to apply the change manually to each).

6. Import the Sample Article

There's a sample article at /examples/20260126.zip. Let's turn it into HTML.

possg import ./examples/20260126.zip

This creates the article.

import accepts not just zip files but also a folder specified directly, containing index.md and images (you can point it at the unzipped folder as-is).

unzip ./examples/20260126.zip -d ./examples/
possg import ./examples/20260126

7. Check the Sample Article

Try visiting http://localhost:3550/staging/ in your browser. (You'll need to enter the id/pass you set in .env.)

You should see an index page with a link to just the one article.

8. Edit or Add Sample Articles

Unzipping /examples/20260126.zip gives you index.md. Edit it, then either zip it back up or re-import it as a folder, and the article gets rewritten.

You can also copy and rename the folder or zip (for a zip the filename becomes the key, for a folder it's the folder name), edit index.md, and import it to add a different article.

9. Publish / Unpublish an Article

An imported article starts out in draft (staging) state. To publish it:

possg publish 20260126

To un-publish it and move it back to draft:

possg unpublish 20260126

10. Delete an Article

To delete an imported article, just run the command below. To delete the article you imported earlier as 20260126.zip, specify the filename (or folder name) without the .zip, i.e. 20260126.

possg remove 20260126

11. Regenerate Articles After a Template Change

To regenerate the HTML for every imported article — for example after changing a template — run:

possg buildall

Tag Feature

Specifying tags in an article's frontmatter automatically generates an article-list page filtered by that tag.

---
title: Article title
datetime: "20260101 12:00"
tags: ["food", "Yokohama"]
---

To use this, you need a tags schema defined under frontmatter.meta in config.mjs (see config.example.mjs for an example definition). On apps that don't define it, the tag feature itself isn't generated at all.

All-Articles List (alllist.json)

Every time the indexes are regenerated — import, publish, unpublish, remove, buildall, and so on — a JSON list of all articles is written directly under both staging and contents (nothing is written when there are no articles). It's meant for cases where you want the article list without parsing HTML: client-side search, archive pages, and the like.

Each entry holds the article's DB key, every field of frontmatter.core, the frontmatter.meta fields you marked with listup: true, the article URL (link), and its publication state (release).

// config.mjs
"meta": {
  "tags": {
    "type": "array",
    "items": { "type": "string" },
    "required": false,
    "listup": true    // <- include this field in alllist.json
  }
}

alllist.json is generated before the HTML of the index and tag index pages, so an index template can call a method in your customfunc.mjs that reads alllist.json and builds part of the page from it. The index template is handed the absolute path of the alllist.json to read (alllistPath) plus isStaging, telling it whether this is the staging side.

<%- func.renderArchive(alllistPath, isStaging) %>

Note that the whole of customfunc.mjs is embedded into the HTML that genviewer/geneditor generate and runs in the browser as well, so writing import fs from "fs" at the top of that file will break the viewer/editor (see possg-core's README below for how to avoid this).

The filename can be changed via ALLLIST_FILE_NAME in config.mjs (default "alllist.json"). See possg-core's README for details.

Syntax Highlighting

Specify a language on a code block in your article body, and it gets colorized automatically.

```javascript
const hello = () => console.log("hi");
```

Article Preview (genviewer)

If you want to check how a zip file or folder article would render with the real template and styles before actually import-ing it, use genviewer.

possg genviewer

Running this generates viewer.html directly under your working directory. Open it in a browser — double-clicking to open it as file:/// works, and so does hosting it on a web server — and dragging and dropping a zip file or a folder onto it previews the rendered result right there. The "Reload" button reloads whatever changes were made to what you dropped (Chromium-based browsers only). Dropping a folder is especially handy for iterative editing: each "Reload" click re-scans the folder on disk from scratch, so edits to index.md or its images show up right away, with no need to re-zip.

Note: if the template uses Apache SSI (<!--#include virtual="...">), the SSI part is resolved via fetch(), so opening it as file:/// will leave just that part unresolved due to the browser's fetch restrictions (everything else works fine). If you want to fully verify a template that uses SSI, host viewer.html on a web server and access it that way.

If you need a version that works fully under file:////offline even with SSI, use:

possg genviewer -static

This generates a separate viewer-static.html, with SSI content resolved once and baked in at generation time instead of fetched at view time (see possg-core's README for the customfunc.mjs setup this requires, and the trade-off involved).

For how to handle a template that depends on an external CDN library (jQuery, a carousel library, etc.), see possg-core's README (you configure this on the customfunc.mjs side). SSI needs no configuration at all for the regular (non-static) mode, since it's auto-detected.

Article Editor (geneditor)

possg geneditor

Generates editor.html: a self-contained article editor (CodeMirror 6-based) with a live preview, built on the same rendering engine as genviewer. The starting YAML frontmatter is generated from your frontmatter schema instead of a generic template, images you upload or drop show up in the live preview immediately, and you can drag and drop an existing zip/folder article onto it to load it for editing. A "Save As" button lets you pick a destination folder or ZIP file to save to (Chromium-based browsers only); once a save location is set (by loading an existing article or via "Save As"), a "Save" button writes back to that same location. "Download ZIP" is always available as a simple no-picker fallback. The interface defaults to English, with a Japanese option in the gear menu (remembered via localStorage). possg geneditor -static is also available, with the same SSI/file:/// trade-off as genviewer -static; -title <title> overrides the page title/header text. See possg-core's README for details.

Checking the Version

possg version

Shows the current version of possg and possg-core respectively.

LICENSE

MIT