mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-07 19:22:14 +09:00
fix(markdown): compile the parser wasm asynchronously (#2900)
This commit is contained in:
@@ -47,11 +47,19 @@ const lenientTextDecoder = new TextDecoder('utf-8', {ignoreBOM: true, fatal: fal
|
|||||||
|
|
||||||
let textDecoder = new TextDecoder('utf-8', {ignoreBOM: true, fatal: true});
|
let textDecoder = new TextDecoder('utf-8', {ignoreBOM: true, fatal: true});
|
||||||
let wasm: WasmExports | null = null;
|
let wasm: WasmExports | null = null;
|
||||||
|
let wasmModule: unknown = null;
|
||||||
let cachedMemory: Uint8Array | null = null;
|
let cachedMemory: Uint8Array | null = null;
|
||||||
|
let replacingOversizedInstance = false;
|
||||||
|
|
||||||
|
interface WasmInstance {
|
||||||
|
exports: Record<string, unknown>;
|
||||||
|
}
|
||||||
|
|
||||||
declare const WebAssembly: {
|
declare const WebAssembly: {
|
||||||
Module: new (bytes: Uint8Array) => unknown;
|
Module: new (bytes: Uint8Array) => unknown;
|
||||||
Instance: new (module: unknown, imports?: Record<string, unknown>) => {exports: Record<string, unknown>};
|
Instance: new (module: unknown, imports?: Record<string, unknown>) => WasmInstance;
|
||||||
|
compile(bytes: Uint8Array): Promise<unknown>;
|
||||||
|
instantiate(module: unknown, imports?: Record<string, unknown>): Promise<WasmInstance>;
|
||||||
};
|
};
|
||||||
|
|
||||||
function getWasmMemory(exports: Record<string, unknown>): WasmExports['memory'] {
|
function getWasmMemory(exports: Record<string, unknown>): WasmExports['memory'] {
|
||||||
@@ -94,22 +102,39 @@ function decodeBase64(value: string): Uint8Array {
|
|||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getWasm(): WasmExports {
|
function setWasmInstance(instance: WasmInstance): WasmExports {
|
||||||
if (!wasm) {
|
wasm = createWasmExports(instance.exports);
|
||||||
const module = new WebAssembly.Module(decodeBase64(MARKDOWN_PARSER_WASM_BASE64));
|
cachedMemory = null;
|
||||||
const instance = new WebAssembly.Instance(module, {});
|
|
||||||
wasm = createWasmExports(instance.exports);
|
|
||||||
cachedMemory = null;
|
|
||||||
}
|
|
||||||
return wasm;
|
return wasm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function preloadMarkdownParserWasm(): Promise<void> {
|
||||||
|
if (wasm) return;
|
||||||
|
wasmModule ??= await WebAssembly.compile(decodeBase64(MARKDOWN_PARSER_WASM_BASE64));
|
||||||
|
const instance = await WebAssembly.instantiate(wasmModule, {});
|
||||||
|
if (!wasm) setWasmInstance(instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getWasm(): WasmExports {
|
||||||
|
if (wasm) return wasm;
|
||||||
|
wasmModule ??= new WebAssembly.Module(decodeBase64(MARKDOWN_PARSER_WASM_BASE64));
|
||||||
|
return setWasmInstance(new WebAssembly.Instance(wasmModule, {}));
|
||||||
|
}
|
||||||
|
|
||||||
function releaseOversizedWasmMemory(): void {
|
function releaseOversizedWasmMemory(): void {
|
||||||
if ((wasm?.memory.buffer.byteLength ?? 0) <= MAX_RETAINED_WASM_MEMORY_BYTES) {
|
if (replacingOversizedInstance || (wasm?.memory.buffer.byteLength ?? 0) <= MAX_RETAINED_WASM_MEMORY_BYTES) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
wasm = null;
|
const oversized = wasm;
|
||||||
cachedMemory = null;
|
replacingOversizedInstance = true;
|
||||||
|
WebAssembly.instantiate(wasmModule, {})
|
||||||
|
.then((instance) => {
|
||||||
|
if (wasm === oversized) setWasmInstance(instance);
|
||||||
|
})
|
||||||
|
.catch(() => {})
|
||||||
|
.finally(() => {
|
||||||
|
replacingOversizedInstance = false;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function memoryU8(): Uint8Array {
|
function memoryU8(): Uint8Array {
|
||||||
|
|||||||
@@ -86,7 +86,19 @@ async function logClientInfo(): Promise<void> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function preloadMarkdownParser(): Promise<void> {
|
||||||
|
try {
|
||||||
|
const {preloadMarkdownParserWasm} = await loadLazyModule(
|
||||||
|
() => import('@app/features/messaging/utils/markdown/parser/MarkdownParserWasm'),
|
||||||
|
);
|
||||||
|
await preloadMarkdownParserWasm();
|
||||||
|
} catch (error) {
|
||||||
|
logger.warn('Failed to preload markdown parser:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function bootstrapThemeStudio(): Promise<void> {
|
async function bootstrapThemeStudio(): Promise<void> {
|
||||||
|
const markdownParserReady = preloadMarkdownParser();
|
||||||
const [{ThemeStudioStandaloneApp}, {setupHttp}, {default: AccountManager}] = await Promise.all([
|
const [{ThemeStudioStandaloneApp}, {setupHttp}, {default: AccountManager}] = await Promise.all([
|
||||||
loadLazyModule(() => import('@app/features/theme_studio/ThemeStudioStandaloneApp')),
|
loadLazyModule(() => import('@app/features/theme_studio/ThemeStudioStandaloneApp')),
|
||||||
loadLazyModule(() => import('@app/app/SetupHttp')),
|
loadLazyModule(() => import('@app/app/SetupHttp')),
|
||||||
@@ -94,6 +106,7 @@ async function bootstrapThemeStudio(): Promise<void> {
|
|||||||
]);
|
]);
|
||||||
await AccountManager.bootstrap();
|
await AccountManager.bootstrap();
|
||||||
setupHttp();
|
setupHttp();
|
||||||
|
await markdownParserReady;
|
||||||
mountRoot(
|
mountRoot(
|
||||||
<AppI18nProvider i18n={i18n}>
|
<AppI18nProvider i18n={i18n}>
|
||||||
<ThemeStudioStandaloneApp data-flx="index.render-theme-studio.theme-studio-standalone-app" />
|
<ThemeStudioStandaloneApp data-flx="index.render-theme-studio.theme-studio-standalone-app" />
|
||||||
@@ -103,6 +116,7 @@ async function bootstrapThemeStudio(): Promise<void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function bootstrapApp(): Promise<void> {
|
async function bootstrapApp(): Promise<void> {
|
||||||
|
const markdownParserReady = preloadMarkdownParser();
|
||||||
const [
|
const [
|
||||||
{App},
|
{App},
|
||||||
{setupHttp},
|
{setupHttp},
|
||||||
@@ -148,6 +162,7 @@ async function bootstrapApp(): Promise<void> {
|
|||||||
await AccountManager.bootstrap();
|
await AccountManager.bootstrap();
|
||||||
setupHttp();
|
setupHttp();
|
||||||
initializeEmojiParser();
|
initializeEmojiParser();
|
||||||
|
await markdownParserReady;
|
||||||
mountRoot(<App data-flx="index.bootstrap.app" />, 'index.bootstrap');
|
mountRoot(<App data-flx="index.bootstrap.app" />, 'index.bootstrap');
|
||||||
QuickSwitcher.preloadModal();
|
QuickSwitcher.preloadModal();
|
||||||
registerServiceWorker();
|
registerServiceWorker();
|
||||||
|
|||||||
Reference in New Issue
Block a user