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

@webhandle/pages-server

v1.0.0

Published

Express middleware that finds files that match the request path and renders them as templates.

Downloads

52

Readme

@webhandle/pages-server

Express middleware that finds files that match the request path and renders them as templates.

Install

npm install @wehandle/pages-server

Usage

If being used with webhandle:

import setupPages from '@webhandle/pages-server/initialize-webhandle-component.mjs'
setupPagesServerMiddleware(webhandleInstance)

If being used with express only:

import {createPagesServerMiddleware} from '@webhandle/pages-server'
let pageServer = createPagesServerMiddleware(pagesLocation)
expressAppOrRouter.use(pageServer)

What's Happening

The middleware is looking at the request and trying to determine if there's a file from the specified folder which would be a match, and if so, loading metadata, running setup code, and then eventually calling render on the res object.

To determine what's being requested, req.path is used. However, if req.pagePath is set, that is used instead. This allows previous middleware to control what page gets rendered without changing the req path.

Finding the Page

Finding a matching page has serveral steps. First, if the request specifies the exact name of a file (/contact-us.html), then that's used. If the request is more general like /contact-us then it tries to determine the best match. If there is a file /contact-us.html, that a good candidate. If /contact-us is a directory on the file system, then it attempts to find an index file for that directory. It also searches for variants of the file which are a better match for the requester's language preferences (more on that later).

Loading Metadata

After a specific file is found, the metadata for the page is loaded. The metadata is a file with the exact same name as the template to be rendered but with the .json extension. This information is parsed and put in res.locals.page. Metadata is a good place to store things like the page title, description, or references to database data.

Access Check

After the page metadata is loaded, a check is run to determine if the user can access the page pageServer.canServePage(req, res, renderSpec). By default, this code only looks to see if

if (res.locals.page.pageVisibility === 'private' && !req.user) {
	return false
}

That is, if a page is marked as private, it will only be shown if the requester is a logged in user.

Page Prerun Code

It was my observation that lots of pages could be rendered without any conditional logic at all, so long as all dynamic data was loaded and ready for it in advance. This makes creating the code for the pages a relatively simple task of just writing the html and structuring it into templates. This looks cleaner and allows for code separation and reuse.

Each page server has an array of "pre-run" functions with the same signatures as express middleware. function(req, res, next). They are added by pushing them onto the pageServer.preRun array.

These are called in order, only if a page is about to be rendered, and after the page metadata is loaded. While all of them are always run, it's not expect that they will all do something for every page.

To illustrate how this works, let's say a page has the following metadata:

{
	"title": "Contact Us"
	, "description": "Meet the team"
	, "loadStaffProfiles": true
}

A pre-run handler could look like this:

async function(req, res, next) {
	if(res.locals.page.loadStaffProfiles) {
		// talk to the database to fetch staff profiles
		res.locals.staffProfiles = await db.getStaff()
	}
	next()
}

In addition to page specific code, pre-run handlers are a good place to load information which is needed for every page, like a menu, but isn't needed at all unless a page is being rendered.

Headers

pageServer.setHeaders(req, res) is called to set any headers needed before render takes place. By default it just sets

res.set('Content-Type', 'text/html; charset=UTF-8')

Logging

Right before rendering the activity is logged. Pages Server uses filter-log, but you can replace it with anything you want at:

pageServer.logPageRender = function(req, res, renderSpec) ...

Rendering

The final step is rendering done by pageServer.render(req, res, renderSpec) which calls res.render with the template name.

Doing Page Setup Without a Page

Sometimes you've got everything set up to load info for your pages, and you want all that stuff to run, but you're not really going to render a page. You're going to render some other template or create the response in code. To prep as if you were going to render a page, you can call the async function

pageServer.setupDataForPages(req, res)

It's not marked as async, because it usually operates in callback mode, but if you call it with only two arguments, it will return a promise.

Optional Usage

The extensions of what's considered a template can be set in the options. Additionally, the names of the files to be used when a directory is requested can be specified.

import {createPagesServerMiddleware} from '@webhandle/pages-server'
let pageServer = createPagesServerMiddleware(pagesLocation, {
	indexNames: ['index']
	, templateExtensions: ['pug', 'html']
})
expressAppOrRouter.use(pageServer)

Extension Points

server.locator
server.preRun
server.searchAlternates
server.findPageInfo
server.logPageRender
server.canServePage
server.prerenderSetup
server.addHeaders
server.render
  • preRun - An array of functions that will be run before a page is rendered
  • searchAlternatives - A boolean which controls whether language alternatives are used
  • locator - An instance of @webhandle/page-locator, or something with the same behavior that finds page candidates