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-plugin-justif

v0.3.0

Published

Vite plugin for justif — publication-grade text justification. Auto-enhances your HTML and wires up every bundled hyphenation language for dev and build.

Readme

vite-plugin-justif

justif for Vite, without the CDN script.

justif ships its auto-enhancement as a <script type="module"> from a CDN, and the CDN build loads non-English hyphenation with dynamically built ./hyphenate/<id>.js specifiers — which no bundler can follow. This plugin solves both problems:

  • virtual:justif — the core API (justify, unjustify) plus a hyphenators map, with every selected language imported statically.
  • virtual:justif/auto — the drop-in auto-enhancement, bundled. Languages are code-split: each language ships as its own chunk, loaded only when that language actually appears in the page.
  • HTML injection — a module script importing virtual:justif/auto is added to every index.html entry, so enabling the plugin is the whole setup.

Requires Vite ^6.3.0 || ^7.0.0 || ^8.0.0 and justif as a peer dependency.

Live demo — justified, hyphenated prose in three languages, each shipping as its own lazy chunk, with a toggle to compare against native browser justification. Source in example/.

Install

npm install justif vite-plugin-justif

Usage

// vite.config.ts
import { defineConfig } from "vite";
import { vitePluginJustif } from "vite-plugin-justif";

export default defineConfig({
    plugins: [vitePluginJustif()],
});

That's it. Every paragraph matching justif's stock candidate selector (p, li, dd, blockquote, figcaption) with text-align: justify is enhanced: lazy hyphenation in the paragraph's language, spacing fallback for languages without a pattern, data-justif markers, and a window.justif escape hatch.

Options

vitePluginJustif({
    /** Languages to bundle. Also controls bundle size.
     *  Defaults to all 23 bundled languages. */
    languages: ["en-us", "de", "fr"],
    /** Candidate selector for the auto-enhancement
     *  (default: "p, li, dd, blockquote, figcaption"). */
    selector: "article p",
    /** Log a reason for every paragraph kept on native layout. */
    debug: true,
    /** Inject the auto entry into every HTML file (default: true). */
    inject: false,
    /** Hide candidates until typeset — no flash of native justification
     *  (default: false). Reveals after 1.5s even if enhancement stalls. */
    cloak: true,
});

Set inject: false when a strict Content-Security-Policy blocks inline scripts — then import virtual:justif/auto from your own entry. selector and debug are baked into the generated module, so they apply either way.

import "virtual:justif/auto";

Avoiding the Enhancement Flash

First paint happens before module scripts run, so without help the browser shows native justification for an instant before justif retypesets. cloak: true fixes this: candidates are hidden by a pre-paint style plus a data-justif-cloak attribute on <html>, and the runtime removes the attribute once layout settles (or after 1.5s, whichever comes first, so content is never trapped). Both knobs take an object form:

cloak: {
    /** Fallback reveal in ms (default: 1500); false = reveal on booted only. */
    timeout: 4000,
    /** Skip the default visibility rule and bring your own cloak CSS. */
    style: false,
}

Your CSS can key transitions off the attribute for a fade-in:

article p {
    transition: opacity 0.25s ease;
}
html[data-justif-cloak] article p {
    opacity: 0;
}

Under a strict CSP (inject: false), write the attribute yourself — <html data-justif-cloak> — and the runtime still reveals; no inline script is involved.

Runtime API

bootAuto is exported as vite-plugin-justif/runtime/auto. It returns a JustifAutoHandle — the same object it exposes on window.justif:

import type { Hyphenator, JustifAutoHandle } from "vite-plugin-justif/runtime/auto";
  • justify / unjustify — the core API.
  • controllers — the active JustifyControllers, rebuilt in place across reconfigure() so held references stay live.
  • booted — resolves once layout has converged for every group.
  • reconfigure() — re-reads --justif-* configuration and rebuilds controllers. (There is no style watcher; call it when config changes.)

Configuration

justif's declarative --justif-* layout options are fully supported: set them on any element and they apply per group, e.g.

:root {
    --justif-hanging-punctuation: all-line-edges;
    --justif-expansion: 4%;
    --justif-last-line-min-width: none;
}

The full surface: --justif-hanging-punctuation, --justif-protrusion, --justif-expansion, --justif-tracking, --justif-last-line-min-width, --justif-last-line-fit, --justif-space-stretch, --justif-space-shrink. (There is no live style watcher — call window.justif.reconfigure() after changing them at runtime.)

See the justif README for the available properties, keywords, and measurement semantics.

How It Works

resolveId/load hook filters answer for virtual:justif and virtual:justif/auto only, so the plugin never intercepts other modules. virtual:justif/auto is a generated module that imports the runtime bootstrap statically, then declares one static-string import() per language:

import { bootAuto } from "vite-plugin-justif/runtime/auto";

bootAuto({
    selector: "p, li, dd, blockquote, figcaption",
    debug: false,
    loaders: {
        "en-us": () => import("justif/hyphenate/en-us").then((m) => m.hyphenateEnUS),
        de: () => import("justif/hyphenate/de").then((m) => m.hyphenateDe),
    },
});

Vite treats every specifier as a static import it can code-split, so the initial bundle stays small and each language loads on demand — concurrently per language group. The resolved hyphenator (or undefined, for languages without a pattern) gives that group the same hyphenation justif's own auto loader would have built at runtime.

Supported Languages

ca, da, de, el, en-gb, en-us, es, fi, fr, hr, hu, it, nb, nl, nn, pl, pt, ru, sk, sl, sv, tr, uk (en resolves to en-us, no to nb).

License

MIT