angular-fonts
v0.0.3
Published
Optimized font loading for Angular with SSR support
Downloads
46
Maintainers
Readme
angular-fonts
Optimized font loading for Angular with SSR support, inspired by @next/font.
Features
- 🚀 Build-time optimization: Download and self-host fonts during build
- ⚡ Runtime service: Dynamic font loading when needed
- 🔄 SSR compatible: Works with Angular 17+ and
@angular/ssr - 🎨 Tailwind integration: CSS variables for both v4 (@theme) and v3 (config file)
- 📦 Google Fonts: 1000+ fonts available
- 🏠 Local fonts: Support for custom font files
- 🎯 Zero layout shift: Automatic fallback metrics
- ✂️ Font subsetting: Reduce file sizes by 80-90% with text/unicode range subsetting
- 🔧 Variable fonts: Full support for variable font axes (wght, slnt, wdth, custom)
- 🌐 Custom CDN: Self-host fonts on your own CDN infrastructure
- 🔄 Advanced retry: Configurable retry strategies with exponential backoff
Installation
npm install angular-fonts
# or
pnpm add angular-fonts
# or
yarn add angular-fontsQuick Start
1. Install the package
npm install angular-fonts
# or
pnpm add angular-fonts
# or
yarn add angular-fonts2. Declare fonts in src/fonts.ts
// src/fonts.ts
import { Inter, Roboto_Mono } from "angular-fonts/google";
export const inter = Inter({
weights: [400, 700],
subsets: ["latin"],
variable: "--font-inter",
});
export const robotoMono = Roboto_Mono({
subsets: ["latin"],
variable: "--font-roboto-mono",
});3. Configure Angular CLI builder
// angular.json
{
"projects": {
"my-app": {
"architect": {
"font-optimize": {
"builder": "angular-fonts:optimize",
"options": {
"outputPath": "dist",
"projectRoot": "",
"sourceRoot": "src",
"fontFile": "src/fonts.ts",
"injectTailwind": "v4"
}
}
}
}
}
}4. Run font optimization
ng run my-app:font-optimize
# or add to your build script
npm run build # includes font optimization5. Use fonts in components
// app.component.ts
import { Component } from "@angular/core";
import { inter, robotoMono } from "./fonts";
@Component({
selector: "app-root",
template: `
<div class="font-sans">Hello World</div>
<code class="font-mono">Code example</code>
`,
host: {
"[class]": "fontClasses",
},
})
export class AppComponent {
fontClasses = `${inter.className} ${robotoMono.className}`;
}2. Local Fonts
// fonts.ts
import { localFont } from "angular-fonts/local";
// Single font file
export const customFont = localFont({
src: "./fonts/my-font.woff2",
variable: "--font-custom",
fallback: ["system-ui", "arial"],
// adjustFontFallback automatically generates fallback metrics (default: true)
});
// Multiple weights and styles
export const rubikFamily = localFont({
src: [
{ path: "./static/Rubik-Regular.ttf", weight: "400", style: "normal" },
{ path: "./static/Rubik-Bold.ttf", weight: "700", style: "normal" },
{ path: "./static/Rubik-Italic.ttf", weight: "400", style: "italic" },
],
variable: "--font-rubik",
display: "swap",
// Automatically uses Arial as fallback for sans-serif fonts
});3. Font Subsetting (Reduce File Size by 80-90%)
// fonts.ts
import { Inter } from "angular-fonts/google";
// Subset by specific text
export const interSubset = Inter({
weights: [400, 700],
subsets: ["latin"],
subset: {
text: "Hello World 123", // Only these characters
},
variable: "--font-inter-subset",
});
// Subset by unicode range
export const interRange = Inter({
weights: [400, 700],
subsets: ["latin"],
subset: {
unicodeRange: "U+0020-007F", // Basic Latin
},
variable: "--font-inter-range",
});
// Use helper for common character sets
import { COMMON_CHARACTER_SETS } from "angular-fonts/google";
export const interBasic = Inter({
weights: [400, 700],
subsets: ["latin"],
subset: {
text: COMMON_CHARACTER_SETS.basicLatin, // A-Z, a-z, 0-9, basic punctuation
},
variable: "--font-inter-basic",
});4. Variable Fonts
// fonts.ts
import { Inter } from "angular-fonts/google";
// Basic variable font
export const interVariable = Inter({
weights: "variable", // Use variable font
subsets: ["latin"],
variable: "--font-inter-variable",
});
// Custom variable axes ranges
export const interCustomAxes = Inter({
weights: "variable",
subsets: ["latin"],
variableAxes: {
wght: [100, 900], // Weight range
slnt: [-10, 0], // Slant range
wdth: [75, 125], // Width range
},
variable: "--font-inter-custom",
});
// Additional variable axes (font-specific)
export const interAdvanced = Inter({
weights: "variable",
subsets: ["latin"],
axes: ["wght", "slnt"], // Specify which axes to include
variableAxes: {
wght: [200, 800],
slnt: [-10, 0],
},
variable: "--font-inter-advanced",
});5. Custom CDN Configuration
// fonts.ts
import { Inter } from "angular-fonts/google";
// Use custom CDN for self-hosting
export const interCDN = Inter({
weights: [400, 700],
subsets: ["latin"],
cdn: {
cssUrl: "https://my-cdn.com/fonts/css2",
fontUrl: "https://my-cdn.com/fonts/files",
},
variable: "--font-inter-cdn",
});6. Advanced Retry & Error Handling
// fonts.ts
import { Inter } from "angular-fonts/google";
export const interResilient = Inter({
weights: [400, 700],
subsets: ["latin"],
retry: {
attempts: 5,
backoff: "exponential",
delay: 200,
timeout: 10000,
maxDelay: 5000,
},
onError: (error) => {
console.error("Font load failed:", error);
// Fallback to system font
},
onRetry: (attempt) => {
console.log(`Retry attempt ${attempt}`);
},
variable: "--font-inter-resilient",
});3. Tailwind CSS Integration
Tailwind v4 (CSS-first)
/* app/globals.css */
@import "tailwindcss";
@theme {
--font-family-sans: var(--font-inter), system-ui, sans-serif;
--font-family-mono: var(--font-roboto-mono), ui-monospace, monospace;
--font-family-custom: var(--font-custom), serif;
}Tailwind v3 (config file)
// tailwind.config.js
module.exports = {
theme: {
extend: {
fontFamily: {
sans: ["var(--font-inter)", ...defaultTheme.fontFamily.sans],
mono: ["var(--font-roboto-mono)", ...defaultTheme.fontFamily.mono],
custom: ["var(--font-custom)", "serif"],
},
},
},
};Vite Plugin (AnalogJS Support)
For projects using Vite or AnalogJS, use the Vite plugin for seamless font optimization.
Quick Start with Vite
// vite.config.ts
import { defineConfig } from "vite";
import angular from "@analogjs/vite-plugin-angular";
import { angularFontPlugin } from "angular-fonts/vite";
export default defineConfig({
plugins: [
angular(),
angularFontPlugin({
// All options are optional with smart defaults
injectHTML: true, // Auto-inject fonts into HTML (default: true)
injectTailwind: "v4", // Auto-inject Tailwind config (default: false)
}),
],
});Configuration Options
angularFontPlugin({
// Font file path (relative to Vite root)
// If not provided, auto-discovers in:
// - src/fonts.ts
// - src/app/fonts.ts
// - src/lib/fonts.ts
// - src/config/fonts.ts
fontsFile?: string;
// Output directory for fonts (default: "dist/assets")
outputDir?: string;
// Generate preload links file (default: true)
injectPreloads?: boolean;
// Generate CSS file (default: true)
injectCSS?: boolean;
// Enable font subsetting (default: true)
subsetting?: boolean;
// Auto-inject font CSS and preloads into HTML (default: true)
// Set to false to disable HTML injection entirely
injectHTML?: boolean;
// Path to index.html (relative to Vite root)
// If not provided, looks in src/index.html
// Set to false to disable HTML processing
indexHtml?: string | false;
// Tailwind integration
// - false: No Tailwind injection (default)
// - 'v3': Inject into tailwind.config.js
// - 'v4': Inject @theme into styles file
// - true: Auto-detect version (defaults to v4)
injectTailwind?: boolean | "v3" | "v4";
// Path to main styles file (relative to Vite root)
// Used for Tailwind v4 injection
// Auto-discovers: styles.css, styles.scss, global.css, etc.
stylesFile?: string;
// Path to Tailwind config (relative to Vite root)
// Used for Tailwind v3 injection
// Auto-discovers: tailwind.config.{js,ts,cjs,mjs}
tailwindFile?: string;
});How It Works
The Vite plugin provides automatic:
- Font File Discovery: Checks 4 common locations for
fonts.ts - HTML Injection: Automatically injects font CSS and preload links into
index.htmlusing idempotent markers (won't duplicate on hot reload) - Tailwind Integration: Injects CSS variables into your Tailwind config (v3 or v4)
- CSS Variables: Generates
:rootCSS variables for all fonts - Build Optimization: Processes fonts during Vite's build phase
Example with Full Configuration
// vite.config.ts
import { defineConfig } from "vite";
import angular from "@analogjs/vite-plugin-angular";
import { angularFontPlugin } from "angular-fonts/vite";
export default defineConfig({
plugins: [
angular(),
angularFontPlugin({
// Custom font file location
fontsFile: "src/config/fonts.ts",
// Custom HTML file
indexHtml: "src/index.html",
// Enable Tailwind v4 injection
injectTailwind: "v4",
stylesFile: "src/styles.css",
// Customize output
outputDir: "public/assets",
// Enable all optimizations
subsetting: true,
injectPreloads: true,
injectCSS: true,
injectHTML: true,
}),
],
});Minimal Configuration (Uses Defaults)
// vite.config.ts
import { defineConfig } from "vite";
import angular from "@analogjs/vite-plugin-angular";
import { angularFontPlugin } from "angular-fonts/vite";
export default defineConfig({
plugins: [
angular(),
angularFontPlugin(), // That's it! Auto-discovers everything
],
});The plugin will:
- ✅ Auto-discover
src/fonts.ts(or alternatives) - ✅ Auto-discover
src/index.html - ✅ Inject font CSS and preloads into HTML
- ✅ Generate optimized fonts in
dist/assets
Differences from Angular CLI Builder
| Feature | Angular CLI Builder | Vite Plugin |
| ------------------ | ------------------- | --------------------- |
| Font Discovery | 4 locations checked | 4 locations checked |
| HTML Injection | ✅ Automatic | ✅ Automatic |
| Tailwind v4 | ✅ Supported | ✅ Supported |
| Tailwind v3 | ✅ Supported | ✅ Supported |
| CSS Variables | ✅ Generated | ✅ Generated |
| Preload Links | ✅ Injected | ✅ Injected |
| Configuration | angular.json | vite.config.ts |
| Hot Reload | ❌ | ✅ Idempotent markers |
| Build Tool | Angular CLI | Vite |
Idempotent Injection
The Vite plugin uses HTML comment markers to prevent duplicate injections during hot reloads:
<head>
<!-- Font CSS -->
<link rel="stylesheet" href="assets/fonts.css" />
<!-- End Font CSS -->
<!-- Font Preloads -->
<link
rel="preload"
href="assets/fonts/inter-400.woff2"
as="font"
type="font/woff2"
crossorigin
/>
<!-- End Font Preloads -->
</head>Running the plugin again will replace the content between markers, not add duplicates.
Disable Features Selectively
// Disable HTML injection (manual control)
angularFontPlugin({
injectHTML: false,
// Fonts still optimized, but you manually add to HTML
});
// Disable Tailwind (use manual CSS variables)
angularFontPlugin({
injectTailwind: false,
// CSS variables still generated in fonts.css
});
// Minimal plugin (just optimize fonts)
angularFontPlugin({
injectHTML: false,
injectTailwind: false,
// Just generates fonts.css and font files
});Build-time Optimization
For optimal performance, use the Angular CLI builder to optimize fonts at build time.
Convention: Single Font Declaration File
The font scanner looks for a single fonts.ts file where all fonts are declared. This approach is:
- ⚡️ Faster: Scans one file instead of entire project
- 📝 Explicit: Clear where fonts are declared
- 🎯 Organized: All font configuration in one place
Default locations checked (in order):
src/fonts.tssrc/app/fonts.tssrc/lib/fonts.tssrc/config/fonts.ts
See examples/fonts.ts.example for a complete example.
1. Configure angular.json
{
"projects": {
"my-app": {
"architect": {
"font-optimize": {
"builder": "angular-fonts:optimize",
"options": {
"outputPath": "public",
"projectRoot": "",
"sourceRoot": "src",
"fontFile": "src/fonts.ts",
"injectTailwind": "v4"
}
}
}
}
}
}If fontFile is not specified, the builder will search for fonts.ts in the default locations above.
2. Run build
ng buildThe builder will:
- Scan your
fonts.tsfile for font declarations - Download Google Fonts and copy local fonts to
assets/fonts/ - Generate optimized CSS with local font paths
- Create preload links for critical fonts
Runtime Usage
For dynamic font loading, use the services:
Google Fonts Service
import { Component, inject } from "@angular/core";
import { GoogleFontService } from "angular-fonts/google";
@Component({
selector: "app-dynamic",
template: `
<div [class]="font().className" [style]="font().style">
Dynamic font loading
</div>
`,
})
export class DynamicComponent {
private fontService = inject(GoogleFontService);
font = this.fontService.loadFont("Inter", {
weights: [400, 700],
subsets: ["latin"],
});
}Local Fonts Service
import { Component, inject } from "@angular/core";
import { LocalFontService } from "angular-fonts/local";
@Component({
selector: "app-local",
template: `
<div [class]="font().className" [style]="font().style">Local font</div>
`,
})
export class LocalComponent {
private fontService = inject(LocalFontService);
font = this.fontService.loadFont({
src: "./fonts/my-font.woff2",
variable: "--font-local",
});
}API Reference
Google Font Options
interface GoogleFontOptions {
weights?: number[] | "variable"; // Font weights (e.g., [400, 700] or "variable")
subsets?: string[]; // Font subsets (e.g., ['latin', 'latin-ext'])
styles?: string[]; // Font styles (e.g., ['normal', 'italic'])
display?: FontDisplay; // Font display strategy ('swap', 'block', 'fallback', 'optional')
preload?: boolean; // Whether to preload the font (default: true)
fallback?: string[]; // Fallback fonts (e.g., ['system-ui', 'sans-serif'])
adjustFontFallback?: boolean; // Generate fallback @font-face with metrics (default: true)
variable?: string; // CSS variable name for Tailwind (e.g., '--font-inter')
axes?: string[]; // Variable font axes (e.g., ['wght', 'ital'])
// Advanced features
subset?: FontSubsetting; // Font subsetting configuration
variableAxes?: VariableFontAxes; // Custom variable font axes ranges
cdn?: CDNConfig; // Custom CDN configuration
retry?: RetryStrategy; // Retry strategy for network requests
onError?: (error: Error) => void; // Error callback
onRetry?: (attempt: number) => void; // Retry callback
}
interface FontSubsetting {
text?: string; // Specific text/characters to include (e.g., "Hello World 123")
unicodeRange?: string; // Custom unicode range (e.g., "U+0020-007F")
}
interface VariableFontAxes {
wght?: [number, number]; // Weight axis range [min, max]
slnt?: [number, number]; // Slant axis range [min, max]
wdth?: [number, number]; // Width axis range [min, max]
[axis: string]: [number, number] | undefined; // Custom axes (e.g., GRAD, opsz)
}
interface CDNConfig {
cssUrl?: string; // Base URL for CSS files (default: 'https://fonts.googleapis.com/css2')
fontUrl?: string; // Base URL for font files (default: 'https://fonts.gstatic.com')
}
interface RetryStrategy {
attempts?: number; // Number of retry attempts (default: 3)
backoff?: "linear" | "exponential"; // Backoff strategy (default: 'exponential')
delay?: number; // Initial delay in milliseconds (default: 100)
timeout?: number; // Request timeout in milliseconds (default: 5000)
maxDelay?: number; // Maximum delay in milliseconds (default: 5000)
}Note: adjustFontFallback is enabled by default and automatically generates fallback font metrics to reduce layout shift during font loading.
Local Font Options
interface LocalFontOptions {
src:
| string
| Array<{
// Font source(s)
path: string;
weight?: string;
style?: string;
}>;
display?: FontDisplay; // Font display strategy ('swap', 'block', 'fallback', 'optional')
weight?: string; // Font weight
style?: string; // Font style
variable?: string; // CSS variable name for Tailwind (e.g., '--font-rubik')
preload?: boolean; // Whether to preload (default: true)
fallback?: string[]; // Fallback fonts (e.g., ['system-ui', 'sans-serif'])
adjustFontFallback?: "Arial" | "Times New Roman" | "Courier New" | false; // Generate fallback @font-face with metrics (default: auto-detected)
declarations?: Array<{
// Custom CSS declarations
prop: string;
value: string;
}>;
// Advanced features
subset?: FontSubsetting; // Font subsetting configuration (requires fontkit)
retry?: RetryStrategy; // Retry strategy for file operations
onError?: (error: Error) => void; // Error callback
onRetry?: (attempt: number) => void; // Retry callback
fallbackFont?: string; // Fallback font to use on error (default: 'system-ui')
}Note: adjustFontFallback for local fonts:
- Default: Auto-detected based on font family name (sans-serif → Arial, serif → Times New Roman, mono → Courier New)
- Explicit: Specify
"Arial","Times New Roman", or"Courier New"to override auto-detection - Disabled: Set to
falseto skip fallback generation
Font Result
interface FontResult {
className: string; // CSS class name
style: {
// Inline style object
fontFamily: string;
fontWeight?: number;
fontStyle?: string;
};
variable?: string; // CSS variable for Tailwind
}Recent Improvements
- ✅ Font subsetting - Reduce file sizes by 80-90% with text/unicode range subsetting
- ✅ Variable font optimization - Full support for variable font axes (wght, slnt, wdth, custom)
- ✅ Custom CDN support - Self-host fonts on your own CDN infrastructure
- ✅ Advanced retry logic - Configurable retry strategies with exponential backoff and callbacks
- ✅ Automatic fallback metrics - Generates fallback @font-face declarations for both Google and local fonts to reduce CLS
- ✅ Local font fallback support - Auto-detects font category (sans/serif/mono) for optimal fallback selection
- ✅ Single font file scanning - Faster builds, explicit configuration
- ✅ 1000+ Google Fonts support - All fonts available via
font-data.json - ✅ Better error messages - Helpful errors showing available options
- ✅ Network retry logic - Automatic retry with exponential backoff
- ✅ Improved font axes - Uses metadata for accurate weight ranges
- ✅ Better variant sorting - Handles complex "ital,wght" formats
- ✅ Build-time optimization - Fonts downloaded and self-hosted during build
- ✅ Browser-safe bundling - Build-time code separated from browser code to avoid Node.js dependencies in bundles
- ✅ Helper utilities - COMMON_CHARACTER_SETS and subsetting helpers for easier font optimization
Available Google Fonts
1000+ Google Fonts are available as individual functions, automatically generated from the latest Google Fonts metadata:
import {
Inter,
Roboto,
Roboto_Mono,
Open_Sans,
Source_Sans_Pro,
Lato,
Montserrat,
Poppins,
Nunito,
Merriweather,
Playfair_Display,
Oswald,
Raleway,
Ubuntu,
Crimson_Text,
Fira_Sans,
PT_Sans,
PT_Serif,
Droid_Sans,
Droid_Serif,
Lora,
Libre_Baskerville,
Cabin,
Arimo,
Titillium_Web,
Work_Sans,
Cormorant_Garamond,
Libre_Franklin,
Encode_Sans,
IBM_Plex_Sans,
IBM_Plex_Serif,
IBM_Plex_Mono,
Space_Mono,
Inconsolata,
Fira_Code,
JetBrains_Mono,
Source_Code_Pro,
Cascadia_Code,
Victor_Mono,
Recursive,
Fraunces,
Bitter,
Crimson_Pro,
Literata,
Chivo,
Spectral,
Karla,
Rubik,
Quicksand,
Maven_Pro,
Exo_2,
Orbitron,
Rajdhani,
Righteous,
Bangers,
Fredoka_One,
Comfortaa,
Varela_Round,
Nunito_Sans,
Source_Sans_3,
Noto_Sans,
Noto_Serif,
// ... and many more!
} from "angular-fonts/google";Fallback Font Metrics (Zero Layout Shift)
This package automatically generates fallback font metrics to reduce Cumulative Layout Shift (CLS) during font loading. Both Google Fonts and local fonts support automatic fallback generation with size-adjust properties that make system fonts match your web font dimensions.
How it works
For each font (Google or local), the package:
- Analyzes the font family to determine the best fallback (Arial, Times New Roman, or Courier New)
- Generates a fallback
@font-facewith override metrics - Injects it into your
fonts.cssautomatically
Font Detection:
- Sans-serif fonts (Inter, Roboto, Open Sans, Rubik, etc.) → Arial fallback
- Serif fonts (Playfair Display, Merriweather, etc.) → Times New Roman fallback
- Monospace fonts (Fira Code, JetBrains Mono, etc.) → Courier New fallback
Example output
/* Your main font */
@font-face {
font-family: "Inter";
src: url(/assets/fonts/inter/...) format("woff2");
}
/* Automatically generated fallback */
@font-face {
font-family: "Inter Fallback";
src: local("Arial");
ascent-override: 90%;
descent-override: 22%;
line-gap-override: 0%;
size-adjust: 100%;
}Configuration
Fallback metrics are enabled by default for both Google and local fonts.
Google Fonts:
export const inter = Inter({
subsets: ["latin"],
weights: [400, 700],
adjustFontFallback: false, // Disable fallback metrics
});Local Fonts:
export const rubik = localFont({
src: "./fonts/Rubik-Regular.ttf",
// Auto-detected as sans-serif → uses Arial fallback
});
export const customSerif = localFont({
src: "./fonts/MySerif.ttf",
adjustFontFallback: "Times New Roman", // Explicitly specify fallback
});
export const noFallback = localFont({
src: "./fonts/Special.woff2",
adjustFontFallback: false, // Disable fallback metrics
});Using the fallback
In your CSS or Tailwind config, reference the fallback font:
.font-inter {
font-family: "Inter", "Inter Fallback", system-ui, sans-serif;
}This ensures the fallback font is used while the web font loads, minimizing layout shift.
Helper Utilities
Common Character Sets
For font subsetting, use predefined character sets:
import { COMMON_CHARACTER_SETS } from "angular-fonts/google";
// Basic Latin characters (A-Z, a-z, 0-9, basic punctuation)
COMMON_CHARACTER_SETS.basicLatin;
// "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 .,!?;:"
// Extended Latin with accents
COMMON_CHARACTER_SETS.latinExtended;
// "ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿ"
// Numbers and common symbols
COMMON_CHARACTER_SETS.numbers;
// "0123456789+-=()[]{}.,!?;:'\"@#$%^&*"
// Common punctuation
COMMON_CHARACTER_SETS.punctuation;
// ".,!?;:'\"()[]{}/\\-_=+*&^%$#@~`|<>"Subsetting Helpers
import { extractUniqueCharacters } from "angular-fonts/google";
// Extract unique characters from text
const uniqueChars = extractUniqueCharacters("Hello World!");
// "Helo Wrd!"
// Use in font subsetting
export const interUnique = Inter({
weights: [400, 700],
subsets: ["latin"],
subset: {
text: extractUniqueCharacters("Your specific text here"),
},
variable: "--font-inter-unique",
});Performance Tips
- Use build-time optimization for production builds
- Preload critical fonts by setting
preload: true - Use CSS variables for Tailwind integration
- Limit font weights to only what you need
- Use font subsets to reduce file sizes by 80-90%
- Enable fallback metrics (default) to reduce layout shift
- Use variable fonts when possible for better performance
- Configure retry strategies for network resilience
- Self-host fonts with custom CDN for faster delivery
- Subset fonts using
COMMON_CHARACTER_SETSfor common use cases
Troubleshooting
Font not loading
- Check that the font name is correct
- Verify network connectivity for Google Fonts
- Ensure local font files exist and are accessible
SSR issues
- Make sure
@angular/ssris properly configured - Check that font preloads are injected in server.ts
- Verify font CSS is included in SSR output
Tailwind not working
- Ensure CSS variables are added to your root element
- Check Tailwind configuration includes the font variables
- Verify font functions return the
variableproperty
Testing
This package includes a comprehensive test suite with 81+ tests covering core functionality.
Run Tests
# Run all tests
pnpm test
# Run with coverage report
pnpm test:coverage
# Run in watch mode
pnpm test:watch
# Run only unit tests
pnpm test:unit
# Run only integration tests
pnpm test:integrationTest Coverage
- Core utilities: 90% coverage
- Google Fonts utils: 76-100% coverage
- Overall: 32% coverage (target: 80%)
See TESTING.md for detailed testing documentation.
CI/CD
Automated tests run on every push via GitHub Actions:
- Tests on Node.js 18.x and 20.x
- Coverage reports uploaded to Codecov
- Build verification
Development
Building the Package
# Build the package
pnpm build
# Build with font generation (automatic)
pnpm prebuild && pnpm buildThe build process automatically:
- Generates font exports from
font-data.json(1890+ fonts) - Compiles TypeScript to JavaScript
- Creates type definitions
Updating Google Fonts
When Google Fonts metadata is updated:
- Update
src/google/font-data.jsonwith new font metadata - Run
pnpm generate:fontsto regenerate exports - All new fonts are immediately available for import
# Manually regenerate font exports
pnpm generate:fontsThis creates ~3800 lines of TypeScript exports in src/google/fonts.ts:
export const Inter = fontFunctions.Inter;
export const Roboto_Mono = fontFunctions["Roboto_Mono"];
// ... 1890+ more fontsSee scripts/README.md for details on the generation process.
Contributing
Contributions are welcome! Please read our contributing guide for details.
When submitting PRs:
- Add tests for new functionality
- Ensure all tests pass:
pnpm test - Maintain or improve coverage:
pnpm test:coverage - Follow existing code style
- If adding fonts, run
pnpm generate:fontsto update exports
License
MIT License - see LICENSE for details.
