Vite plugin that extracts only the glyphs you use from font files — icon fonts, text fonts, or both. Supports Vite 5, 6, 7, and 8.
Before: Material Icons 348 KB (all 2,000+ icons)
After: Material Icons 12 KB (only 3 icons you need) → 97% smaller
- Icon font minification — keep only the ligatures you use (Material Icons, FontAwesome, etc.)
- Text font subsetting — keep only specific characters via
?subset=query - Zero-config auto mode — detects glyphs from CSS
content: "..."automatically - Google Fonts optimization — appends
&text=parameter for server-side subsetting - Works in build and dev — minifies fonts on-the-fly during development
- Vite 5–8 support — compatible with both Rollup and Rolldown bundlers
- Content-based hashing — output filenames change when config changes (cache-safe)
- Live playground — see the plugin in action
- Disk cache — skip re-minification on repeated builds
npm install vite-font-extractor-plugin// vite.config.js
import FontExtractor from 'vite-font-extractor-plugin'
export default defineConfig({
plugins: [FontExtractor()],
})The plugin scans all CSS for content: "..." declarations, collects referenced glyphs, and strips everything else from
font files.
Specify exactly which icons to keep:
FontExtractor({
type: 'manual',
targets: [
{
fontName: 'Material Icons',
ligatures: ['close', 'menu', 'search', 'home'],
},
],
})Strip unused characters from text fonts like Roboto, Inter, or Open Sans.
/* Keep only Latin letters and digits */
@font-face {
font-family: 'Roboto';
src: url('./fonts/Roboto.woff2?subset=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789') format('woff2');
}
/* Keep a Unicode range (e.g. Cyrillic) */
@font-face {
font-family: 'Roboto';
src: url('./fonts/Roboto.woff2?subset=U+0400-04FF') format('woff2');
}
/* Combine characters and Unicode ranges */
@font-face {
font-family: 'Roboto';
src: url('./fonts/Roboto.woff2?subset=ABC,U+0400-04FF') format('woff2');
}Useful for runtime font loading (Rive, Canvas, PDF generators):
import fontUrl from './fonts/Roboto.woff2?subset=ABCabc'
// fontUrl is a clean URL to the subsetted font asset
rive.load({fonts: [fontUrl]})FontExtractor({
type: 'manual',
targets: [
{
fontName: 'Roboto',
characters: 'ABCabc0123456789',
engine: 'subset',
},
],
})The plugin appends &text= to Google Font URLs, letting Google's servers do the subsetting:
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">@import "https://fonts.googleapis.com/icon?family=Material+Icons";Multi-family URLs are supported: family=Material+Icons|Roboto.
Enable disk cache to skip re-minification when fonts and config haven't changed:
FontExtractor({
type: 'manual',
targets: [{fontName: 'Material Icons', ligatures: ['close']}],
cache: true, // caches in node_modules/.font-extractor-cache
// cache: './my-cache', // or a custom path
})The cache is automatically cleaned when cache is set to false.
| Vite | Status |
|---|---|
| v5 | Stable |
| v6 | Stable |
| v7 | Stable |
| v8 | Experimental |
Vite 8 uses Rolldown instead of Rollup. Icon font minification works fully. The
?subset=feature has known limitations — see ROADMAP for details.
import FontExtractor from 'vite-font-extractor-plugin'
FontExtractor(options?: PluginOption): Plugin| Option | Type | Default | Description |
|---|---|---|---|
type |
'auto' | 'manual' |
'auto' |
Glyph detection strategy |
targets |
Target | Target[] |
— | Fonts to process. Required in manual mode |
cache |
boolean | string |
— | Enable disk cache (or custom path) |
logLevel |
'info' | 'warn' | 'error' | 'silent' |
Vite config | Log verbosity |
apply |
'build' | 'serve' |
both | Restrict to build or dev mode |
ignore |
string[] |
— | Font names to skip entirely |
| Option | Type | Description |
|---|---|---|
fontName |
string |
Must match font-family in CSS (without quotes) |
ligatures |
string[] |
Icon names to keep (e.g. ['close', 'menu']) |
raws |
string[] |
Raw Unicode characters to keep |
characters |
string |
Characters string for text font subsetting |
unicodeRanges |
string[] |
Unicode ranges (e.g. ['U+0400-04FF']) |
engine |
'icon' | 'subset' |
icon for icon fonts, subset for text fonts |
withWhitespace |
boolean |
Include whitespace glyphs (default: false) |
Font not being minified?
- Check that
fontNameexactly matches thefont-familyvalue in your CSS@font-face(without quotes) - Make sure the font isn't in the
ignorelist
Warning: "has no minify options"?
- The plugin found a
@font-facebut the font isn't intargets - Fonts with
?subset=URLs don't trigger this warning — they're processed automatically - To silence: add the font to
targets, use?subset=, or add toignore
Google Font URL not transformed?
- Use spaces in
fontName:'Material Icons', not'Material+Icons'
Auto mode missing glyphs?
- Auto mode only detects glyphs from CSS
content: "..."properties - If icons are referenced by class name or JS, use
manualmode instead
Issues and pull requests are welcome on GitHub.
