mffontship
v1.1.2
Published
CLI tool to download and manage Google Fonts locally — zero build step, pure ESM.
Maintainers
Readme
mffontship
Download and self-host Google Fonts in one command. Zero build step, pure ESM, Node 18+.
mffontship fetches .woff2 files directly from the Google Fonts API, writes them to disk, and generates a _font-faces.css file alongside a fonts-manifest.json you can commit. It ships a WordPress preset that also injects the @import into your theme's style.css.
Installation
# Use without installing — fonts/ folder created in the current directory
npx mffontship add "Inter" 400,700
# WordPress preset
npx mffontship add "Inter" 400,700 --wordpress
# Or install globally
npm install -g mffontship
mffontship add "Inter" 400,700 --wordpressCommands
add <family> <weights>
Download a Google Font family and register it locally. <weights> is a comma-separated list of numeric weights.
# No flags needed — creates fonts/ in the current working directory
mffontship add "Inter" 400,700
# WordPress preset — resolves dest automatically from cwd
mffontship add "Inter" 400,500,700 --wordpress
# WordPress with a non-default theme slug
mffontship add "Playfair Display" 400,700 --wordpress --theme="my-theme-child"
# WordPress + italic variants
mffontship add "Inter" 400,700 --wordpress --italic
# Explicit destination folder (no preset)
mffontship add "Inter" 400,700 --dest="path/to/fonts"
# Custom CSS fallback
mffontship add "Playfair Display" 400,700 --dest="fonts" --fallback=serif
# Skip the "MF " prefix — font is stored and referenced as plain "Inter"
mffontship add "Inter" 400,700 --no-prefix
# Preview what would be downloaded — no files written
mffontship add "Inter" 400,700 --wordpress --dry-run| Flag | Argument | Default | Description |
|---|---|---|---|
| --wordpress | — | off | Activate the WordPress preset. Resolves the destination to <cwd>/wp-content/themes/<theme>/. Also injects @import "fonts/_font-faces.css"; into style.css after the theme header block (idempotent). |
| --theme | <slug> | bb-theme-child | WordPress theme folder name. Only used with --wordpress. |
| --dest | <path> | — | Explicit destination folder. Relative to cwd or absolute. Cannot be used together with --wordpress. |
| --italic | — | off | Also download italic variants for all specified weights. |
| --fallback | <generic> | sans-serif | CSS generic font family written into _font-faces.css (e.g. serif, monospace). |
| --no-prefix | — | off | Store the font family name without the MF prefix. By default every family is prefixed — e.g. MF Inter. Pass --no-prefix to register it as plain Inter instead. |
| --dry-run | — | off | Print the filenames that would be downloaded without writing anything to disk. |
Writes (relative to dest):
fonts/
inter/ ← one sub-folder per family slug
inter-400.woff2
inter-400-italic.woff2
inter-700.woff2
fonts-manifest.json ← tracks all registered fonts; safe to commit
_font-faces.css ← auto-generated @font-face rules; do not edit manuallyremove <family>
Remove a single font family: deletes its .woff2 directory and regenerates _font-faces.css.
mffontship remove "Inter"
mffontship remove "Inter" --wordpress
mffontship remove "Inter" --dest="path/to/fonts"
mffontship remove "Playfair Display" --wordpress --theme="my-theme-child"| Flag | Argument | Default | Description |
|---|---|---|---|
| --wordpress | — | off | Use the WordPress preset to resolve the destination. |
| --theme | <slug> | bb-theme-child | WordPress theme folder name. |
| --dest | <path> | — | Explicit destination folder. |
list
Print a table of all fonts currently tracked in fonts-manifest.json.
mffontship list
mffontship list --wordpress
mffontship list --dest="path/to/fonts"| Flag | Argument | Default | Description |
|---|---|---|---|
| --wordpress | — | off | Use the WordPress preset to resolve the destination. |
| --theme | <slug> | bb-theme-child | WordPress theme folder name. |
| --dest | <path> | — | Explicit destination folder. |
Example output:
FONT NAME WEIGHTS STYLES
--------------------------------------------------------------------
MF Inter 400, 500, 700 normal
MF Playfair Display 400, 700 normal, italicsync
Regenerate _font-faces.css from fonts-manifest.json without re-downloading any files. Use this after manually editing the manifest.
mffontship sync
mffontship sync --wordpress
mffontship sync --dest="path/to/fonts"| Flag | Argument | Default | Description |
|---|---|---|---|
| --wordpress | — | off | Use the WordPress preset to resolve the destination. |
| --theme | <slug> | bb-theme-child | WordPress theme folder name. |
| --dest | <path> | — | Explicit destination folder. |
reset
Remove all registered fonts, delete every .woff2 directory, wipe fonts-manifest.json, and clear _font-faces.css.
mffontship reset
mffontship reset --wordpress
mffontship reset --dest="path/to/fonts"| Flag | Argument | Default | Description |
|---|---|---|---|
| --wordpress | — | off | Use the WordPress preset to resolve the destination. |
| --theme | <slug> | bb-theme-child | WordPress theme folder name. |
| --dest | <path> | — | Explicit destination folder. |
Adding a new preset (Laravel, Next.js, …)
- Create
src/presets/your-stack.jsexporting a plain object:
// src/presets/your-stack.js
import path from 'node:path';
export default {
resolveDest(cwd, flags) {
return path.join(cwd, 'resources/fonts');
},
afterAdd(dest, flags) {
// optional — runs after a successful `add`
},
};- Register it in
src/presets/index.js:
import yourStack from './your-stack.js';
const presets = { wordpress, 'your-stack': yourStack };- Call it with
--your-stack… or just wire up the flag inbin/mffontship.js. No other code changes required.
Security model
mffontship is a local CLI tool. It does not run install scripts and does not execute shell commands.
Network access is only used when the user explicitly runs mffontship add. The tool fetches CSS from https://fonts.googleapis.com and downloads font files exclusively from https://fonts.gstatic.com. All download URLs are validated at runtime to enforce HTTPS and the exact fonts.gstatic.com hostname — no other host is ever contacted.
Filesystem access is limited to the destination chosen by the user. By default this is a fonts/ folder inside the current working directory. The WordPress preset writes under wp-content/themes/<theme>/fonts/. The --dest flag lets the user point to any path they control — it is intentional user-directed output, not automatic or hidden writes.
No install hooks — the package has no postinstall, preinstall, prepare, or other lifecycle scripts that run automatically when consumers install it.
Code-level safeguards:
- Path traversal guard — all font directories are validated against the fonts root with
realpathSyncbefore any write or delete. - CSS sanitisation — family names, file entries, weights, and styles are all validated before being written into
_font-faces.css. - Atomic writes — manifest and CSS files are written to a
.tmpfile and renamed atomically. - Idempotent WP injection — the
@importis never inserted twice. - WordPress
--themesanitisation — only letters, numbers,_, and-are accepted; path separators are rejected.
Requirements
- Node.js ≥ 18 (uses native
fetch)
License
MIT
