Chinese Font Project

cn-font-split User Guide

cn-font-split is a crucial component of the Chinese Web Font Project, enabling the deployment of Chinese fonts over the web. It divides the large Chinese font packages into smaller, easily deployable, on-demand loading chunks, creating a highly available web font solution.

cn-font-split boasts exceptional cross-platform capabilities. It can run in Node.js environments, Bun environments, Deno environments, the command line, and even in browser environments, with a unified and simple usage approach!

Since the syntax of JavaScript runtimes is quite similar, the following examples will use the Node.js environment.

Simple Usage in Node.js

  1. Install cn-font-split
npm i cn-font-split
npm i cn-font-split # or
  1. Write a JS script
// index.mjs
import fs from 'fs-extra';
import { fontSplit } from '../dist/index.js';
fontSplit({
    // This is the directory for the packaged output
    destFold: '../zh-cn/temp/node',
    // This is the original font package
    FontPath: '../demo/public/SmileySans-Oblique.ttf',
});
  1. Run the script
node index.mjs

Introduction to Generated Font Artifacts

  1. result.css
    1. The entry CSS file that the front-end code can directly reference.
  2. woff2 Font
    1. The core artifact, a font subpackage optimized by cn-font-split.
  3. index.html
    1. The test HTML file that is generated by default.
    2. An early test webpage file that allows you to see the effects of the packaging in detail through a port.
  4. preview.svg
    1. An image of the test font that is generated by default.
    2. You can use this image to get a simple idea of what the font looks like.
  5. reporter.json
    1. The report file from cn-font-split.
    2. It contains analysis and reference data on woff2.

Custom Configuration Properties

Key operations for generating artifacts can be achieved through corresponding configuration properties. Below are some examples based on specific needs.

  1. Force sub-packaging of certain characters

The default behavior of cn-font-split is to automatically sub-package all characters within the font. However, in special cases, you may want to sub-package only specific characters.

{
    // Disable automatic sub-packaging, so only the characters specified in subsets will be packaged.
    autoChunk: false,

    // Force sub-packaging, which takes precedence over automatic sub-packaging.
    subsets: [
        // This is a single package containing characters with unicode 31105 and 8413.
        [31105, 8413]
    ],
}

Typically, we operate with strings rather than unicode characters, so the following method is more appropriate.

{
    subsets: [
        '中文网字计划'
            .split('')
            .filter(Boolean)
            .map((i) => i.charCodeAt(0))
    ],
}
  1. Control the generated CSS file
{
    css: {
        // Change the font name referenced in the CSS
        fontFamily: '823746343',

        // FontWeight may not be required in some cases.
        fontWeight: false,

        // Do not declare local characters.
        localFamily: false,

        // Do not generate comments
        comment: false,
        // Uncomment for specific customization
        // comment: {
        //     base: false,
        //     nameTable: false,
        //     unicodes: true
        // }
    },
}
  1. Change the naming of packaged artifacts

Thanks to richex-cn for their assistance.

{
    renameOutputFont: '[hash:10][ext]', // Automatically truncates the hash length.
    renameOutputFont: '[index][ext]', // Uses an index instead of a hash.
    // Custom naming implementation
    renameOutputFont({ transferred, ext, index }) {
        const algorithm = 'sha256'
        const hash = crypto.createHash(algorithm).update(transferred).digest('hex');
        // return index.toString() + ext // Named by index.
        return hash.slice(0, 6) + ext; // Short hash naming.
    }
}
  1. Customize the test image for packaging
{
    previewImage: {
        /** Text to display in the image */
        text: 'Excellent Chinese Font',
        /** Filename for the preview image, no extension needed */
        name: 'Example'
    },
    // Do not generate
    // previewImage: false
}