1
0
mirror of https://github.com/excalidraw/excalidraw.git synced 2024-11-02 03:25:53 +01:00

Build tweaks for server-side, fixes - WIP

This commit is contained in:
Marcel Mraz 2024-09-02 11:43:44 +02:00
parent 6ce17a80c4
commit 1e19a446b8
11 changed files with 87 additions and 86 deletions

@ -62,10 +62,8 @@ export class ExcalidrawFontFace implements IExcalidrawFontFace {
return new Promise<string>((resolve) => {
this.getContent(codePoints).then((content) => {
resolve(`@font-face {
font-family: ${this.fontFace.family};
src: url(${content});
}`);
resolve(`
@font-face { font-family: ${this.fontFace.family}; src: url(${content}); }`);
});
});
}

@ -15,16 +15,13 @@ const load = (): Promise<{
}> => {
return new Promise(async (resolve, reject) => {
try {
WebAssembly.instantiate(binary).then((module) => {
const module = await WebAssembly.instantiate(binary);
const harfbuzzJsWasm = module.instance.exports;
// @ts-expect-error since `.buffer` is custom prop
const heapu8 = new Uint8Array(harfbuzzJsWasm.memory.buffer);
const hbSubset = {
subset: (
fontBuffer: ArrayBuffer,
codePoints: ReadonlySet<number>,
) => {
subset: (fontBuffer: ArrayBuffer, codePoints: ReadonlySet<number>) => {
return bindings.subset(
harfbuzzJsWasm,
heapu8,
@ -35,7 +32,6 @@ const load = (): Promise<{
};
resolve(hbSubset);
});
} catch (e) {
reject(e);
}

@ -47,6 +47,7 @@ const Module = (function () {
moduleOverrides[key] = Module[key];
}
}
let arguments_ = [];
let thisProgram = "./this.program";
let quit_ = function (status, toThrow) {
@ -3917,6 +3918,7 @@ const Module = (function () {
let calledRun;
Module.then = function (func) {
if (calledRun) {
throw new Error("1 This error should be silently swallowed");
func(Module);
} else {
const old = Module.onRuntimeInitialized;
@ -3924,6 +3926,7 @@ const Module = (function () {
if (old) {
old();
}
throw new Error("This error should be silently swallowed 1");
func(Module);
};
}
@ -4046,3 +4049,5 @@ const Module = (function () {
})();
export default Module;

@ -15,12 +15,6 @@ const load = (): Promise<{
}> => {
return new Promise(async (resolve, reject) => {
try {
// initializing the module manually, so that we could pass in the wasm binary
bindings({ wasmBinary: binary }).then(
(module: {
woff2Enc: (buffer: ArrayBuffer, byteLength: number) => Vector;
woff2Dec: (buffer: ArrayBuffer, byteLength: number) => Vector;
}) => {
// re-map from internal vector into byte array
function convertFromVecToUint8Array(vector: Vector): Uint8Array {
const arr = [];
@ -31,6 +25,13 @@ const load = (): Promise<{
return new Uint8Array(arr);
}
// TODO_CHINESE: bindings implements .then, but rejections will still likely be not caught
// initializing the module manually, so that we could pass in the wasm binary
const module: {
woff2Enc: (buffer: ArrayBuffer, byteLength: number) => Vector;
woff2Dec: (buffer: ArrayBuffer, byteLength: number) => Vector;
} = await bindings({ wasmBinary: binary });
// re-exporting only compress and decompress functions (also avoids infinite loop inside emscripten bindings)
const woff2 = {
compress: (buffer: ArrayBuffer) =>
@ -44,8 +45,6 @@ const load = (): Promise<{
};
resolve(woff2);
},
);
} catch (e) {
reject(e);
}

@ -31,8 +31,8 @@ export class WorkerPool<T, R> {
},
) {
this.workerUrl = workerUrl;
// by default, active & idle workers will be terminated after 10 seconds of inactivity
this.workerTTL = options.ttl || 10_000;
// by default, active & idle workers will be terminated after 5 seconds of inactivity
this.workerTTL = options.ttl || 5_000;
this.initWorker = options.initWorker;
}

@ -82,7 +82,6 @@ const rawConfig = {
entryPoints: ["index.ts"],
bundle: true,
format: "esm",
packages: "external",
};
// const BASE_PATH = `${path.resolve(`${__dirname}/..`)}`;

@ -0,0 +1,6 @@
# 1. Created "XiaolaiNotoEmoji" through FontForge
- Merged `XiaolaiSC-Regular.ttf` with `NotoEmoji-Regular.ttf` (kept in the codebasefor future reference)
- Adjusted glyphs of the merged font to fit the Em box
- Added merged copyright & license
- Generated versions for different Em sizes 1000 and 2048 (otherwise pyftmerge throws)

Binary file not shown.

Binary file not shown.

Binary file not shown.

@ -47,7 +47,7 @@ module.exports.woff2BrowserPlugin = () => {
* 2. convert all the imported fonts (including those from cdn) at build time into .ttf (since Resvg does not support woff2, neither inlined dataurls - https://github.com/RazrFalcon/resvg/issues/541)
* - merging multiple woff2 into one ttf (for same families with different unicode ranges)
* - deduplicating glyphs due to the merge process
* - merging emoji font for each
* - merging fallback font for each
* - printing out font metrics
*
* @returns {import("esbuild").Plugin}
@ -176,6 +176,11 @@ module.exports.woff2ServerPlugin = (options = {}) => {
// for now we are interested in the regular families only
for (const [family, { Regular }] of sortedFonts) {
if (family === "Xiaolai SC") {
// don't generate ttf for Xiaolai SC, as we have it hardcoded
continue;
}
const baseFont = Regular[0];
const tempFilePaths = Regular.map((_, index) =>
@ -192,41 +197,34 @@ module.exports.woff2ServerPlugin = (options = {}) => {
fs.writeFileSync(tempFilePaths[index], font.write({ type: "ttf" }));
}
const emojiFilePath = path.resolve(
const fallbackFilePath2048 = path.resolve(
__dirname,
"./assets/NotoEmoji-Regular.ttf",
);
const emojiBuffer = fs.readFileSync(emojiFilePath);
const emojiFont = Font.create(emojiBuffer, { type: "ttf" });
// hack so that:
// - emoji font has same metrics as the base font, otherwise pyftmerge throws due to different unitsPerEm
// - emoji font glyphs are adjusted based to the base font glyphs, otherwise the glyphs don't match
const patchedEmojiFont = Font.create({
...baseFont.data,
glyf: baseFont.find({ unicode: [65] }), // adjust based on the "A" glyph (does not have to be first)
}).merge(emojiFont, { adjustGlyf: true });
const emojiTempFilePath = path.resolve(
outputDir,
`temp_${family}_Emoji.ttf`,
);
fs.writeFileSync(
emojiTempFilePath,
patchedEmojiFont.write({ type: "ttf" }),
"./assets/XiaolaiNotoEmoji-2048.ttf",
);
const fallbackFilePath1000 = path.resolve(
__dirname,
"./assets/XiaolaiNotoEmoji-1000.ttf",
);
const fallbackBuffer = fs.readFileSync(fallbackFilePath2048);
const fallbackFont = Font.create(fallbackBuffer, { type: "ttf" });
const mergedFontPath = path.resolve(outputDir, `${family}.ttf`);
if (baseFont.data.head.unitsPerEm !== 1000) {
execSync(
`pyftmerge --output-file="${mergedFontPath}" "${tempFilePaths.join(
'" "',
)}" "${emojiTempFilePath}"`,
)}" "${fallbackFilePath2048}"`,
);
} else {
execSync(
`pyftmerge --output-file="${mergedFontPath}" "${tempFilePaths.join(
'" "',
)}" "${fallbackFilePath1000}"`,
);
}
// cleanup
fs.rmSync(emojiTempFilePath);
for (const path of tempFilePaths) {
fs.rmSync(path);
}
@ -243,8 +241,8 @@ module.exports.woff2ServerPlugin = (options = {}) => {
...mergedFont.data,
name: {
...mergedFont.data.name,
copyright: `${baseFont.data.name.copyright} & ${emojiFont.data.name.copyright}`,
licence: `${baseFont.data.name.licence} & ${emojiFont.data.name.licence}`,
copyright: `${baseFont.data.name.copyright} & ${fallbackFont.data.name.copyright}`,
licence: `${baseFont.data.name.licence} & ${fallbackFont.data.name.licence}`,
},
});
@ -255,7 +253,7 @@ module.exports.woff2ServerPlugin = (options = {}) => {
console.info(`Generated "${family}"`);
if (Regular.length > 1) {
console.info(
`- by merging ${Regular.length} woff2 files and 1 emoji ttf file`,
`- by merging ${Regular.length} woff2 files and 1 fallback ttf file`,
);
}
console.info(