@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.tsfiles - 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
headorbodytags 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/unifyThe interactive flow will:
- ask you which HTML file should be the base document
- let you add CSS files
- let you add JS or TS entry files
- ask for the output filename
- ask whether to minify
- ask whether to remove matching external references
The default output name is based on the selected HTML file:
index.html->index-unify.htmllanding.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 \
--yesFlags
--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:
- before
</head> - after
<head ...> - after
<html ...> - at the top of the document if none of the above exist
Scripts are inserted in this order of preference:
- before
</body> - before
</html> - after
<body ...> - 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-kitbuildcoveragedistnode_modulesout
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 testRun the CLI from source during development:
npm run dev -- --helpPractical 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
.htmlextension will automatically get one appended - If no HTML files are found in the current directory, the CLI exits with an error
