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

@ovineko/spa-guard-node

v0.0.2-alpha-1

Published

Server-side HTML cache with ETag/304, pre-compression, and i18n for spa-guard

Readme

@ovineko/spa-guard-node

npm license

Server-side HTML cache for spa-guard — pre-compresses your SPA's HTML for all languages and serves it with ETag/304 and content-encoding negotiation.

Install

npm install @ovineko/spa-guard-node @ovineko/spa-guard
npm install parse5

Usage

Build the cache once at startup, then use get() on each request:

import { createHtmlCache } from "@ovineko/spa-guard-node";
import { readFile } from "node:fs/promises";

const html = await readFile("dist/index.html", "utf8");
const cache = await createHtmlCache({ html });

// In your request handler:
const { body, headers, statusCode } = cache.get({
  acceptEncoding: req.headers["accept-encoding"],
  acceptLanguage: req.headers["accept-language"],
  ifNoneMatch: req.headers["if-none-match"],
});
res.writeHead(statusCode, headers);
res.end(body);

With custom translations and language filter:

const cache = await createHtmlCache({
  html,
  languages: ["en", "ko", "ja"],
  translations: {
    ko: { heading: "서비스 점검 중입니다" },
  },
});

Multiple pages with createHTMLCacheStore

import { createHTMLCacheStore } from "@ovineko/spa-guard-node";

const store = createHTMLCacheStore({
  main: () => readFile("dist/index.html", "utf8"),
  admin: () => readFile("dist/admin.html", "utf8"),
});

await store.load();

const cache = store.getCache("main");

Server-side i18n patching

import { patchHtmlI18n } from "@ovineko/spa-guard-node";

const patched = patchHtmlI18n({
  html,
  acceptLanguage: req.headers["accept-language"],
});

Builder API

Use the builder API to generate the spa-guard runtime script outside of Vite (e.g., in a custom build step or SSR framework):

import { buildSpaGuardScript, buildExternalScript } from "@ovineko/spa-guard-node";

// Inline script — returns script content and HTML tag strings
const { scriptContent, hash, html, tags } = await buildSpaGuardScript({
  version: "1.0.0",
  html: { spinner: { background: "#f5f5f5" } },
});

// External script — writes a content-hashed file to disk
const result = await buildExternalScript({
  outDir: "dist/assets",
  publicPath: "/assets",
  version: "1.0.0",
});
// result.publicUrl => '/assets/spa-guard.abc12345.js'
// result.html => ['<script src="/assets/spa-guard.abc12345.js"></script>', ...]

API

  • buildSpaGuardScript(options?) — builds the inline runtime script; returns BuildScriptResult
  • buildExternalScript(options) — writes a content-hashed script file to outDir; returns BuildExternalScriptResult
  • BuildScriptOptions — options for buildSpaGuardScript (extends core Options, adds trace?: boolean)
  • BuildExternalScriptOptions — options for buildExternalScript (extends BuildScriptOptions, adds outDir: string and publicPath?: string)
  • BuildScriptResult{ scriptContent, hash, html: string[], tags: HtmlTagDescriptor[] }
  • BuildExternalScriptResult{ fileName, publicUrl, html: string[], tags: HtmlTagDescriptor[] }
  • HtmlTagDescriptor — structured tag object { tag, attrs?, children?, injectTo } for framework injection
  • createHtmlCache(options) — builds a cache with gzip/brotli/zstd variants for all languages; returns an HtmlCache with a get() method
  • createHTMLCacheStore(input, languages?) — manages multiple named caches; call load() once then getCache(key)
  • patchHtmlI18n(options) — injects <meta name="spa-guard-i18n"> and updates <html lang> for server-side rendering
  • matchLang(input, available?) — resolves an Accept-Language value to a supported language code
  • translations — built-in translation map (en, ko, ja, zh, fr, de, es, pt, ru, ar)

Related packages

License

MIT