配置 Vercel 优化大文件缓存性能

f8ef57b3b0e3c827d9f168f4a491ddc8

Excalidraw 是一个非常好用的手绘风格的绘图工具,我给自己部署了一个版本来降低自己写作配图的难度。如果你感兴趣,可以访问 draw.ixiqin.com 体验我自己维护的版本。

白宦成

在配置 Vercel 的中文字体以后出现了一个很大的问题:中文字体文件巨大。因为和英文只有 26 个字母不同,中文想要让常见文字都要放在其中,则需要一个巨大的字库来支持不同文字的展示。也因此使得中文字体远大于英文字体。即使不同的文件类型会有优化,但近 100 倍的文件大小差距还是会让整个应用加载速度极慢。

d2b5ca33bd970f64a6301fa75ae2eb22 14

不过,好在字体是一个相对稳定的文件, 不会经常变化,因此我们可以借助浏览器和 HTTP 协议中设计的缓存能力来优化体验。通过对较大的字体文件进行持久缓存,来确保非第一次加载后的使用体验。

Cache-Control

 Cache-Control 通用消息头字段,被用于在http请求和响应中,通过指定指令来实现缓存机制。缓存指令是单向的,这意味着在请求中设置的指令,不一定被包含在响应中。

想要实现对于文件的缓存控制,少不了使用 Cache Control 头来进行控制。以我为例,我为这些字体配置的 Cache Control 的值为 public, max-age=31536000, immutable,这意味着:

  1. 我的字体文件可以被人任意对象缓存(public):这样 Vercel 的 CDN、用户的浏览器都会帮助我将字体文件进行缓存,提升访问的体验。
  2. 我的字体文件要缓存 365 天(max-age=31536000):我的字体文件可以缓存一年(实际上更长都无所谓,因为字体不会经常变化)
  3. 不主动发起校验请求(immutable):如果浏览器支持,则在读到 immutable ,不会再向服务器发起校验请求头(比如 If-None-MatchIf-Modified-Since)。关于这个属性,可以参考 https://datatracker.ietf.org/doc/html/rfc8246

经过上述的配置,在标准的浏览器中,当他们处理到我的字体文件时,就会将字体文件进行缓存,留存至本地,并在用户显式清理缓存之前,始终使用缓存中的字体文件来进行加载,从减少需要从服务器端加载的文件的数量,提升网站的访问体验。

在 Vercel 中配置

在 Vercel 中如果需要控制不同的文件的 Header,则需要修改项目根目录下的 vercel.json 文件,在其中配置 headers ,匹配要处理的文件,并设置特定的 Header。

{
  "public": true,
  "headers": [
    {
      "source": "/(.*).(ttf|otf|woff2)",
      "headers": [
        {
          "key": "Cache-Control",
          "value": "public, max-age=31536000, immutable"
        }
      ]
    }
  ]
}
Code language: JSON / JSON with Comments (json)

具体代码可以参考:https://github.com/bestony/excalidraw/commit/50e48fd054ccb5fe6e8fe302d135e8f643ed20eb

为 Excalidraw 添加中文手写字体

9a1f326b911de6c1629837f3b57551e5

Excalidraw 是一个非常好用的手绘风格的绘图工具,我给自己部署了一个版本来降低自己写作配图的难度。如果你感兴趣,可以访问 draw.ixiqin.com 体验我自己维护的版本。

白宦成

我在使用 Excalidraw 时,最大的的问题就是没有中文的手写字体,这也是促使我自建的一个重要的原因。

d2b5ca33bd970f64a6301fa75ae2eb22 15
效果

中文手写字体我选择的是 小赖字体 ,小赖字体可以免费商用,对于我这样的用途来说,更加的安全。

原理

实现的原理并不复杂,在页面中引入对应的字体文件,并为对应的字体设置对应的 Font Family 即可。

添加字体

在 Excalidraw 中添加字体,需要在 public 目录中加入你的字体文件,并在 public/fonts.css 中添加对应的字体引入,这样后续你的应用中就可以使用对应的字体来进行绘图。

需要注意的事,这里的 Font-Family 的值不要瞎填,后续会用到。

@font-face {  
	font-family: "XiaolaiSC";  
	src: url("XiaolaiSC-Regular.ttf");  
	font-display: swap;
}
Code language: CSS (css)

此外,为了让浏览器可以提前加载字体,还可以在 public/index.html 中添加如下代码来实现预加载。

<link rel="preload" href="XiaolaiSC-Regular.ttf" as="font" type="font/ttf" crossorigin="anonymous" />
Code language: HTML, XML (xml)

添加常量

在 Excalidraw 中,组件使用的字体被定义在 src/constants.ts 中的 FONT_FAMILY 常量中,你需要在其中添加相应的 Font。这里就会用到你刚刚填写的 Font Family

export const FONT_FAMILY = {
    Virgil: 1,
    Helvetica: 2,
    Cascadia: 3,
    XiaolaiSC: 4, // 这一行是新增的
};
Code language: JavaScript (javascript)

在控制台上添加对应的调用

当你完成了这些基本的配置后,最后就简单了,只需要在 src/actions/actionProperties.tsx 中的 actionChangeFontFamily 中添加对应的 value 即可实现新字体的引入。

{
    value: FONT_FAMILY.XiaolaiSC,
    text: "小赖字体",
    icon: <FontFamilyLaiIcon theme={appState.theme} />,
},
Code language: JavaScript (javascript)

参考代码:https://github.com/bestony/excalidraw/commit/f308dc32a958e4cb4fb4658cd9a5c9a19ad6d683

移除 Excalidraw 右上角的 Plus 连接

9a1f326b911de6c1629837f3b57551e5

Excalidraw 是一个非常好用的手绘风格的绘图工具,我给自己部署了一个版本来降低自己写作配图的难度。如果你感兴趣,可以访问 draw.ixiqin.com 体验我自己维护的版本。

白宦成

Excalidraw 在右上角加入了他们的 Plus 版本服务的连接。不过我是自己使用,所以就不需要这样的导流连接,因此,可以通过修改 src/excalidraw-app/index.tsx 文件,将其中的代码进行替换,即可实现移除 Plus Link

原版

const PlusLinkJSX = (
  <p style={{ direction: "ltr", unicodeBidi: "embed" }}>
    Introducing Excalidraw+
    <br />
    <a
      href="https://plus.excalidraw.com/plus?utm_source=excalidraw&utm_medium=banner&utm_campaign=launch"
      target="_blank"
      rel="noreferrer"
    >
      Try out now!
    </a>
  </p>
);
Code language: JavaScript (javascript)

移除后

const PlusLinkJSX = <></>;
Code language: JavaScript (javascript)

自定义 Excalidraw 的字体大小

9a1f326b911de6c1629837f3b57551e5

Excalidraw 是一个非常好用的手绘风格的绘图工具,我给自己部署了一个版本来降低自己写作配图的难度。如果你感兴趣,可以访问 draw.ixiqin.com 体验我自己维护的版本。

白宦成

Excalidraw 默认的字体整体比较小,对于我来说,习惯将图画的大一些,这样在不同的设备上,都可以方便的看清楚图片的内容。

修改 S、M、L、XL 对应的字体大小

Excalidraw 将字体大小的变化定义在 src/actions/actionProperties.tsx 当中,因此,你需要修改不同按钮具体的字体,则需要修改这里的配置。

d2b5ca33bd970f64a6301fa75ae2eb22 12
字体大小修改工具

将下方代码中的 options 中 value 修改为你需要的值,即可实现不同的字体大小。

export const actionChangeFontSize = register({
  name: "changeFontSize",
  perform: (elements, appState, value) => {
    return changeFontSize(elements, appState, () => value, value);
  },
  PanelComponent: ({ elements, appState, updateData }) => (
    <fieldset>
      <legend>{t("labels.fontSize")}</legend>
      <ButtonIconSelect
        group="font-size"
        options={[
          {
            value: 20,
            text: t("labels.small"),
            icon: <FontSizeSmallIcon theme={appState.theme} />,
            testId: "fontSize-small",
          },
          {
            value: 28,
            text: t("labels.medium"),
            icon: <FontSizeMediumIcon theme={appState.theme} />,
            testId: "fontSize-medium",
          },
          {
            value: 36,
            text: t("labels.large"),
            icon: <FontSizeLargeIcon theme={appState.theme} />,
            testId: "fontSize-large",
          },
          {
            value: 50,
            text: t("labels.veryLarge"),
            icon: <FontSizeExtraLargeIcon theme={appState.theme} />,
            testId: "fontSize-veryLarge",
          },
        ]}
        value={getFormValue(
          elements,
          appState,
          (element) => {
            if (isTextElement(element)) {
              return element.fontSize;
            }
            const boundTextElement = getBoundTextElement(element);
            if (boundTextElement) {
              return boundTextElement.fontSize;
            }
            return null;
          },
          appState.currentItemFontSize || DEFAULT_FONT_SIZE,
        )}
        onChange={(value) => updateData(value)}
      />
    </fieldset>
  ),
});
Code language: PHP (php)

修改默认字体大小

默认字体的大小被定义在 src/constants.ts,你可以修改其中的 DEFAULT_FONT_SIZE 来实现控制默认情况下的字体大小。

export const DEFAULT_FONT_SIZE = 28;
Code language: JavaScript (javascript)

参考代码:https://github.com/bestony/excalidraw/commit/78d2d103b40c48bdccbecd7deb85f1fd0d6b4d2f

https://github.com/bestony/excalidraw/commit/14bca18aa6395280cfda15202beaf56dc966a401