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 🙏

© 2024 – Pkg Stats / Ryan Hefner

wunphile

v1.0.2-b

Published

Simple, imperative JavaScript-based static site generator

Downloads

72

Readme

Wunphile

Simple, imperative JavaScript-based static site generator, compatible with Node.js, Deno (2.0+), and Bun.

About

Wunphile (pronounced "one file") allows you to build your site as if it was an Express-like app, but generate a nice, static bundle.

Below is what a simple blog site might look like:

import config from './config.js'

import { Wunphile, html } from 'wunphile'
import { getAllBlogPosts } from './util/blog.js'

import IndexPage from './component/page/IndexPage.js'
import BlogPostPage from './component/page/BlogPostPage.js'

const ssg = new Wunphile(import.meta.url)

// We use the `page` to register components for pages.
ssg.page('/index.html', IndexPage)

// Components are simply functions that return HTML using the "html" template function.
// Similarly to React, strings interpolated into the template function will be sanitized.
// The "html" template function takes in a template string and returns React-style RenderFragments.
// No JSX needed!
ssg.page('/test.html', () => html`<h1>Hello from ${config.siteName}!</h1>`)

// We can write any logic we want to drive site generation.
// The "getAllBlogPosts" function could be reading markdown files from a directory,
// pulling from a database, or even fetching data from an API.
for (const post of await getAllBlogPosts()) {
    ssg.page(`/blog/${post.slug}/index.html`, () => new BlogPostPage(post))
}

// We mount static files from a local "assets" directory to the "/static" path.
// So if there is a file named "logo.png" in the "assets" directory, it will be served at "/static/logo.png".
ssg.staticDir('/static', './assets')

// We can also mount individual static files.
// The line below will mount the local file "./metadata-files/favicon.ico" to the "/favicon.ico" path.
ssg.staticFile('/favicon.ico', './metadata-files/favicon.ico')

// Runs the site generator CLI.
// The CLI can build the site or serve it on a local HTTP server for development.
await ssg.cli()

The above code will look very familiar to anyone who has used Express or a similar imperative-style web framework. Paths are mapped to functions that return HTML, static directories are mounted, etc.

Unlike backend frameworks, however, Wunphile generates all the HTML and files at build time. It writes everything to an output directory, ready to be served by a traditional webserver such as Nginx or Caddy.

Its goal is to live up to the following qualities:

Simple

Unlike a framework such as Astro or Next.js, this library does not perform any magic or postprocessing on the HTML. Instead, it simply acts as a wrapper around your own logic that handles all the filesystem operations for you and provides an abstraction for paths, components and static files. Because it does not do any postprocessing, what you write is what you get, even down to whitespace and indentation.

Since it does not perform any transformations on input, it does not rely on a build system or transpiler. This means that it can avoid the weight and headache of a core dependency on a tool like Webpack. Sites made with this library are likely to work many years down the road due to it using almost entirely standard JavaScript APIs, along with a handful of Node.js APIs for interacting with the filesystem.

Pure JavaScript

This library consists of a single pure JavaScript file, and building1 has no dependencies other than Node.js APIs. Instead of using JSX, it takes advantage of the JavaScript template literal syntax to provide a simple, safe API for writing HTML.

While it is not written in TypeScript, the library is fully typed and documented using JSDoc.

Because it is written in JavaScript, it can be used in any non-browser environment, including Deno (2.0+) and Bun. In fact, due to it only being a single file with no external build dependencies, it can be used in projects without even needing a package manager!

1 While building has no external dependencies, development mode has some minimal dependencies to handle MIME resolution and filesystem watching.

Static

Instead of trying to be a full-stack framework, this library is designed only with static site generation in mind. It is not a framework for building web apps, and does not provide any dynamic routing or middleware.

More complicated frontend integration is out of the scope of this library, but there is nothing stopping developers from using it as a basis for a framework that does provide such features.

Development Mode and Hot Reloading

When the cli method is called with the --dev or -d option, a development server will be started.

The development server will watch the project root directory for changes and hot reload the site when changes are detected.

While in development mode, the site will not be built and the filesystem will not be touched. Instead, the site will be served from an embedded HTTP server.

Whenever the site is hot reloaded, pages open in the browser will be automatically reloaded through a small script injected into pages in development mode. This can be disabled by setting the SSG_DEV_NO_INJECT environment variable to 1.

To disable hot reloading entirely, set the SSG_DEV_NO_HOT_RELOAD environment variable to 1.

Note that whenever the site is hot reloaded, the main module will be re-run in a worker thread. This means that the main module should not contain any extra code besides what is necessary to build the site.

Installation

Note that the development mode CLI is not available in this case, because required dependencies for it are not included.

Note that your project must support ESM (ES2022 modules) to import the library.

CLI Usage

If your project calls the cli method, it will act as a CLI for building and serving the site.

If run with no arguments, it will build the site.

If run with --dev or -d, it will start a development server.

See the --help option for more information about the CLI and environment variables that can be used to configure it.

Example Project

You can look at an example project that implements a simple blog site here.

IDE Integration

Wunphile uses ES6 template literals for composing HTML. Different IDEs need different configuration to provide syntax highlighting and intellisense for HTML inside template literals.

VS Code

Install the es6-string-html extension.

JetBrains IDEs

Recent versions of JetBrains IDEs should support syntax highlighting and intellisense for HTML inside template literals out of the box.