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

vite-njk-trace

v1.0.1

Published

Dev-only Vite plugin that wraps every Nunjucks template (and rendered page) with HTML comments so you can see template origins in DevTools.

Readme

vite-njk-trace

License: MIT Vite 5–8 Node >= 18 Nunjucks ^3

Dev-only Vite plugin that injects Nunjucks template boundaries into your rendered HTML as comments, so every fragment in DevTools' Elements panel reveals exactly which .njk file it came from.


Features

  • Loader trace — wraps every {% include %}, {% extends %}, and {% import %} template with <!-- NJK: START … --> / <!-- NJK: END … --> comments.
  • Page wrapper — wraps the rendered page body via transformIndexHtml (post order) so the page itself is also annotated.
  • Zero-config dev-only — registered with apply: "serve", so vite build is unaffected and ships no trace comments.
  • Reference counted — multiple enableNjkTraceLoader calls are balanced; the prototype is only patched on the first call and restored on the last.
  • Lazy nunjucks resolution — nunjucks is loaded with createRequire only when the plugin runs. Installing vite-njk-trace in a non-Nunjucks project does not throw ERR_MODULE_NOT_FOUND.
  • Hardened paths — leading separators in pagesDir are stripped, and every label uses forward slashes regardless of host OS.
  • Sanitised HTML — --> in template paths is escaped to -- > so injected comments are always well-formed.
  • Dual ESM/CJS — ships dist/index.mjs, dist/index.cjs, dist/index.d.ts, and dist/index.d.cts with full TypeScript declarations.
  • No side effects — "sideEffects": false for safe tree-shaking.

Compatibility

| Dependency | Supported versions | | ---------- | ------------------ | | Vite | ^5.0.0, ^6.0.0, ^7.0.0, ^8.0.0 | | Nunjucks | ^3.0.0 | | Node | >=18 |

Both vite and nunjucks are listed as optional peer dependencies — install them in your project if they are not already present.


Installation

pnpm add -D vite-njk-trace
# or
npm install -D vite-njk-trace
# or
yarn add -D vite-njk-trace

Quick start

// vite.config.ts
import { defineConfig } from "vite";
import path from "node:path";
import { fileURLToPath } from "node:url";
import viteNjkTrace from "vite-njk-trace";

const projectRoot = path.dirname(fileURLToPath(import.meta.url));

export default defineConfig({
  plugins: [
    viteNjkTrace({
      projectRoot,
      pagesDir: "frontend/src/views/pages",
    }),
  ],
});

Now open http://localhost:5173/ in your browser, inspect any element, and you will see comments like:

<!-- NJK: START frontend/src/views/partials/_header.njk -->
<header>…</header>
<!-- NJK: END frontend/src/views/partials/_header.njk -->

<main>
  <h1>Home</h1>
  <!-- NJK: START frontend/src/views/partials/_card.njk -->
  <section class="card">…</section>
  <!-- NJK: END frontend/src/views/partials/_card.njk -->
</main>

<!-- NJK: START frontend/src/views/pages/index.njk -->
<!-- NJK: END frontend/src/views/pages/index.njk -->

Order of plugins / Troubleshooting

vite-njk-trace uses enforce: "post" and the configResolved hook so that the Nunjucks loader patch is applied after all normal plugins (including template-engine plugins like vite-plugin-njk-frontmatter) have finished their own setup. This means plugin order in vite.config.js no longer affects correctness.

For best practice, place viteNjkTrace() after your template-engine plugins in the plugins array:

export default defineConfig({
  plugins: [
    vitePluginNjkFrontmatter(),   // template engine plugin
    viteNjkTrace({ projectRoot }), // ← after template plugins (recommended)
  ],
});

If you only see the root template (index.njk) traced but not its included partials, ensure that your template engine plugin registers its Nunjucks Environment / FileSystemLoader during the config or configResolved phase — hooks that run after configResolved (e.g. configureServer) are too late for the loader patch to pick up the loader instance.


Configuration

| Option | Type | Default | Description | | ------------------- | --------- | -------------------------------- | --------------------------------------------------------------------------- | | projectRoot | string | process.cwd() | Absolute root for resolving relative template paths in the HTML comments. | | pagesDir | string | "frontend/src/views/pages" | Path to the directory of .njk pages, relative to projectRoot. Leading slashes are stripped. | | enablePagesTrace | boolean | true | When true, the page wrapper (via transformIndexHtml) is enabled. |


API

viteNjkTrace(options?) (default export)

Returns a PluginOption[] containing:

  1. vite-njk-trace:loader — monkey-patches FileSystemLoader.prototype.getSource (dev only).
  2. vite-njk-trace:pages — wraps the rendered page via transformIndexHtml (only when enablePagesTrace is true).

Both sub-plugins are dev-only (apply: "serve").

Programmatic / standalone

import nunjucks from "nunjucks";
import {
  enableNjkTraceLoader,
  disableNjkTraceLoader,
} from "vite-njk-trace";

enableNjkTraceLoader({ projectRoot: __dirname });
nunjucks.configure("frontend/src/views", { autoescape: false });
console.log(nunjucks.render("pages/index.njk"));
disableNjkTraceLoader();

Sub-plugins

import viteNjkTrace, { njkTracePages } from "vite-njk-trace";

export default defineConfig({
  plugins: [
    viteNjkTrace({ enablePagesTrace: false }),
    njkTracePages({ pagesDir: "src/pages" }),
  ],
});

Exported symbols

| Export | Kind | Description | | ---------------------------- | -------- | ---------------------------------------------------------------------------- | | default / viteNjkTracePlugin | function | Vite plugin: returns the loader + (optional) pages sub-plugins. | | enableNjkTraceLoader | function | Wraps FileSystemLoader.prototype.getSource. Reference-counted. | | disableNjkTraceLoader | function | Decrements the refcount; restores original getSource only at 0. | | isWrapped | function | Inspect whether the loader prototype is currently patched. | | getPatchCount | function | Returns the current reference count for the loader patch. | | njkTracePagesPlugin | function | Builds the page-wrapper Vite plugin (transformIndexHtml). | | njkTracePages | function | Convenience wrapper that resolves user options and returns a Vite plugin. | | START / END | function | Comment generators (<!-- NJK: START … --> / <!-- NJK: END … -->). |


Behaviour

  • Dev-only. apply: "serve" keeps the plugin out of the production bundle.
  • Reference counted. Each enableNjkTraceLoader increments, each disableNjkTraceLoader decrements. The prototype is patched on 0 → 1 and restored on 1 → 0.
  • Safe. If nunjucks.FileSystemLoader cannot be resolved, enableNjkTraceLoader logs a warning and returns a no-op teardown. The plugin never throws at import time.
  • Path safe. Leading separators in pagesDir are stripped so it can never be promoted to an absolute path. Labels are always forward-slash, regardless of host OS.
  • HTML safe. Any --> inside a template path is escaped to -- > so injected comments remain well-formed.
  • Page resolution. The page wrapper tries <base>.njk first, then <base>/index.njk, mirroring Vite's HTML routing.

Project layout

vite-njk-trace/
├── src/
│   ├── index.ts          # Public API + default plugin (PluginOption[])
│   ├── loader.ts         # Lazy FileSystemLoader prototype patch (ref-counted)
│   ├── pages-plugin.ts   # transformIndexHtml wrapper (path-hardened)
│   └── types.ts          # Options interface
├── tests/
│   └── unit/             # Vitest unit tests
├── tests_plugin/         # Manual integration playground
├── dist/                 # Build output (tsup): {index.cjs,index.mjs,index.d.ts,index.d.cts}
├── tsup.config.ts
├── tsconfig.json
├── vitest.config.ts
└── package.json

Scripts

pnpm build            # tsup → dist/{index.cjs,index.mjs,index.d.ts,index.d.cts}
pnpm test             # vitest run
pnpm typecheck        # tsc --noEmit
pnpm prepublishOnly   # build + test

Manual playground

# from the repo root
pnpm install
pnpm --filter vite-njk-trace build
pnpm --filter vite-njk-trace-playground dev
# → http://localhost:5173/

License

MIT © vinyardrip