WeChat Mini Programs Break Custom Chinese Fonts in Five Different Ways
Any Mini Program that needs a custom Chinese typeface will hit the same silent failures on real hardware. The developer tools paper over illegal URL schemes, missing font weights, and Canvas API mismatches, so a project that looks finished in the simulator ships broken to users.
A WeChat Mini Program called JuShi needed three custom Chinese fonts for its UI and poster export. The developer tools showed everything working, but real devices rendered system Heiti everywhere and threw a cascade of opaque errors. The root cause is a collision of five constraints: a 2MB main package limit, `loadFontFace` rejecting local paths, separate APIs for page text and Canvas text, CSS font-weight fallback behavior, and subpackage resource isolation. The only stable architecture splits the problem into two pipelines: Data URL or HTTPS for page rendering via `loadFontFace` with `webview` scope, and local files written to `USER_DATA` for Canvas 2D poster rendering via `canvas.loadFont`. A font subset encoded as base64 JSON in the main package provides immediate first-screen rendering, while a full woff downloaded over HTTPS later overwrites it. Every failure path needs an explicit fallback so the app never breaks, just degrades to system fonts.
The WeChat developer tools are dangerously permissive with local font paths, creating a systematic gap between simulator success and real-device failure that the official documentation does not warn about.
Chinese font loading in Mini Programs is not a single technical problem but a collision of five independent constraints—package size, URL scheme, dual APIs, CSS weight fallback, and subpackage isolation—that only surface together on hardware.
The architecture of splitting page rendering and poster rendering into two completely separate font pipelines is unintuitive but necessary because WeChat provides no unified custom font API across webview and Canvas contexts.
Free Chinese handwriting fonts almost never include a Bold weight, so the common CSS pattern of `font-weight: 700` on titles silently destroys the custom font without any console error.