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

@fsoc/dhow

v1.2.5

Published

JSX-powered SSG for Node.js

Readme

This is a fork of kartiknair/dhow with some additional features.

From the original README:

JSX-powered SSG for Node.js. Write logic like React with a directory-structure like Next.js but generate plain HTML with no client side JS.

The changes in this fork are made in the hope that the modifications will eventually be included in the upstream repository.

Getting Started

The interface to the dhow command is

$ npx @fsoc/dhow --help
  Usage
    $ dhow <command> [options]

  Available Commands
    build    Compiles your pages for deployment
    dev      Rebuilds your pages on change and hosts them locally

  For more info, run any command with the `--help` flag
    $ dhow build --help
    $ dhow dev --help

  Options
    -i, --indir      Sets the directory where files will be read from  (default pages)
    -v, --version    Displays current version
    -h, --help       Displays this message

By default, dhow expects a directory structure like

├── pages
│   ├── about.js
│   └── index.js
└── public
    └── dhow.jpg

and, given the above, generates a directory like

out
├── about
│   └── index.html
├── dhow.jpg
└── index.html

which can be statically hosted using any webserver. The content of the public directory is simply copied over, the JavaScript files in the pages directory are transpiled to HTML and then copied to an appropiate location based on the file path.

Pages (the JavaScript files in the pages directory) are expected to export a function which returns JSX.

const Home = () => (<>
    <img src={'/dhow.jpg'} alt={'Dhow'} />

    <p>
        JSX-powered SSG for Node.js. Write logic like React with a directory-structure like Next.js but generate plain HTML with no client side JS.
    </p>
</>)

export default Home

Build time data fetching

In addition to the required default export, pages can export the (optionally async) function getProps, which can be used to dynamicaly fetch content at build time. Its return value is passed to the default-exported function.

export default ({ buildTime }) => (<>
    <p>
        This page was built on <time datetime={buildTime.toISOString()}>
            {buildTime.toDateString()}
        </time>.
    </p>
</>)

export const getProps = async () => ({
    buildTime: new Date()
})

Dynamic pages

By default each page is mapped to a route, determined by its file path. One can map a single page to multiple routes by wrapping its file name in brackets, like pages/post/[pid].js.

In order to define the possible routes, a page can export the (optionally async) function getPaths, which is expected to return an array of strings. The file name is ignored and can be thought to be replaced with each item in the array.

export default ({ content }) => (<>
    <p>
        {content}
    </p>
</>)

const data = {
    'about': /* ... */,
    'contact': /* ... */,
    'privacy': /* ... */,
}

export const getProps = async (slug) => ({
    content: data[slug]
})

export const getPaths = async () => Object.keys(data)

As can be seen in the example above, each item in the returned array is also passed to getProps (if it was exported). Assuming the above code is in the pages root, this would result in the routes /about, /contact and /privacy being available.

Custom App and Document

Analogous to NextJS, one can override the default App or Document through providing an _app.js or _document.js in the pages directory.

The App is a wrapper around every page, it receives the component that is exported from every page and the result of the getProps function (undefined if it was not exported).

const App = ({ Component, pageProps = {} }) => (<>
    <Component {...pageProps} />

    <Footer />
</>)

export default App

The Document is the actual DOM tree into which the built HTML of every page will be inserted, it should, at minimum, include

const Document = () => (<>
    <html>
        <head>
        </head>

        <body>
            {/* Pages will get inserted here. */}
        </body>
    </html>
</>)

export default Document

Note that, if provided, this is a complete replacement of the internal default tree (which looks like the above), so make sure it is complete.

Modifying the head content

A Head component is exported which can be used to modify the contents of the document head on a per-page basis.

import { Head } from '@fsoc/dhow'

export default () => (<>
    <Head>
        <title>Page title</title>
    </Head>
</>)

It's fine to have multiple Heads in one document, but note that (unlike NextJS, for example) the content of the Head will be appended to what is already in it (i. e. what was provided in Document or App).

Debugging and miscellaneous

A number of internal variables are exposed through process.env for the consumption of pages.

  • __DHOW_STAGING_PATH the absolute path to the internal staging folder
  • __DHOW_PAGE_PATH the absolute path to the internal page file corresponding to the current file
  • __DHOW_PAGE_DIR the absolute path to the directory in which the current page file is in, for convenience
  • __DHOW_ROUTE_PATH the name of the current route, this is the path to which the index.html file which is generated for the current page will be written to, relative to the output directory

Debug is used to provide debug logs, enable it through setting the environment variable DEBUG=dhow:*.

CSS

CSS is processed using PostCSS, dhow will attempt to read a postcss.config.js file from the root of the project and pass it to PostCSS. If none is found, nothing is passed through.