Skip to content

Performance Optimization

Info

This documentation is AI-generated. You can help improve it by submitting an Issue.

提示

If the issue remains unresolved, visit GitHub Issues to search or submit new feedback, or join QQ group 694413711 for community support.

Contributions to this tutorial are always welcome.

Using Pre-compressed Assets

The release packages come in three variants:

  • Default install packages:
    • File names: howiehz-higan-zh-hans.zip, howiehz-higan-en.zip
    • Includes: .br precompressed files actually present in the current build output, mainly .js, .css, .ttf, and .ico. For example, .js maps to .js.br
    • Best for: direct Halo CMS v2.24+ delivery[1]
  • Tiny install packages:
    • File names: howiehz-higan-zh-hans-tiny.zip, howiehz-higan-en-tiny.zip
    • Includes: no precompressed assets, removes the default font assets, replaces the default logo asset with a 1x1 placeholder image, and excludes Mermaid / instant.page runtime injection
    • Best for: smaller installs
  • Full precompressed packages:
    • File names: howiehz-higan-zh-hans-full-precompressed.zip, howiehz-higan-en-full-precompressed.zip
    • Includes: .gz / .br / .zst precompressed files actually present in the current build output, mainly .js, .css, .ttf, and .ico. For example, .js maps to .js.gz, .js.br, and .js.zst
    • Best for: reverse proxies, CDNs, object storage, or other self-managed static asset services
  • Compression levels:
    • *.gz — gzip (compression level 9, maximum)
    • *.br — brotli (compression level 11, maximum)
    • *.zst — zstandard (compression level 19, maximum[2])

Notes:

  • Current Halo CMS behavior keeps using the same precompressed variant after it has served one once, such as .br, until restart. If that file is later removed, Halo CMS does not switch to another variant automatically and may return 500 Internal Server Error instead. If you hit this after switching package variants, restart Halo CMS.

Thanks to nonzzz/vite-plugin-compression for creating this plugin.

Configuring the Server to Serve Pre-compressed Static Assets

When using the full precompressed packages behind reverse proxies, CDNs, object storage, or other self-managed static asset services, you can use precompressed files according to client support.

nginx Configuration (Full Precompressed Install Packages)

nginx
http {
    # Enable gzip_static module to serve pre-compressed .gz files
    gzip_static on;

    # Fall back to dynamic gzip compression if static file not found
    gzip on;
    gzip_types application/atom+xml application/javascript application/json application/vnd.api+json application/rss+xml application/vnd.ms-fontobject application/x-font-opentype application/x-font-truetype application/x-font-ttf application/x-javascript application/xhtml+xml application/xml font/eot font/opentype font/otf font/truetype image/svg+xml image/vnd.microsoft.icon image/x-icon image/x-win-bitmap text/css text/javascript text/plain text/xml;

    # Enable brotli_static to serve pre-compressed .br files
    # Requires ngx_brotli module: https://github.com/google/ngx_brotli
    brotli_static on;

    # Fall back to dynamic Brotli compression if static file not found
    brotli on;
    brotli_types application/atom+xml application/javascript application/json application/vnd.api+json application/rss+xml application/vnd.ms-fontobject application/x-font-opentype application/x-font-truetype application/x-font-ttf application/x-javascript application/xhtml+xml application/xml font/eot font/opentype font/otf font/truetype image/svg+xml image/vnd.microsoft.icon image/x-icon image/x-win-bitmap text/css text/javascript text/plain text/xml;

    # Enable zstd_static to serve pre-compressed .zst files
    # Requires zstd-nginx-module module: https://github.com/tokers/zstd-nginx-module
    zstd_static on;

    # Fall back to dynamic zstd compression if static file not found
    zstd on;
    zstd_types application/atom+xml application/javascript application/json application/vnd.api+json application/rss+xml application/vnd.ms-fontobject application/x-font-opentype application/x-font-truetype application/x-font-ttf application/x-javascript application/xhtml+xml application/xml font/eot font/opentype font/otf font/truetype image/svg+xml image/vnd.microsoft.icon image/x-icon image/x-win-bitmap text/css text/javascript text/plain text/xml;

    server {
        # ...
    }
}

Apache Configuration (Full Precompressed Install Packages)

apache
# Enable mod_deflate for fallback dynamic compression
<IfModule mod_deflate.c>
    AddOutputFilterByType DEFLATE application/atom+xml application/javascript application/json application/vnd.api+json application/rss+xml application/vnd.ms-fontobject application/x-font-opentype application/x-font-truetype application/x-font-ttf application/x-javascript application/xhtml+xml application/xml font/eot font/opentype font/otf font/truetype image/svg+xml image/vnd.microsoft.icon image/x-icon image/x-win-bitmap text/css text/javascript text/plain text/xml
</IfModule>

# Serve pre-compressed files
<IfModule mod_rewrite.c>
    RewriteEngine On

    # Serve .zst file if it exists and client supports zstd
    RewriteCond %{HTTP:Accept-Encoding} zstd
    RewriteCond %{REQUEST_FILENAME}.zst -f
    RewriteRule ^(.*)$ $1.zst [L]

    # Serve .br file if it exists and client supports brotli
    RewriteCond %{HTTP:Accept-Encoding} br
    RewriteCond %{REQUEST_FILENAME}.br -f
    RewriteRule ^(.*)$ $1.br [L]

    # Serve .gz file if it exists and client supports gzip
    RewriteCond %{HTTP:Accept-Encoding} gzip
    RewriteCond %{REQUEST_FILENAME}.gz -f
    RewriteRule ^(.*)$ $1.gz [L]
</IfModule>

# Set correct content-type and encoding headers
<FilesMatch "\.js\.gz$">
    Header set Content-Type "application/javascript"
    Header set Content-Encoding "gzip"
</FilesMatch>

<FilesMatch "\.js\.br$">
    Header set Content-Type "application/javascript"
    Header set Content-Encoding "br"
</FilesMatch>

<FilesMatch "\.js\.zst$">
    Header set Content-Type "application/javascript"
    Header set Content-Encoding "zstd"
</FilesMatch>

<FilesMatch "\.css\.gz$">
    Header set Content-Type "text/css"
    Header set Content-Encoding "gzip"
</FilesMatch>

<FilesMatch "\.css\.br$">
    Header set Content-Type "text/css"
    Header set Content-Encoding "br"
</FilesMatch>

<FilesMatch "\.css\.zst$">
    Header set Content-Type "text/css"
    Header set Content-Encoding "zstd"
</FilesMatch>

<FilesMatch "\.ttf\.gz$">
    Header set Content-Type "font/ttf"
    Header set Content-Encoding "gzip"
</FilesMatch>

<FilesMatch "\.ttf\.br$">
    Header set Content-Type "font/ttf"
    Header set Content-Encoding "br"
</FilesMatch>

<FilesMatch "\.ttf\.zst$">
    Header set Content-Type "font/ttf"
    Header set Content-Encoding "zstd"
</FilesMatch>

<FilesMatch "\.ico\.gz$">
    Header set Content-Type "image/x-icon"
    Header set Content-Encoding "gzip"
</FilesMatch>

<FilesMatch "\.ico\.br$">
    Header set Content-Type "image/x-icon"
    Header set Content-Encoding "br"
</FilesMatch>

<FilesMatch "\.ico\.zst$">
    Header set Content-Type "image/x-icon"
    Header set Content-Encoding "zstd"
</FilesMatch>

Important Notes

This theme has been optimized with code splitting, reduced external dependencies, and minimized single-page resource sizes. Please note the following during use:

  1. Avoid referencing extremely slow resources: such as huge images or public CDN resources with poor accessibility.
  2. Deploy CDN when possible: Personal sites are limited by bandwidth and server performance. Using CDN for static resources can significantly improve loading speed.
  3. Use modern image formats: such as WebP and AVIF, which can reduce image size while maintaining equivalent image quality.
  4. Use modern font formats: When using custom fonts, prioritize the woff2 format, which offers significant improvements in file size and loading performance compared to woff and ttf. This theme supports configurable font subsetting for optimal on-demand loading; consider using the online font subsetter for preparation.

  1. Halo CMS v2.24+ prefers .gz over .br when both are present[3], so the default packages keep only .br to prefer the smaller precompressed asset when serving directly from Halo CMS. ↩︎

  2. HTTP zstd caps Window_Size at 8 MB, so the highest usable compression level is 19. See RFC 9659 Section 3 and RFC 9659 Section 5.1. ↩︎

  3. Since Spring Framework v7.0.7 / v6.2.18, precompressed resource selection has changed from the built-in default order .br -> .gz to Accept-Encoding order. As a result, when .br and .gz both exist, common browser requests usually hit .gz first. Related issue: https://github.com/spring-projects/spring-framework/issues/36507 ↩︎

Released under MIT License