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

@turntrout/subfont

v1.11.0

Published

Automatically subset web fonts to only the characters used on your pages. Fork of Munter/subfont with modern defaults.

Downloads

6,415

Readme

@turntrout/subfont

Build Status

A faster fork of subfont that subsets web fonts to only the characters used on your pages. Adds parallel tracing, disk caching, woff2-only output, always-on variable font instancing, and is fully written in TypeScript (the upstream is JavaScript). On turntrout.com (382 pages, 20+ font variants), switching to this fork cut font subsetting from 111 minutes to 28 minutes.

Aggressive woff2 subsetting

subfont produces dramatically smaller font files by stripping data that browsers never use:

| Optimization | Technique | | ---------------------------- | --------------------------------------------------------------------------------------- | | Hinting removal | Strips TrueType hinting instructions (browsers auto-hint) | | Name table pruning | Keeps only the 4 IDs browsers read (family, subfamily, full name, PostScript name) | | Name lang-ID filter | Keeps only en-US name strings; drops Japanese, Russian, Korean, etc. | | Table stripping | Drops DSIG, LTSH, VDMX, hdmx, gasp, PCLT | | MATH-table drop (gated) | Drops MATH when no math codepoints are used on the page | | Color-table drop (gated) | Drops COLR/CPAL/SVG /CBDT/CBLC/sbix/EBDT/EBLC/EBSC when no emoji used | | Layout-script filter (gated) | Drops GSUB/GPOS lookups for OpenType scripts the page doesn't render | | CSS-aware feature retention | Drops GSUB/GPOS features the page's CSS doesn't reference |

Reproducible benchmark on testdata/subsetFonts/OpenSans-400.ttf (run with node scripts/bench-readme.js); "upstream" = the subset-font package the original Munter/subfont uses, woff2-compressed:

| Text sample | Upstream subfont | @turntrout/subfont | Savings | | ----------------- | ---------------- | -------------------- | ------- | | Heading (short) | 2,604 B | 828 B | 68% | | Paragraph | 4,448 B | 2,072 B | 53% | | Full page charset | 9,388 B | 5,500 B | 41% |

Install

pnpm add -g @turntrout/subfont

Or with npm:

npm install -g @turntrout/subfont

Requires Node.js >= 18.

Usage

# Optimize build artifacts in-place (recommended)
subfont path/to/dist/index.html -i

# Preview without writing
subfont path/to/dist/index.html --dry-run

# Output to a separate directory
subfont path/to/index.html -o path/to/output

# Crawl all linked pages
subfont path/to/index.html -i --recursive

# Trace JS-rendered content in headless Chrome
subfont path/to/index.html -i --dynamic

# Cache subset results between runs
subfont path/to/index.html -i --cache

Options

| Flag | Default | Description | | -----------------: | :-----: | :---------------------------------------------------------------------------------------------------------------------------------------------------------- | | -i, --in-place | off | Modify files in-place | | -o, --output | | Output directory | | --root | | Path to web root (deduced from input files if not specified) | | --canonical-root | | URI root where the site will be deployed | | -r, --recursive | off | Crawl linked pages | | --dynamic | off | Trace with headless browser | | --dry-run | off | Preview without writing | | --fallbacks | on | Async-load the full original font as a fallback for dynamic content | | --font-display | swap | auto/block/swap/fallback/optional | | --text | | Extra characters for every subset | | --cache [dir] | off | Cache subset results to disk between runs | | --concurrency N | auto | Max worker threads (defaults to CPU count, max 8). Warns when exceeding memory-based estimate (~50 MB per worker) | | --chrome-flags | | Custom Chrome flag for --dynamic. Use the = form and repeat for multiple flags: --chrome-flags=--no-sandbox --chrome-flags=--disable-features=Foo,Bar | | --source-maps | off | Preserve CSS source maps (slower) | | --strict | off | Exit non-zero if any warnings are emitted | | -s, --silent | off | Suppress all console output | | -d, --debug | off | Verbose timing and font glyph detection info | | --relative-urls | off | Emit relative URLs instead of root-relative | | --inline-css | off | Inline the subset @font-face CSS into HTML |

Run subfont --help for the full list.

Environment variables

| Variable | Description | | --------------------------- | ------------------------------------------------------------------------------ | | PUPPETEER_EXECUTABLE_PATH | Path to a Chrome/Chromium binary; skips auto-download when --dynamic is used |

To include extra characters in a specific font's subset, add -subfont-text to its @font-face:

@font-face {
  font-family: Roboto;
  src: url(roboto.woff2) format('woff2');
  -subfont-text: '0123456789';
}

Programmatic API

const subfont = require('@turntrout/subfont');

const assetGraph = await subfont(
  {
    inputFiles: ['path/to/index.html'],
    inPlace: true,
  },
  console
);

The package ships CommonJS with TypeScript declarations (subfont.d.ts). Returns the Assetgraph instance.

Parameters

subfont(options, console) — the second argument is an optional logger (anything with log, warn, and error methods — e.g. the global console). Pass null together with silent: true to suppress all output.

The options object accepts the following keys:

| Option | Type | Default | Description | | --------------- | ------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------ | | inputFiles | string[] | [] | HTML entry points (file paths or URLs). At least one is required unless root is given. | | root | string | deduced | Path or URL to the web root. Deduced from inputFiles if omitted. | | canonicalRoot | string | — | URI root where the site will be deployed (used to rewrite absolute URLs). | | output | string | — | Output directory. Mutually exclusive with inPlace. | | inPlace | boolean | false | Modify input files in place. | | dryRun | boolean | false | Trace and compute subsets but do not write any files. | | recursive | boolean | false | Crawl linked pages starting from inputFiles. | | dynamic | boolean | false | Trace JS-rendered content in headless Chrome (via puppeteer). | | fallbacks | boolean | true | Async-load the full original font as a fallback for dynamic content. | | fontDisplay | string | 'swap' | font-display CSS value: auto, block, swap, fallback, or optional. | | text | string | — | Extra characters to include in every subset. | | inlineCss | boolean | false | Inline the subset @font-face CSS into the HTML document. | | relativeUrls | boolean | false | Emit relative URLs instead of root-relative URLs. | | sourceMaps | boolean | false | Preserve CSS source maps (slower). | | concurrency | number | auto | Max parallel tracing workers. Defaults to CPU count, capped by available memory (~50 MB per worker). | | chromeFlags | string[] | [] | Extra Chrome flags forwarded to puppeteer when dynamic is set. | | cache | boolean \| string | false | Cache subset results between runs. Pass a path to customize the cache directory; true uses .subfont-cache inside the root directory. | | strict | boolean | false | Resolve with a non-zero exit (via the CLI) if any warnings are emitted. | | silent | boolean | false | Suppress all log output to console. | | debug | boolean | false | Emit verbose timing and glyph-detection info. |

License

MIT -- Original work by Peter Muller (Munter)