背景
现在很流行的服务端渲染(SSR),或者 JAMStack,都免不了要在服务器上做一些静态编译。如果我们编译的对象都只是纯粹的 JavaScript 和 CSS,那都不会有什么大问题。
但是有时候我们会希望渲染一些更丰富的内容,比如使用 puppeteer 将页面在服务端渲染成图片,又或者静态生成流程图。这时可能会遇到问题:
- 如果渲染成 SVG,那结果可能是框框的大小和字的大小不匹配,字会超出框框的范围,或者干脆被截断了;
- 如果渲染成位图,如 PNG,那结果很有可能是 CJK 的文字全部变成了框框,像这样:
□□
。
根本原因就是服务器一般是 Linux 系统,系统没有内置对应的字体,所以降级成了其他(丑陋的)字体。
所以,我们需要向服务端安装一个支持 CJK 的字体,然后再做构建。
安装字体
Google 一下,再看看 StackOverflow,就能找到答案了:
mkdir -p ~/.fonts
cp my-font.ttc ~/.fonts
fc-cache ~/.fonts
npm run build
这里的重点是把字体复制到 ~/.fonts
后,需要强制运行一下 fc-cache ~/.fonts
来刷新字体缓存。
选择字体
那么安装的字体如何选择呢?
最完美的方案当然是服务端和客户端使用同一种字体来做渲染,这就要求我们的客户端也要内置一份字体。
然而,CJK 的字符集太大,字体文件通常也特别大,所以一般网页都会优先使用系统内置的字体,CSS 如下:
body {
font-family: -apple-system,system-ui,BlinkMacSystemFont,"Segoe UI",...;
}
所以,从实践来看,服务端和客户端使用同一份字体并不现实。
那就退而求其次,找个开源的字体安装到服务器上。这里我选择了文泉驿,下载 wqy-zenhei.ttc
之后,内置到项目中,构建之前安装一下。
整合到 Gatsby
集成到一个 Gatsby 项目中,只需修改一下 package.json
中的 build 命令如下:
{
// ...
"scripts": {
// ...
"build": "mkdir -p ~/.fonts && cp assets/wqy-zenhei.ttc ~/.fonts && fc-cache ~/.fonts && gatsby build",
}
}