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 🙏

© 2025 – Pkg Stats / Ryan Hefner

hbh-deve

v0.0.6

Published

Flexible SSR view engine and dynamic route loader for Express.js with support for Pug, HTML, Markdown, and JS-based views. Includes file-based routing, hot reload, and customizable layout rendering.

Downloads

123

Readme

🚀 hbh-deve

A flexible SSR view engine and dynamic file-based route loader for Express.js.
Supports .pug, .html, .md, and .js views — with live reload, layouts, and developer-friendly DX.


✨ Features

  • 📁 File-based routing — Auto-maps views/pages/ structure to Express routes
  • 🧠 Multi-format views — Render .pug, .html, .md, and .js as SSR templates
  • 🔁 Live reload — Watches files and reloads connected browsers on changes
  • 🧩 Layouts — Optional layout.pug support with layout toggling per-view
  • 📦 Frontmatter — In Markdown and .js views for metadata
  • 🛠️ Middleware support — Per-view Express middleware via .js exports
  • 🔧 Configurable — Customizable via hbh-deve.config.js or use same defaults
  • 🧪 Error overlays — In-browser overlays for SSR/runtime errors

📦 Installation

npm install hbh-deve
# or
yarn add hbh-deve

🗂️ Project Structure

project-root/
├── views/
│   ├── layout.pug            # Optional shared layout
│   └── pages/                # Route-driven views
│       ├── index.pug         # route: /
│       ├── about.html        # route: /about
│       ├── blog/
│       │   └── [slug].md     # dynamic: /blog/:slug
│       └── user/[id].js      # dynamic: /user/:id
├── hbh-deve.config.js        # Optional custom config
└── index.js                  # App entry

⚙️ Configuration (Optional)

// hbh-deve.config.js
import path from 'path';

const __dirname = process.cwd();
const ViewBase = path.join(__dirname, 'views');

export const directories = {
  __dirname,
  ViewBase,
  PagesBase: path.join(ViewBase, 'pages'),
  Layout: path.join(ViewBase, 'layout.pug')
};

🚀 Quick Start

1. Create Express app

import express from 'express';
import { Attach } from 'hbh-deve';

const app = express();

await Attach(app); // Loads all views + routes automatically

app.listen(3000, () => {
  console.log('✅ Running at http://localhost:3000');
});

2. Add views

views/pages/index.pug

h1 Welcome to my app!
p Current time: {{ new Date().toLocaleTimeString() }}

views/pages/blog/[slug].md

---
title: My Blog Post
nolayout: false
---

# Hello {{ params.slug }}

This is a markdown page.

views/pages/user/[id].js

export default async ({ params }) => {
  return {
    title: `User: ${params.id}`,
    html: `<p>Hello, <strong>${params.id}</strong></p>`
  };
};

export const middlewares = [
  (req, res, next) => {
    console.log('👋 User route hit');
    next();
  }
];

🔹 Layouts

Supports optional layouts (layout.pug) with automatic injection of default content and live reload. The behavior adapts based on what the user layout already contains.


1️⃣ Default Layout Injection

Given a layout like:

doctype html
html
  head
    title My App
  body
    h1 Header from layout

The engine automatically injects:

  • Live reload script (always)
  • Default content block if .page!= page is missing
  • Default scripts block if .scripts!= scripts is missing

Rendered final Pug:

doctype html
html
  head
    title My App
  body
    h1 Header from layout

    // ✅ Injected automatically:
    script.
      const es = new EventSource('/__reload');
      es.onmessage = (e) => {
        if (e.data === 'reload') location.reload();
      };

    if page
      .page!= page

    if scripts
      .scripts!= scripts

User-defined blocks are respected — duplicates are never injected.


2️⃣ Per-View Layout Toggle

You can disable the layout per view if needed:

| View Type | How to disable layout | | --------- | -------------------------------------------------------- | | .pug | Add //- nolayout at the top | | .md | Add nolayout: true in frontmatter | | .js | Return { nolayout: true } from the async view function |


3️⃣ Injection Flow

        ┌─────────────────────┐
        │ Load user layout.pug │
        └─────────┬───────────┘
                  │
                  ▼
       ┌───────────────────┐
       │ Strip comments     │
       └─────────┬─────────┘
                 │
                 ▼
   ┌─────────────────────────────┐
   │ Build injection string       │
   │ (force reload + default      │
   │ content/scripts if missing)  │
   └─────────┬───────────┬───────┘
             │           │
             │           ▼
             │     ┌───────────────┐
             │     │ Inject into   │
             │     │ <body> tag    │
             │     │ maintain      │
             │     │ indentation   │
             │     └─────┬─────────┘
             ▼           │
   ┌─────────────────────────────┐
   │ Compile final Pug            │
   │ Render with locals           │
   └─────────────────────────────┘

4️⃣ Fallback

If layout.pug does not exist:

  • A default layout with all blocks and live reload is used.
  • Ensures the page always renders without breaking.

5️⃣ Example Usage in a Pug Page

views/pages/index.pug:

h1 Welcome
p Current time: {{ new Date().toLocaleTimeString() }}

Behavior:

  • If layout.pug exists:

    • h1 Welcome remains intact
    • .page!= page is injected if missing
    • Live reload script is added automatically
  • If layout.pug is missing:

    • Page is rendered with the default layout
    • .page!= page and live reload script are included automatically

6️⃣ Automatic Injection Overview

| Injection Type | When It Happens | Notes | | -------------------------- | ------------------------------------ | ------------------------------------------------ | | Live reload script | Always | Injected in every page rendered | | .page!= page block | Only if missing in user layout.pug | Ensures content is displayed without duplication | | .scripts!= scripts block | Only if missing in user layout.pug | Scripts section is added if not already present | | User-defined blocks | Never overwritten | Preserves whatever user has already defined |

✅ This table helps you quickly see what the engine automatically injects versus what it preserves.


🧠 Supported View Types

| Format | Features | | ------- | ------------------------------------------------------------------------------- | | .pug | Pug syntax, supports layout.pug, variable injection | | .html | HTML with {{ variable }} interpolation | | .md | Markdown with frontmatter, supports nolayout | | .js | Async view functions, return { html, title, ... }, can export middlewares[] |


🧩 Routing Patterns

| File Name | Route Path | | --------------------- | -------------- | | index.pug | / | | about.html | /about | | user/[id].js | /user/:id | | blog/[[lang]].md | /blog/:lang? | | docs/[...slug].md | /docs/* | | api/[[...catch]].js | /api/*? |


🔄 Live Reload

  • Automatically watches views/ and reloads browser
  • Injects <script> tag automatically in rendered pages
  • No browser extension required
  • Works with .pug, .html, .md, and .js views

🧪 Template Interpolation

You can use {{ variable }} inside .html, .pug, and .md.

<h1>Hello, {{ query.name }}</h1>
<p>Time: {{ new Date().toLocaleTimeString() }}</p>

Certain blocks like <script> and comments are excluded from interpolation for safety.


❌ Error Overlay

When rendering fails (in dev), a browser overlay will appear:

⚠️ SSR Rendering Error

File: /views/pages/user/[id].js

Error: Unexpected token export

📄 Disabling Layout

Layout is applied automatically, but you can disable it per view:

| View Type | How to disable layout | | --------- | ----------------------------------------------------- | | .pug | Add //- nolayout at top | | .md | Add in frontmatter: nolayout: true | | .js | Return { nolayout: true } or include in frontmatter |


📚 API Reference

Attach(app: Express, options?)

  • Loads routes from views/pages/
  • Applies view rendering engine
  • Enables live reload via SSE
  • Supports optional config overrides

📦 Scripts

Add this in your package.json:

"scripts": {
  "dev": "node index.js"
}

Then run:

npm run dev

🔐 Security Notes

  • Sandboxed parser for .html and .md
  • Blocks unsafe expressions like eval, Function, window, etc.

📝 License

ISC


✍️ Author

HBH Made with ❤️ for Express.js developers