docusaurus: Can't render `mindmap` mermaid diagrams

Have you read the Contributing Guidelines on issues?

Prerequisites

  • I’m using the latest version of Docusaurus.
  • I have tried the npm run clear or yarn clear command.
  • I have tried rm -rf node_modules yarn.lock package-lock.json and re-installing packages.
  • I have tried creating a repro with https://new.docusaurus.io.
  • I have read the console error message carefully (if applicable).

Description

It looks like the mindmap Mermaid diagram doesn’t work with the current Docusaurus integrations. Other diagrams do work as expected.

Reproducible demo

https://github.com/Quansight-Labs/cf-infra-docs

Steps to reproduce

I followed the instructions for Mermaid diagrams and modified my Docusaurus configuration accordingly (see this PR).

I would have expected the rendering to work out of the box after those changes, but it doesn’t.

Expected behavior

Get the same diagram as available in mermaid.live

Actual behavior

You first see this warning:

image

Clicking on Try Again gets you to a rendered page with a faulty diagram:

image

Locally, you see this error message:

ERROR
Diagram is a promise. Use renderAsync.
    at Object.render (webpack-internal:///./node_modules/mermaid/dist/mermaid-ae477ddf.js:29923:13)
    at eval (webpack-internal:///./node_modules/@docusaurus/theme-mermaid/lib/client/index.js:44:58)
    at mountMemo (webpack-internal:///./node_modules/react-dom/cjs/react-dom.development.js:15846:19)
    at Object.useMemo (webpack-internal:///./node_modules/react-dom/cjs/react-dom.development.js:16219:16)
    at useMemo (webpack-internal:///./node_modules/react/cjs/react.development.js:1532:21)
    at useMermaidSvg (webpack-internal:///./node_modules/@docusaurus/theme-mermaid/lib/client/index.js:21:168)
    at MermaidDiagram (webpack-internal:///./node_modules/@docusaurus/theme-mermaid/lib/theme/Mermaid/index.js:14:139)
    at renderWithHooks (webpack-internal:///./node_modules/react-dom/cjs/react-dom.development.js:14985:18)
    at mountIndeterminateComponent (webpack-internal:///./node_modules/react-dom/cjs/react-dom.development.js:17811:13)
    at beginWork (webpack-internal:///./node_modules/react-dom/cjs/react-dom.development.js:19049:16)
ERROR
Diagram mindmap already registered.
    at registerDiagram (webpack-internal:///./node_modules/mermaid/dist/mermaid-ae477ddf.js:7474:11)
    at eval (webpack-internal:///./node_modules/mermaid/dist/mermaid-ae477ddf.js:29705:7)

It sounds like this discussion, which led to this commit. I assume something similar is needed here? I am not an expert in anything JavaScript, sorry 😬

Your environment

Self-service

  • I’d be willing to fix this bug myself.

About this issue

  • Original URL
  • State: closed
  • Created a year ago
  • Reactions: 4
  • Comments: 18

Most upvoted comments

FYI, in my simple use case, this patch seems to do the trick. Basically, simply using useState() + useEffect() instead of useMemo() since it seems that useMemo() does not play nice with async.

diff --git a/lib/client/index.js b/lib/client/index.js
index 1c121a7adf027f62e1d57510f9d86eee62d313ea..9c0d384f2facfd36e50839c0c03d264243b4bded 100644
--- a/lib/client/index.js
+++ b/lib/client/index.js
@@ -4,7 +4,7 @@
  * This source code is licensed under the MIT license found in the
  * LICENSE file in the root directory of this source tree.
  */
-import { useMemo } from 'react';
+import { useEffect, useMemo, useState } from 'react';
 import { useColorMode, useThemeConfig } from '@docusaurus/theme-common';
 import mermaid from 'mermaid';
 // Stable className to allow users to easily target with CSS
@@ -26,7 +26,8 @@ export function useMermaidSvg(txt, mermaidConfigParam) {
      */
     const defaultMermaidConfig = useMermaidConfig();
     const mermaidConfig = mermaidConfigParam ?? defaultMermaidConfig;
-    return useMemo(() => {
+    const [svgResult, setSvgResult] = useState('');
+    useEffect(() => {
         /*
         Mermaid API is really weird :s
         It is a big mutable singleton with multiple config levels
@@ -55,6 +56,11 @@ export function useMermaidSvg(txt, mermaidConfigParam) {
         Not even documented: mermaid.render returns the svg string
         Using the documented form is un-necessary
          */
-        return mermaid.render(mermaidId, txt);
+        mermaid.render(mermaidId, txt)
+          .then((result) => {
+            setSvgResult(result.svg);
+          });
     }, [txt, mermaidConfig]);
+    
+    return svgResult;
 }
diff --git a/src/client/index.ts b/src/client/index.ts
index f8302085c44155f693aa2c68f4a6d109c5228e4b..3e069146167e4a504e30e337e19ad076fa57a0fa 100644
--- a/src/client/index.ts
+++ b/src/client/index.ts
@@ -5,7 +5,7 @@
  * LICENSE file in the root directory of this source tree.
  */
 
-import {useMemo} from 'react';
+import {useEffect,useMemo,useState } from 'react';
 import {useColorMode, useThemeConfig} from '@docusaurus/theme-common';
 import mermaid, {type MermaidConfig} from 'mermaid';
 import type {ThemeConfig} from '@docusaurus/theme-mermaid';
@@ -40,8 +40,9 @@ export function useMermaidSvg(
    */
   const defaultMermaidConfig = useMermaidConfig();
   const mermaidConfig = mermaidConfigParam ?? defaultMermaidConfig;
+  const [svgResult, setSvgResult] = useState('');
 
-  return useMemo(() => {
+  useEffect(() => {
     /*
     Mermaid API is really weird :s
     It is a big mutable singleton with multiple config levels
@@ -72,6 +73,11 @@ export function useMermaidSvg(
     Not even documented: mermaid.render returns the svg string
     Using the documented form is un-necessary
      */
-    return mermaid.render(mermaidId, txt);
+    mermaid.render(mermaidId, txt)
+      .then((result) => {
+        setSvgResult(result.svg);
+      });
   }, [txt, mermaidConfig]);
+  
+  return svgResult;
 }

@slorber

I read show us a repro as show us a repo so I apoligize for the complexity 🤦‍♂️

That being said, thank you for actually looking into it because that small typo was indeed the issue and now everything is 👌

Thanks again!! 🙏

@Olshansk you shared your prod site source code, this is not a minimal repro.

Here’s a minimal repro proof that Docusaurus can support Mermaid timelines: https://stackblitz.com/edit/github-b3imwp?file=src%2Fpages%2Findex.md,docusaurus.config.ts

CleanShot 2024-02-21 at 10 22 20

If your site doesn’t, then maybe you did something wrong, but I can’t study it in depth to help you so a minimal repro is always preferable than a link to a large open source production site.

As part of the Mermaid v10 upgrade that I’d like to do for Docusaurus v3, we’ll also get new features like Markdown support, requested here: https://github.com/facebook/docusaurus/issues/9296

I assume you also upgraded to v10 right?

Yes, I did add an overrides with pnpm to upgrade to mermaid@10.2.3. So far so good, I have added multiple diagrams per page. I also added a way for each node to be a link[^1].

The only issue I have (and I don’t care in my use case), is that when loading a page, I have an error message while waiting for mermaid to build and provide the diagram to the component.

[^1]:by ejecting the Mermaid component and parsing the resulting SVG to create links where needed since this is not possible with mermaid mindmap.

9.4 mentions mindmap needs renderAsync: https://github.com/mermaid-js/mermaid/releases/tag/v9.4.0

With v10.0 it seems that now Mermaid render always returns a promise (breaking chance) and renderAsync is deprecated or removed:

I guess we should upgrade to Mermaid v10 and handle the promise

While upgrading we should probably also prevent concurrent mermaid rendering issues, cf my comment here: https://github.com/facebook/docusaurus/issues/8357#issuecomment-1582229887