Skip to content

Commit dd69c1c

Browse files
authored
refactor: fix mermaid in production (#6149)
Use dynamic CDN import to use Mermaid as Parcel has issues on handling the static import in production.
1 parent 88dd7d2 commit dd69c1c

File tree

2 files changed

+29
-20
lines changed

2 files changed

+29
-20
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
11
import { Theme } from '@logto/schemas';
2-
import mermaid from 'mermaid';
2+
import { type Mermaid as MermaidType } from 'mermaid';
33
import { useEffect } from 'react';
44

55
import useTheme from '@/hooks/use-theme';
66

7-
mermaid.initialize({
8-
startOnLoad: true,
9-
theme: 'default',
10-
securityLevel: 'loose',
11-
fontFamily: 'Fira Code',
12-
});
7+
const loadMermaid = async () => {
8+
// Define this variable to "outsmart" the detection of the dynamic import by Parcel:
9+
// https://github.com/parcel-bundler/parcel/issues/7064#issuecomment-942441649
10+
const uri = 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs';
11+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
12+
const imported: { default: MermaidType } = await import(uri);
13+
return imported.default;
14+
};
15+
16+
const mermaidPromise = loadMermaid();
1317

1418
type Props = {
1519
readonly children: string;
@@ -24,14 +28,16 @@ export default function Mermaid({ children }: Props) {
2428
const theme = useTheme();
2529

2630
useEffect(() => {
27-
mermaid.initialize({
28-
theme: themeToMermaidTheme[theme],
29-
});
31+
(async () => {
32+
const mermaid = await mermaidPromise;
33+
mermaid.initialize({
34+
startOnLoad: false,
35+
theme: themeToMermaidTheme[theme],
36+
securityLevel: 'loose',
37+
});
38+
await mermaid.run();
39+
})();
3040
}, [theme]);
3141

32-
useEffect(() => {
33-
mermaid.contentLoaded();
34-
}, []);
35-
3642
return <div className="mermaid">{children}</div>;
3743
}

packages/core/src/middleware/koa-security-headers.ts

+9-6
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,16 @@ export default function koaSecurityHeaders<StateT, ContextT, ResponseBodyT>(
4141
/** Google Sign-In (GSI) origin for Google One Tap. */
4242
const gsiOrigin = 'https://accounts.google.com/gsi/';
4343

44-
// We use react-monaco-editor for code editing in the admin console. It loads the monaco editor asynchronously from a CDN.
44+
// We have the following use cases:
45+
//
46+
// 1. We use `react-monaco-editor` for code editing in the admin console. It loads the monaco
47+
// editor asynchronously from jsDelivr.
48+
// 2. We use `mermaid` for rendering diagrams in the admin console. It loads the mermaid library
49+
// asynchronously from jsDelivr since Parcel has issues with loading it directly in production.
50+
//
4551
// Allow the CDN src in the CSP.
4652
// Allow blob: for monaco editor to load worker scripts
47-
const monacoEditorCDNSource = [
48-
'https://cdn.jsdelivr.net/npm/[email protected]/min/vs/',
49-
'blob:',
50-
];
53+
const cdnSources = ['https://cdn.jsdelivr.net/', 'blob:'];
5154

5255
/**
5356
* Default Applied rules:
@@ -122,7 +125,7 @@ export default function koaSecurityHeaders<StateT, ContextT, ResponseBodyT>(
122125
scriptSrc: [
123126
"'self'",
124127
...conditionalArray(!isProduction && ["'unsafe-eval'", "'unsafe-inline'"]),
125-
...monacoEditorCDNSource,
128+
...cdnSources,
126129
],
127130
connectSrc: ["'self'", logtoOrigin, ...adminOrigins, ...coreOrigins, ...developmentOrigins],
128131
// Allow Main Flow origin loaded in preview iframe

0 commit comments

Comments
 (0)