cn-font-split

repository·release·Indexed 22 days ago

https://github.com/konghayao/cn-font-split

A high-performance font subsetter for CJK and other characters, supporting otf, ttf, and woff2 formats. It leverages Rust and WebAssembly to provide multi-threaded splitting for precise package size control. The project includes a JavaScript library with automatic runtime detection (Node.js, Bun, Deno), a Python beta CLI, and supporting tools such as cn-font-replacer for dynamic font loading, cn-font-metrics for reducing Cumulative Layout Shift (CLS), and a font-to-SVG renderer.

Tokens
21.6K
Snippets
56
Records
129
Agent score
76%

What's inside cn-font-split

  1. Overview of the cn-font-split FFI build project

    release
    The ffi package is a dedicated project for building Foreign Function Interface (FFI) binary artifacts for cn-font-split. Its primary goal is to produce multi-platform binaries that are uploaded to GitHub Releases to ensure high execution efficiency across various environments.
  2. Overview of cn-font-split

    release

    cn-font-split is a high-performance font subsetting tool used by the Chinese Web Font Project. It is designed to split massive font files into smaller, web-optimized chunks for efficient distribution.

    Key features include:

    • High Performance: Implemented via WebAssembly or Rust FFI, achieving sub-second build times (e.g., 2MB font in ~50ms).
    • Cross-Platform: Runs in Browsers, WASI, Linux, macOS, and Windows. Compatible with Node.js, Deno, Bun, and Python.
    • Broad Language Support: While optimized for Chinese, it intelligently subsets any characters present in the font, including Japanese, Korean, Arabic, and minority languages.
    • Advanced Capabilities: Supports OTF formats, complex glyph rendering, variable fonts (automatic weight recognition), and font preview image generation.
    • Consistency: Guarantees identical output across all platforms.
  3. Implement Minimalist Optimization (Subsets)

    release

    For high-performance needs (like landing pages), use "Minimalist Optimization". This mode scans your source files to collect only the characters actually used in your code, resulting in much smaller font files (approx. 10% of full size).

    1. Configure scanning: Add scanFiles to the plugin options in your bundler config.
    2. Import with query: Append ?subsets to your font import statement.

    Scoped Subsets (using key)

    You can define multiple subsets by providing an object to scanFiles. Use the key query parameter in your import to specify which subset to load.

    Example: import { css } from 'font.ttf?subsets&key=subset-1'

    // vite.config.js configuration for subsets
    import Font from 'vite-plugin-font';
    
    // Single scan scope
    Font.vite({
        scanFiles: ['src/**/*.{vue,ts,tsx,js,jsx}'],
    });
    
    // Multiple scoped subsets
    Font.vite({
        scanFiles: {
            default: ['src/**/*.{json,js,jsx,ts,tsx,vue}'],
            'subset-1': ['example/**/*.{json,js,jsx,ts,tsx,vue}'],
        },
    });
    
    // Usage in component
    import { css } from '../../demo/public/SmileySans-Oblique.ttf?subsets&key=subset-1';
  4. Generate a 10s expiring token

    release

    The server uses a time-based token algorithm for authentication. Tokens expire every 10 seconds. To generate a valid token, compute the SHA256 hash of the token string concatenated with the current Unix timestamp divided by 10,000 (floored).

    Algorithm logic: sha256(token + Math.floor(Date.now()/10000))

    // 10s 过期的 token
    sha256(token + Math.floor(Date.now()/10000))
  5. Understand the cn-font-split architecture

    release

    The cn-font-split system is organized into three distinct layers that separate core logic from communication and external interfaces:

    1. Core Layer (core): Handles the actual font subsetting operations. It utilizes harfbuzz and opentype libraries for high-performance font manipulation. The core logic consists of:
      • pre_subset: Pre-processes font data and optimizes multi-language subsetting to determine characters.
      • run_subset: Manages large-scale batch subsetting operations.
      • link_subset: Links, integrates, and reports the subsetted font data to generate final results.
    2. Message Channel Layer (message_channel): Acts as the bridge for external interaction using Protocol Buffers (protobuf). Definitions are managed via the cn-font-proto library. Data is exchanged either via generated protobuf structs (for Rust-to-Rust communication) or via binary data (for cross-language communication).
    3. Wrapper Layer (wrapper): Provides the public interfaces for different deployment scenarios and programming languages.
  6. Follow naming conventions for Rust development

    release

    When contributing to or developing with the Rust components of cn-font-split, adhere to these naming rules:

    1. Code Style: Use snake_case for Rust projects (standard IDE linting will assist with this).
    2. Package Naming: Use hyphens (-) to separate words in package names instead of underscores (_).
  7. Install vite-plugin-font

    release

    Install vite-plugin-font as a development dependency. If you are in mainland China, you should set the CN_FONT_SPLIT_GH_HOST environment variable to ensure smooth installation from GitHub mirrors.

    Windows (Command Prompt):

    set CN_FONT_SPLIT_GH_HOST=https://ik.imagekit.io/github
    npm i -D vite-plugin-font

    Linux/macOS:

    export CN_FONT_SPLIT_GH_HOST=https://ik.imagekit.io/github
    npm i -D vite-plugin-font
    npm i -D vite-plugin-font