docusaurus中嵌入Excalidraw并引入中文手写字体

302 阅读3分钟

0. 效果

上次把Excalidraw嵌入到docusaurus,这次我试着添加中文字体。

image.png

可以看到显示的中文是某种中文字体。

下面我将记录我的修改过程,最终替换产物在这里注意版本是0.17.6

1. 原理

直接修改源码,在字体选项中加了一个。然后重新打包替换了原始文件。

2.修改源码

2.1. 始代码仓库,切换分支到tag: 0.17.6

2.2. 字体文件都放在根目录的public文件夹中,这里我添加了一个中文字体cn.tff名字随意。

image.png

2.3. 文件夹的fonts.css中添加样式,这里font-family名字要记住,后面代码要用

@font-face {
  font-family: "Cn";
  src: url("cn.ttf");
  font-display: swap;
}

2.4. 修改src\constants.ts

export const FONT_FAMILY = {
  Virgil: 1,
  Helvetica: 2,
  Cascadia: 3,
// 这个值随便取,不重复就行了
// 键名Cn就是上面的font-family名字
// 代码中会取这个名字加载字体
+ Cn: 4,
  Assistant: 5,
};

2.5. 修改src\element\textElement.ts

const DEFAULT_LINE_HEIGHT = {
  // ~1.25 is the average for Virgil in WebKit and Blink.
  // Gecko (FF) uses ~1.28.
  [FONT_FAMILY.Virgil]: 1.25 as ExcalidrawTextElement["lineHeight"],
  // ~1.15 is the average for Virgil in WebKit and Blink.
  // Gecko if all over the place.
  [FONT_FAMILY.Helvetica]: 1.15 as ExcalidrawTextElement["lineHeight"],
  // ~1.2 is the average for Virgil in WebKit and Blink, and kinda Gecko too
  [FONT_FAMILY.Cascadia]: 1.2 as ExcalidrawTextElement["lineHeight"],
  // 这个行高主要是用于计算尺寸,这里我直接设置的1.2,平常使用没什么问题
+ [FONT_FAMILY.Cn]: 1.2 as ExcalidrawTextElement["lineHeight"],
};

2.6. 修改src\actions\actionProperties.tsx添加字体

// 找到actionChangeFontFamily方法
// 在PanelComponent参数中修改
    const options: {
      value: FontFamilyValues;
      text: string;
      icon: JSX.Element;
      testId: string;
    }[] = [
      {
        value: FONT_FAMILY.Virgil,
        text: t("labels.handDrawn"),
        icon: FreedrawIcon,
        testId: "font-family-virgil",
      },
      {
        value: FONT_FAMILY.Helvetica,
        text: t("labels.normal"),
        icon: FontFamilyNormalIcon,
        testId: "font-family-normal",
      },
      {
        value: FONT_FAMILY.Cascadia,
        text: t("labels.code"),
        icon: FontFamilyCodeIcon,
        testId: "font-family-code",
      },
      // 添加了一个字体备选项
      // 这个选项就是我们的字体
      {
        value: FONT_FAMILY.Cn,
        text: t("labels.code"),
        icon: FontFamilyCodeIcon,
        testId: "font-family-code",
      },
    ];

2.7. 打包

进入\src\packages\excalidraw,执行yarn build:umd,生成静态资源和js

\src\packages\excalidraw\dist中就能看到产物

image.png

打包可能会报错NODE_ENV不是指令,这是因为Windows系统原因,但是不影响打包。

3. 使用

3.1. 修改npm

你可以直接复制到npm包里面修改,然后用patch-package之类的工具记录修改。

3.2. 外部引用

由于文档很有可能部署在内网,而excalidraw的字体之类的静态资源会请求互联网,所以我决定按照文档的方式改为引用文档的静态文件目录。

并且不修改npm包,而是打包的时候通过script标签引入。

要实现这一功能,我们需要完成修改webpack配置入口html额外注入代码

3.2.1. 修改webpack配置

自定义一个docusaurus插件excalidrawPlugin

import type { PluginModule } from "@docusaurus/types";
import webpack from "webpack";

const plugin: PluginModule = async function (context) {
  return {
    name: "excalidraw-plugin",
    configureWebpack(webpackConfig, isServer, utils) {
      return {
      // 由于我要自己引入js,所以要将这些库标记为外部
      // 所有的插件会在server打包和client打包的时候执行两次
      // excalidraw只运行在client所以这里不对server做处理
        externals: {
          ...(isServer
            ? {}
            : {
                "@excalidraw/excalidraw": "ExcalidrawLib",
                // excalidraw 运行的前提是环境中有react
                // 所以react也需要单独提出来
                react: "React",
                "react-dom": "ReactDOM",
              }),
        },
      };
    },
  };
};
export default plugin;

3.2.2. 入口html额外注入代码

排除了上面库文件的打包,我们需要在入口html中注入这些文件:

// ...
return {
    configureWebpack(){},
    injectHtmlTags() {
      return {
        headTags: [
        // 这一步是文档中写的将excalidraw的资源目录地址改为当前网址
          {
            tagName: "script",
            innerHTML: `
              window.EXCALIDRAW_ASSET_PATH = "/";
            `,
          },
      // 插入react
          {
            tagName: "script",
            attributes: {
              async: false,
              src: "/react.production.min.js",
            },
          },
    // 插入react-dom
          {
            tagName: "script",
            attributes: {
              async: false,
              src: "/react-dom.production.min.js",
            },
          },
    // 插入之前修改的excalidraw
          {
            tagName: "script",
            attributes: {
              async: false,
              src: "/excalidraw.production.min.js",
            },
          },
        ],
      };
    },
}

// ...

image.png 将需要的静态文件放入static文件夹就可以了。