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

@jiant/unify

v0.1.2

Published

Interactive CLI to inline CSS and JS into an HTML file.

Readme

@jiant/unify

@jiant/unify turns a small web project into one portable HTML file.

Point it at a directory with an HTML entry, choose the CSS and JavaScript or TypeScript files you want, and it will stitch everything together into a single document with inline <style> and <script> blocks. It is built for the boring but useful moment when you need to hand someone one file that just opens and works.

What It Does

  • Scans the current directory recursively for .html, .css, .js, and .ts files
  • Lets you build interactively, or skip prompts with CLI flags
  • Bundles selected JS and TS entry files with esbuild
  • Inlines CSS before </head> when possible
  • Inlines scripts before </body> when possible
  • Falls back cleanly when head or body tags are missing
  • Optionally removes matching external <link> and <script src> tags for the files you inlined
  • Optionally minifies the final HTML output

Why It Exists

Modern front-end projects scatter a simple page across multiple files. That is usually fine until you need one artifact:

  • a throwaway prototype for review
  • a standalone demo
  • a shareable HTML deliverable
  • an archive snapshot of a static page
  • a single-file handoff for environments where asset hosting is annoying

unify is the compression step between “this project works locally” and “here, open this file.”

Quick Start

Inside a project folder:

npx @jiant/unify

The interactive flow will:

  1. ask you which HTML file should be the base document
  2. let you add CSS files
  3. let you add JS or TS entry files
  4. ask for the output filename
  5. ask whether to minify
  6. ask whether to remove matching external references

The default output name is based on the selected HTML file:

  • index.html -> index-unify.html
  • landing.html -> landing-unify.html

Non-Interactive Usage

npx @jiant/unify \
  --html index.html \
  --css reset.css,theme.css \
  --css components.css \
  --js vendor.js \
  --js app.ts,analytics.js \
  --ignore-path coverage,tmp/generated \
  --include-path dist \
  --output demo-bundle.html \
  --minify \
  --remove-inlined-references \
  --overwrite \
  --yes

Flags

  • --html <file>: base HTML file
  • --css <file[,file...]>: CSS files to inline, repeatable
  • --js <file[,file...]>: JS or TS entry files to bundle and inline, repeatable
  • --output <file>: output HTML filename
  • --ignore-path <path[,path...]>: ignore extra directories during recursive scan
  • --include-path <path[,path...]>: include directories that would otherwise be ignored
  • --minify: minify the generated file
  • --no-minify: keep readable formatting
  • --remove-inlined-references: remove matching external asset tags from the HTML
  • --keep-inlined-references: keep original external tags
  • --overwrite: replace an existing output file without asking
  • --yes, -y: skip confirmation prompts
  • --help, -h: print help

How Injection Works

CSS is inserted in this order of preference:

  1. before </head>
  2. after <head ...>
  3. after <html ...>
  4. at the top of the document if none of the above exist

Scripts are inserted in this order of preference:

  1. before </body>
  2. before </html>
  3. after <body ...>
  4. at the end of the document if none of the above exist

Each inlined block keeps a source marker so you can still see where it came from:

<style>
  /* Source: theme.css */
  body { color: red; }
</style>

<script>
  // Source: app.ts
  (() => {
    console.log("hello");
  })();
</script>

JavaScript and TypeScript Handling

Selected .js and .ts files are treated as browser entry points and bundled with esbuild before injection.

Current behavior:

  • bundle mode is enabled
  • output format is iife
  • platform is browser
  • target is es2018

That makes the generated HTML easier to open directly without needing a module loader.

File Discovery Rules

The scan is recursive and ignores common generated folders:

  • .git
  • .next
  • .nuxt
  • .output
  • .svelte-kit
  • build
  • coverage
  • dist
  • node_modules
  • out

To keep the prompt usable, the scan stops with an error if it finds more than 500 supported files total.

You can change that behavior from the CLI:

  • --ignore-path generated,coverage: ignore additional directories by name or relative path
  • --ignore-path apps/site/tmp: ignore one specific nested path
  • --include-path dist: scan a directory that is ignored by default
  • --include-path packages/demo/dist: scan one specific ignored path without changing the rest

Reference Removal

If you pass --remove-inlined-references, unify will remove matching tags for the assets you selected, for example:

  • <link rel="stylesheet" href="./theme.css">
  • <script src="./app.js"></script>

It only removes tags that match files you actually chose to inline. Unrelated asset tags stay untouched.

Development

npm install
npm run build
npm test

Run the CLI from source during development:

npm run dev -- --help

Practical Notes

  • Paths are resolved relative to the current working directory
  • The tool expects the files you pass via flags to exist in the discovered project set
  • Output names without an .html extension will automatically get one appended
  • If no HTML files are found in the current directory, the CLI exits with an error