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 🙏

© 2024 – Pkg Stats / Ryan Hefner

@sumotto/gulp-local-fonts

v1.5.0

Published

Loads fonts from Google Fonts CSS or locally CSS based on JSON file

Downloads

269

Readme

Local Fonts

Loads fonts from Google Fonts CSS or locally CSS based on JSON file.

Installation

You can install the package as follows:

npm install @sumotto/gulp-local-fonts --save-dev

# or

yarn add @sumotto/gulp-local-fonts --dev

Usage

const { src, dest, task } = require('gulp');
const localFonts = require('@sumotto/gulp-local-fonts');

task('fonts', function () {
  return src('./src/fonts.json')
    .pipe(localFonts())
    .pipe(dest('./dist/fonts/'));
});
import { src, dest, task } from 'gulp';
import localFonts from '@sumotto/gulp-local-fonts';

task('fonts', function () {
  return src('./src/fonts.json')
    .pipe(localFonts())
    .pipe(dest('./dist/fonts/'));
});

JSON file format sample

{
  "google": [
    "Roboto",
    "Open Sans",
    "Lato:100,100i,300,300i,400,400i,700,700i,900,900i"
  ],
  "local": [
    "fonts/fonts.css"
  ]
}

Options

task('fonts', function () {
  return src('./src/fonts.json')
    .pipe(localFonts({
      cache: true,
      google: {
        url: 'https://fonts.googleapis.com/css',
        display: 'swap',
        text: 'abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789,.!?&%$#@;:/|\'"`^{}[]()<>+=*~',
        subset: false,
        effect: false,
      },
      cssTransform: false,
      nodeFetchOptions: {
        headers: {
          'User-Agent':
            'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36',
        },
      },
      createdJsFiles: true,
      jsTransform: false,
    }))
    .pipe(dest('./dist/fonts/'));
});

cache

Type: boolean
Default: true

If true, then the files are collected and written to the cache, and on next runs of the Gulp task the JSON has not changed, the files will be taken from the cache, if the JSON has changed the files will be re-generated.

If false files will be generated every time the Gulp task is run.

google

Type: object

The parameters correspond to the Google Fonts API.

url

Type: string
Default: https://fonts.googleapis.com/css

display

Type: string | string[]
Default: swap

text

Type: string | false
Default: abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789,.!?&%$#@;:/|\'"`^{}[]()<>+=*~

subset

Type: string | false
Default: false

effect

Type: string | false
Default: false

cssTransform

Type: Function<(css: string) => string> | false
Default: false

You can pass some function that will receive the generated CSS as input, you can change it and return it. For example, use the CSSO CSS minifier.

import { minify } from 'csso'; // npm install csso

task('fonts', function () {
  return src('./src/fonts.json')
    .pipe(localFonts({
      cssTransform: ({ css }) => minify(css).css,
    }))
    .pipe(dest('./dist/fonts/'));
});

nodeFetchOptions

Type: object
Default:

{
  headers: {
    'User-Agent':
    'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36',
  },
}

The parameters correspond to the Node Fetch Options.

createdJsFiles

Type: boolean
Default: true

Determines if additional JS files need to be generated. These files are described below.

jsTransform

Type: Function<(js: string, fileName: string, css: string) => string> | false
Default: false

You can pass some function that will receive the generated JS as input, you can change it and return it. This function will be applied to all JS files separately. Additionally, the function receives the file name as the second parameter, and the generated css as the third. For example, use the Terser.

import { minify } from 'terser'; // npm install terser

task('fonts', function () {
  return src('./src/fonts.json')
    .pipe(localFonts({
      jsTransform: async ({ js }) => ( await minify(js, { module: true }) ).code,
    }))
    .pipe(dest('./dist/fonts/'));
});

Output JS files

fonts.js

Contains an object with font data.

Example:

export default {
  "barlow-100-italic": [
    "Barlow",
    "local('Barlow Thin Italic'), url(Barlow-ThinItalic.woff2) format('woff2')",
    { "style": "italic", "weight": 100, "display": "swap" },
  ],
  "barlow-800-normal": [
    "Barlow",
    "local('Barlow ExtraBold'), url(Barlow-ExtraBold.woff2) format('woff2')",
    { "style": "normal", "weight": 800, "display": "swap" },
  ],
}

Used in fonts-classes.js, fonts-load.js and fonts-preloader-main.js.

fonts-classes.js

Handles font load events and sets classes on . Class format: font-{fontFamily}-{fontWeight}-{fontStyle}-{done|error}

Using in HTML


<script src="fonts-classes.js" type="module" async></script>

fonts-get-format-from-font-data.js

Gets the font format based on its data.

Used in fonts-preloader-main.js.

fonts-get-key-from-font-face.js

Gets the font key based on its data.

Used in fonts-classes.js and fonts-preloader-main.js.

fonts-get-src-from-font-data.js

Gets the SRC of a font based on its data.

Used in fonts-preloader-main.js.

fonts-load.js

Loads fonts without using the fonts.css file.

Using in HTML


<script src="fonts-load.js" type="module" async></script>

fonts-preloader-main.js

If you use different fonts on different pages, or some of them do not use all font options, and you want to load preload fonts. Then you can send a list of fonts needed for the initial page of a particular page. You will need to write a server script that will take an array of fonts and save them to the server for each page.

Using


<script src="fonts-preloader-main.js" data-fonts-preloader-fetch-url="url-to-save-data" type="module" async></script>

A POST request ('Content-Type': 'application/json;charset=utf-8') with font data, will be sent to the URL specified in data-fonts-preloader-fetch-url.

{
  "fonts": [
    {
      "src": "Barlow-ThinItalic.woff2",
      "type": "woff2"
    }
  ]
}

fonts-preloader-worker.js

A worker that sends font data to the endpoint.

Used in fonts-preloader-main.js.

Using in WordPress

Class contains the operation logic for connecting and saving data for the preloader. It is calculated that your fonts are in the child theme in the "fonts" folder.

class-theme-fonts.php

<?php
class Theme_Fonts {
	protected const META_KEY       = '_theme_preload_fonts';
	protected const REST_NAMESPACE = '/theme/v1/';
	protected const REST_ROUTE     = 'fonts-preloader/';

	protected static array $preload_fonts = array();
	protected static array $preload_js    = array(
		'fonts-classes.js',
		'fonts.js',
		'fonts-get-key-from-font-data.js',
	);

	public static function init( $type ) : void {
		if ( 'css' === $type ) {
			add_action(
				'wp_head',
				array( static::class, 'add_fonts_css' ),
				- 10
			);
		} else {
			array_unshift( static::$preload_js, 'fonts-load.js' );
			add_action(
				'wp_head',
				array( static::class, 'add_fonts_js' ),
				- 10
			);
		}

		add_action(
			'wp',
			array( static::class, 'set_preload_fonts' ),
		);
		add_action(
			'wp',
			array( static::class, 'the_preload_headers' ),
			11
		);
		add_action(
			'wp_head',
			array( static::class, 'the_preload_links' ),
			- 20
		);
		add_action(
			'rest_api_init',
			array( static::class, 'registration_rest_routes' )
		);
	}

	public static function add_fonts_js() : void {
		$font_dir   = get_stylesheet_directory() . '/fonts/';
		$js_content = WLD_Filesystem::get_file_contents( $font_dir . 'fonts.js' );
		if ( $js_content ) {
			static::the_classes_script();
			printf(
				'<script src="%s" id="theme-fonts-load-js" type="module" async></script>',
				esc_url( static::get_url( 'fonts-load.js' ) )
			);
			static::the_save_preload_script();
		}
	}

	public static function add_fonts_css() : void {
		$font_dir    = get_stylesheet_directory() . '/fonts/';
		$css_content = WLD_Filesystem::get_file_contents( $font_dir . 'fonts.css' );
		if ( $css_content ) {
			$font_url = static::get_url();
			static::the_classes_script();
			printf(
				'<style id="theme-fonts-css">%s</style>',
				str_replace(
					'url(',
					'url(' . esc_url( $font_url ),
					$css_content
				)
			);
			static::the_save_preload_script();
		}
	}

	public static function set_preload_fonts() : void {
		$preload_fonts = get_post_meta( get_the_ID(), static::META_KEY, true );
		if ( is_array( $preload_fonts ) ) {
			static::$preload_fonts = $preload_fonts;
		}
	}

	public static function the_preload_links() : void {
		if ( static::$preload_js ) {
			foreach ( static::$preload_js as $js ) {
				echo sprintf(
					'<link rel="preload" href="%s" as="script" crossorigin>',
					esc_url( static::get_url( $js ) ),
				);
			}
		}
		if ( static::$preload_fonts ) {
			foreach ( static::$preload_fonts as $font ) {
				echo sprintf(
					'<link rel="preload" href="%s" as="font" type="%s" crossorigin>',
					esc_url( static::get_url( $font['src'] ) ),
					esc_attr( 'font/' . $font['type'] )
				);
			}
		}
	}

	public static function the_preload_headers() : void {
		if ( wp_doing_ajax() ) {
			return;
		}

		if ( static::$preload_js ) {
			foreach ( static::$preload_js as $js ) {
				header(
					sprintf(
						'Link: <%s>; rel=preload; as=script; crossorigin"',
						esc_url_raw( static::get_url( $js ) ),
					),
					false
				);
			}
		}
		if ( static::$preload_fonts ) {
			foreach ( static::$preload_fonts as $font ) {
				header(
					sprintf(
						'Link: <%s>; rel=preload; as=font; type="%s"; crossorigin"',
						esc_url_raw( static::get_url( $font['src'] ) ),
						'font/' . $font['type']
					),
					false
				);
			}
		}
	}

	public static function save_preload_fonts( WP_REST_Request $request ) : WP_REST_Response {
		update_post_meta( $request['post_id'], static::META_KEY, $request['fonts'] );

		return new WP_REST_Response( 'Saved' );
	}

	public static function registration_rest_routes() : void {
		register_rest_route(
			static::REST_NAMESPACE,
			static::REST_ROUTE . '(?P<post_id>\d+)',
			array(
				'methods'             => 'POST',
				'callback'            => array( static::class, 'save_preload_fonts' ),
				'permission_callback' => static function () {
					return current_user_can( 'manage_options' );
				},
				'args'                => array(
					'fonts' => array(
						'type'        => 'array',
						'uniqueItems' => true,
						'items'       => array(
							'type'       => 'object',
							'properties' => array(
								'src'  => array(
									'type'    => 'string',
									'pattern' => '^[[:alnum:]-]+.(eot|svg|ttf|woff2?)$',
								),
								'type' => array(
									'type' => 'string',
									'enum' => array(
										'eot',
										'svg',
										'opentype',
										'truetype',
										'woff',
										'woff2',
									),
								),
							),
						),
						'required'    => true,
					),
				),
			)
		);
	}

	protected static function get_url( $file_name = '' ) : string {
		static $font_url;
		if ( null === $font_url ) {
			$font_url = get_stylesheet_directory_uri() . '/fonts/';
		}

		return $font_url . $file_name;
	}

	protected static function the_classes_script() : void {
		printf(
			'<script src="%s" id="theme-fonts-classes-js" type="module" async></script>',
			esc_url( static::get_url( 'fonts-classes.js' ) )
		);
	}

	protected static function the_save_preload_script() : void {
		if ( current_user_can( 'manage_options' ) ) {
			printf(
				'<script src="%s" data-fonts-preloader-fetch-url="%s" id="theme-fonts-preloader-main-js" type="module" async></script>',
				esc_url( static::get_url( 'fonts-preloader-main.js' ) ),
				esc_url(
					wp_nonce_url(
						get_rest_url(
							null,
							static::REST_NAMESPACE . static::REST_ROUTE . get_the_ID()
						),
						'wp_rest'
					)
				)
			);
		}
	}
}

functions.php

<?php
// Include a class file.
require get_stylesheet_directory() . '/inc/class-theme-fonts.php';

// Select the best option for you.
// Initialize with font connection via css.
Theme_Fonts::init( 'css' );

// Or initialize with font connection via js.
Theme_Fonts::init( 'js' );

License

MIT License