feat(mermaid): load ELK library on demand

This commit is contained in:
Elian Doran 2024-11-25 21:58:56 +02:00
parent e3c8c0c1f2
commit 2ef956da87
No known key found for this signature in database
3 changed files with 45 additions and 5 deletions

View File

@ -59,7 +59,16 @@ const FORCE_GRAPH = {
const MERMAID = { const MERMAID = {
js: [ js: [
"node_modules/mermaid/dist/mermaid.min.js", "node_modules/mermaid/dist/mermaid.min.js"
]
}
/**
* The ELK extension of Mermaid.js, which supports more advanced layouts.
* See https://www.npmjs.com/package/@mermaid-js/layout-elk for more information.
*/
const MERMAID_ELK = {
js: [
"libraries/mermaid-elk/elk.min.js" "libraries/mermaid-elk/elk.min.js"
] ]
} }
@ -200,6 +209,7 @@ export default {
WHEEL_ZOOM, WHEEL_ZOOM,
FORCE_GRAPH, FORCE_GRAPH,
MERMAID, MERMAID,
MERMAID_ELK,
EXCALIDRAW, EXCALIDRAW,
MARKJS, MARKJS,
I18NEXT, I18NEXT,

View File

@ -0,0 +1,28 @@
import library_loader from "./library_loader.js";
let elkLoaded = false;
/**
* Determines whether the ELK extension of Mermaid.js needs to be loaded (which is a relatively large library), based on the
* front-matter of the diagram and loads the library if needed.
*
* <p>
* If the library has already been loaded or the diagram does not require it, the method will exit immediately.
*
* @param mermaidContent the plain text of the mermaid diagram, potentially including a frontmatter.
*/
export async function loadElkIfNeeded(mermaidContent) {
if (elkLoaded) {
// Exit immediately since the ELK library is already loaded.
return;
}
const parsedContent = await mermaid.parse(mermaidContent, {
suppressErrors: true
});
if (parsedContent?.config?.layout === "elk") {
elkLoaded = true;
await library_loader.requireLibrary(library_loader.MERMAID_ELK);
mermaid.registerLayoutLoaders(MERMAID_ELK);
}
}

View File

@ -3,6 +3,7 @@ import libraryLoader from "../services/library_loader.js";
import NoteContextAwareWidget from "./note_context_aware_widget.js"; import NoteContextAwareWidget from "./note_context_aware_widget.js";
import server from "../services/server.js"; import server from "../services/server.js";
import utils from "../services/utils.js"; import utils from "../services/utils.js";
import { loadElkIfNeeded } from "../services/mermaid.js";
const TPL = `<div class="mermaid-widget"> const TPL = `<div class="mermaid-widget">
<style> <style>
@ -57,11 +58,10 @@ export default class MermaidWidget extends NoteContextAwareWidget {
this.$errorContainer.hide(); this.$errorContainer.hide();
await libraryLoader.requireLibrary(libraryLoader.MERMAID); await libraryLoader.requireLibrary(libraryLoader.MERMAID);
const documentStyle = window.getComputedStyle(document.documentElement); const documentStyle = window.getComputedStyle(document.documentElement);
const mermaidTheme = documentStyle.getPropertyValue('--mermaid-theme'); const mermaidTheme = documentStyle.getPropertyValue('--mermaid-theme');
mermaid.registerLayoutLoaders(MERMAID_ELK);
mermaid.mermaidAPI.initialize({ mermaid.mermaidAPI.initialize({
startOnLoad: false, startOnLoad: false,
theme: mermaidTheme.trim(), theme: mermaidTheme.trim(),
@ -112,6 +112,7 @@ export default class MermaidWidget extends NoteContextAwareWidget {
zoomOnClick: false zoomOnClick: false
}); });
} catch (e) { } catch (e) {
console.warn(e);
this.$errorMessage.text(e.message); this.$errorMessage.text(e.message);
this.$errorContainer.show(); this.$errorContainer.show();
} }
@ -123,6 +124,7 @@ export default class MermaidWidget extends NoteContextAwareWidget {
const blob = await this.note.getBlob(); const blob = await this.note.getBlob();
const content = blob.content || ""; const content = blob.content || "";
await loadElkIfNeeded(content);
const {svg} = await mermaid.mermaidAPI.render(`mermaid-graph-${idCounter}`, content); const {svg} = await mermaid.mermaidAPI.render(`mermaid-graph-${idCounter}`, content);
return svg; return svg;
} }