refactor(client): use webpack for mermaid

This commit is contained in:
Elian Doran 2025-03-21 23:25:04 +02:00
parent f4d5b9fc29
commit 28c51cb38a
No known key found for this signature in database
11 changed files with 23 additions and 67 deletions

View File

@ -76,7 +76,6 @@ try {
"node_modules/dayjs/",
"node_modules/boxicons/css/",
"node_modules/boxicons/fonts/",
"node_modules/mermaid/dist/",
"node_modules/jquery/dist/",
"node_modules/jquery-hotkeys/",
"node_modules/split.js/dist/",

View File

@ -16,7 +16,6 @@ import RelationMapButtons from "../widgets/floating_buttons/relation_map_buttons
import SvgExportButton from "../widgets/floating_buttons/svg_export_button.js";
import BacklinksWidget from "../widgets/floating_buttons/zpetne_odkazy.js";
import HideFloatingButtonsButton from "../widgets/floating_buttons/hide_floating_buttons_button.js";
import MermaidWidget from "../widgets/mermaid.js";
import NoteListWidget from "../widgets/note_list.js";
import GlobalMenuWidget from "../widgets/buttons/global_menu.js";
import LauncherContainer from "../widgets/containers/launcher_container.js";
@ -165,7 +164,6 @@ export default class MobileLayout {
.child(new BacklinksWidget())
.child(new HideFloatingButtonsButton())
)
.child(new MermaidWidget())
.child(new PromotedAttributesWidget())
.child(
new ScrollingContainer()

View File

@ -15,6 +15,7 @@ import { loadElkIfNeeded, postprocessMermaidSvg } from "./mermaid.js";
import { normalizeMimeTypeForCKEditor } from "./mime_type_definitions.js";
import renderDoc from "./doc_renderer.js";
import { t } from "i18next";
import type { Mermaid } from "mermaid";
let idCounter = 1;
@ -226,7 +227,7 @@ function renderFile(entity: FNote | FAttachment, type: string, $renderedContent:
}
async function renderMermaid(note: FNote | FAttachment, $renderedContent: JQuery<HTMLElement>) {
await libraryLoader.requireLibrary(libraryLoader.MERMAID);
const mermaid = (await import("mermaid")).default;
const blob = await note.getBlob();
const content = blob?.content || "";
@ -236,10 +237,10 @@ async function renderMermaid(note: FNote | FAttachment, $renderedContent: JQuery
const documentStyle = window.getComputedStyle(document.documentElement);
const mermaidTheme = documentStyle.getPropertyValue("--mermaid-theme");
mermaid.mermaidAPI.initialize({ startOnLoad: false, theme: mermaidTheme.trim(), securityLevel: "antiscript" });
mermaid.mermaidAPI.initialize({ startOnLoad: false, theme: mermaidTheme.trim() as "default", securityLevel: "antiscript" });
try {
await loadElkIfNeeded(content);
await loadElkIfNeeded(mermaid, content);
const { svg } = await mermaid.mermaidAPI.render("in-mermaid-graph-" + idCounter++, content);
$renderedContent.append($(postprocessMermaidSvg(svg)));

View File

@ -55,10 +55,6 @@ const WHEEL_ZOOM: Library = {
js: ["node_modules/vanilla-js-wheel-zoom/dist/wheel-zoom.min.js"]
};
const MERMAID: Library = {
js: ["node_modules/mermaid/dist/mermaid.min.js"]
};
const MARKJS: Library = {
js: ["node_modules/mark.js/dist/jquery.mark.es6.min.js"]
};
@ -181,7 +177,6 @@ export default {
CALENDAR_WIDGET,
KATEX,
WHEEL_ZOOM,
MERMAID,
MARKJS,
HIGHLIGHT_JS,
LEAFLET

View File

@ -1,3 +1,5 @@
import type { Mermaid } from "mermaid";
let elkLoaded = false;
/**
@ -9,7 +11,7 @@ let elkLoaded = false;
*
* @param mermaidContent the plain text of the mermaid diagram, potentially including a frontmatter.
*/
export async function loadElkIfNeeded(mermaidContent: string) {
export async function loadElkIfNeeded(mermaid: Mermaid, mermaidContent: string) {
if (elkLoaded) {
// Exit immediately since the ELK library is already loaded.
return;
@ -18,7 +20,7 @@ export async function loadElkIfNeeded(mermaidContent: string) {
const parsedContent = await mermaid.parse(mermaidContent, {
suppressErrors: true
});
if (parsedContent?.config?.layout === "elk") {
if (parsedContent && parsedContent.config?.layout === "elk") {
elkLoaded = true;
mermaid.registerLayoutLoaders((await import("@mermaid-js/layout-elk")).default);
}

View File

@ -8,6 +8,7 @@ import library_loader, { Library } from "./services/library_loader.ts";
import type { init } from "i18next";
import type { lint } from "./services/eslint.ts";
import type { RelationType } from "./widgets/type_widgets/relation_map.ts";
import type { Mermaid } from "mermaid";
interface ElectronProcess {
type: string;
@ -138,45 +139,6 @@ declare global {
zoomOnClick: boolean
})
};
interface MermaidApi {
initialize(opts: {
startOnLoad: boolean,
theme: string,
securityLevel: "antiscript"
}): void;
render(selector: string, data: string);
}
interface MermaidLoader {
}
interface MermaidChartConfig {
useMaxWidth: boolean;
}
interface MermaidConfig {
theme: string;
securityLevel: "antiscript",
flow: MermaidChartConfig;
sequence: MermaidChartConfig;
gantt: MermaidChartConfig;
class: MermaidChartConfig;
state: MermaidChartConfig;
pie: MermaidChartConfig;
journey: MermaidChartConfig;
git: MermaidChartConfig;
}
var mermaid: {
mermaidAPI: MermaidApi;
registerLayoutLoaders(loader: MermaidLoader);
init(config: MermaidConfig, el: HTMLElement | JQuery<HTMLElement>);
parse(content: string, opts: {
suppressErrors: true
}): Promise<{
config: {
layout: string;
}
}>
};
interface CKCodeBlockLanguage {
language: string;
label: string;
@ -207,7 +169,7 @@ declare global {
enablePreview: boolean
},
mermaid: {
lazyLoad: () => Promise<void>,
lazyLoad: () => Promise<Mermaid>,
config: MermaidConfig
}
});

View File

@ -7,6 +7,7 @@ import AbstractSplitTypeWidget from "./abstract_split_type_widget.js";
* This adds the following functionality:
*
* - Automatic handling of the preview when content or the note changes.
* - Built-in pan and zoom functionality with automatic re-centering.
*
*/
export default abstract class AbstractSvgSplitTypeWidget extends AbstractSplitTypeWidget {

View File

@ -13,10 +13,10 @@ import dialogService from "../../services/dialog.js";
import { initSyntaxHighlighting } from "./ckeditor/syntax_highlight.js";
import options from "../../services/options.js";
import toast from "../../services/toast.js";
import { getMermaidConfig } from "../mermaid.js";
import { normalizeMimeTypeForCKEditor } from "../../services/mime_type_definitions.js";
import { buildConfig, buildToolbarConfig } from "./ckeditor/config.js";
import type FNote from "../../entities/fnote.js";
import { getMermaidConfig } from "./mermaid.js";
const ENABLE_INSPECTOR = false;
@ -279,7 +279,7 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget {
enablePreview: true // Enable preview view
},
mermaid: {
lazyLoad: async () => await libraryLoader.requireLibrary(libraryLoader.MERMAID),
lazyLoad: async () => (await import("mermaid")).default, // FIXME
config: getMermaidConfig()
}
});

View File

@ -1,3 +1,4 @@
import type { MermaidConfig } from "mermaid";
import library_loader from "../../services/library_loader.js";
import { loadElkIfNeeded, postprocessMermaidSvg } from "../../services/mermaid.js";
import AbstractSvgSplitTypeWidget from "./abstract_svg_split_type_widget.js";
@ -11,8 +12,8 @@ export class MermaidTypeWidget extends AbstractSvgSplitTypeWidget {
}
async renderSvg(content: string) {
await library_loader.requireLibrary(library_loader.MERMAID);
await loadElkIfNeeded(content);
const mermaid = (await import("mermaid")).default;
await loadElkIfNeeded(mermaid, content);
mermaid.mermaidAPI.initialize({
startOnLoad: false,
@ -28,19 +29,18 @@ export class MermaidTypeWidget extends AbstractSvgSplitTypeWidget {
export function getMermaidConfig(): MermaidConfig {
const documentStyle = window.getComputedStyle(document.documentElement);
const mermaidTheme = documentStyle.getPropertyValue("--mermaid-theme");
const mermaidTheme = documentStyle.getPropertyValue("--mermaid-theme") as "default";
return {
theme: mermaidTheme.trim(),
theme: mermaidTheme.trim() as "default",
securityLevel: "antiscript",
// TODO: Are all these options correct?
flow: { useMaxWidth: false },
flowchart: { useMaxWidth: false },
sequence: { useMaxWidth: false },
gantt: { useMaxWidth: false },
class: { useMaxWidth: false },
state: { useMaxWidth: false },
pie: { useMaxWidth: true },
journey: { useMaxWidth: false },
git: { useMaxWidth: false }
gitGraph: { useMaxWidth: false }
};
}

View File

@ -1,10 +1,10 @@
import AbstractTextTypeWidget from "./abstract_text_type_widget.js";
import libraryLoader from "../../services/library_loader.js";
import { applySyntaxHighlight } from "../../services/syntax_highlight.js";
import { getMermaidConfig } from "../mermaid.js";
import type FNote from "../../entities/fnote.js";
import type { EventData } from "../../components/app_context.js";
import { getLocaleById } from "../../services/i18n.js";
import { getMermaidConfig } from "./mermaid.js";
const TPL = `
<div class="note-detail-readonly-text note-detail-printable">
@ -141,8 +141,8 @@ export default class ReadOnlyTextTypeWidget extends AbstractTextTypeWidget {
});
// Initialize mermaid
await libraryLoader.requireLibrary(libraryLoader.MERMAID);
mermaid.init(getMermaidConfig(), this.$content.find(".mermaid-diagram"));
const mermaid = (await import("mermaid")).default;
mermaid.init(getMermaidConfig(), this.$content.find(".mermaid-diagram")[0]);
}
async refreshIncludedNoteEvent({ noteId }: EventData<"refreshIncludedNote">) {

View File

@ -64,8 +64,6 @@ async function register(app: express.Application) {
app.use(`/${assetPath}/node_modules/boxicons/css/`, persistentCacheStatic(path.join(srcRoot, "..", "node_modules/boxicons/css/")));
app.use(`/${assetPath}/node_modules/boxicons/fonts/`, persistentCacheStatic(path.join(srcRoot, "..", "node_modules/boxicons/fonts/")));
app.use(`/${assetPath}/node_modules/mermaid/dist/`, persistentCacheStatic(path.join(srcRoot, "..", "node_modules/mermaid/dist/")));
app.use(`/${assetPath}/node_modules/jquery/dist/`, persistentCacheStatic(path.join(srcRoot, "..", "node_modules/jquery/dist/")));
app.use(`/${assetPath}/node_modules/jquery-hotkeys/`, persistentCacheStatic(path.join(srcRoot, "..", "node_modules/jquery-hotkeys/")));