0. 效果
上次把Excalidraw
嵌入到docusaurus
,这次我试着添加中文字体。
可以看到显示的中文是某种中文字体。
下面我将记录我的修改过程,最终替换产物在这里注意版本是0.17.6:
1. 原理
直接修改源码,在字体选项中加了一个。然后重新打包替换了原始文件。
2.修改源码
2.1. 始代码仓库,切换分支到tag: 0.17.6
。
2.2. 字体文件都放在根目录的public
文件夹中,这里我添加了一个中文字体cn.tff
名字随意。
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
中就能看到产物
打包可能会报错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",
},
},
],
};
},
}
// ...
将需要的静态文件放入
static
文件夹就可以了。