From 3698b30809d7c95f5babb5a12b90ccb0c3a2f64b Mon Sep 17 00:00:00 2001 From: Sidharth Vinod Date: Sat, 8 Oct 2022 13:14:16 +0800 Subject: [PATCH] fix: Optimize diagram loading --- packages/mermaid/src/__mocks__/mermaidAPI.ts | 6 +- .../mermaid/src/diagram-api/detectType.ts | 2 + .../src/diagram-api/diagram-orchestration.ts | 63 +++++++------------ .../src/diagram-api/diagramAPI.spec.ts | 19 +++--- .../mermaid/src/diagram-api/diagramAPI.ts | 8 +-- packages/mermaid/src/mermaid.ts | 6 -- packages/mermaid/src/mermaidAPI.ts | 19 +----- 7 files changed, 44 insertions(+), 79 deletions(-) diff --git a/packages/mermaid/src/__mocks__/mermaidAPI.ts b/packages/mermaid/src/__mocks__/mermaidAPI.ts index f15db139f..08c5b7eea 100644 --- a/packages/mermaid/src/__mocks__/mermaidAPI.ts +++ b/packages/mermaid/src/__mocks__/mermaidAPI.ts @@ -11,17 +11,13 @@ import Diagram from '../Diagram'; // Normally, we could just do the following to get the original `parse()` // implementation, however, requireActual returns a promise and it's not documented how to use withing mock file. -let hasLoadedDiagrams = false; /** * @param text * @param parseError */ // eslint-disable-next-line @typescript-eslint/ban-types function parse(text: string, parseError?: Function): boolean { - if (!hasLoadedDiagrams) { - addDiagrams(); - hasLoadedDiagrams = true; - } + addDiagrams(); const diagram = new Diagram(text, parseError); return diagram.parse(text, parseError); } diff --git a/packages/mermaid/src/diagram-api/detectType.ts b/packages/mermaid/src/diagram-api/detectType.ts index d7ae4ffdf..9536fded2 100644 --- a/packages/mermaid/src/diagram-api/detectType.ts +++ b/packages/mermaid/src/diagram-api/detectType.ts @@ -1,4 +1,5 @@ import { MermaidConfig } from '../config.type'; +import { log } from '../logger'; import { DetectorRecord, DiagramDetector, DiagramLoader } from './types'; const directive = @@ -47,6 +48,7 @@ export const addDetector = (key: string, detector: DiagramDetector, loader?: Dia throw new Error(`Detector with key ${key} already exists`); } detectors[key] = { detector, loader }; + log.debug(`Detector with key ${key} added${loader ? ' with loader' : ''}`); }; export const getDiagramLoader = (key: string) => detectors[key].loader; diff --git a/packages/mermaid/src/diagram-api/diagram-orchestration.ts b/packages/mermaid/src/diagram-api/diagram-orchestration.ts index ec73e445d..a26edb303 100644 --- a/packages/mermaid/src/diagram-api/diagram-orchestration.ts +++ b/packages/mermaid/src/diagram-api/diagram-orchestration.ts @@ -1,12 +1,4 @@ -import { registerDiagram, registerDetector } from './diagramAPI'; -import { DiagramDefinition, DiagramDetector } from './types'; - -// // @ts-ignore: TODO Fix ts errors -// import mindmapParser from '../diagrams/mindmap/parser/mindmap'; -// import * as mindmapDb from '../diagrams/mindmap/mindmapDb'; -// import { mindmapDetector } from '../diagrams/mindmap/mindmapDetector'; -// import mindmapRenderer from '../diagrams/mindmap/mindmapRenderer'; -// import mindmapStyles from '../diagrams/mindmap/styles'; +import { registerDiagram } from './diagramAPI'; // @ts-ignore: TODO Fix ts errors import gitGraphParser from '../diagrams/git/parser/gitGraph'; @@ -102,17 +94,15 @@ import { setConfig } from '../config'; import errorRenderer from '../diagrams/error/errorRenderer'; import errorStyles from '../diagrams/error/styles'; -const registerDiagramAndDetector = ( - id: string, - diagram: DiagramDefinition, - detector: DiagramDetector -) => { - registerDiagram(id, diagram); - registerDetector(id, detector); -}; - +let hasLoadedDiagrams = false; export const addDiagrams = () => { - registerDiagramAndDetector( + if (hasLoadedDiagrams) { + return; + } + // This is added here to avoid race-conditions. + // We could optimize the loading logic somehow. + hasLoadedDiagrams = true; + registerDiagram( 'error', // Special diagram with error messages but setup as a regular diagram { @@ -136,7 +126,7 @@ export const addDiagrams = () => { (text) => text.toLowerCase().trim() === 'error' ); - registerDiagramAndDetector( + registerDiagram( 'c4', { parser: c4Parser, @@ -149,7 +139,7 @@ export const addDiagrams = () => { }, c4Detector ); - registerDiagramAndDetector( + registerDiagram( 'class', { parser: classParser, @@ -166,7 +156,7 @@ export const addDiagrams = () => { }, classDetector ); - registerDiagramAndDetector( + registerDiagram( 'classDiagram', { parser: classParser, @@ -183,7 +173,7 @@ export const addDiagrams = () => { }, classDetectorV2 ); - registerDiagramAndDetector( + registerDiagram( 'er', { parser: erParser, @@ -193,7 +183,7 @@ export const addDiagrams = () => { }, erDetector ); - registerDiagramAndDetector( + registerDiagram( 'gantt', { parser: ganttParser, @@ -203,7 +193,7 @@ export const addDiagrams = () => { }, ganttDetector ); - registerDiagramAndDetector( + registerDiagram( 'info', { parser: infoParser, @@ -213,7 +203,7 @@ export const addDiagrams = () => { }, infoDetector ); - registerDiagramAndDetector( + registerDiagram( 'pie', { parser: pieParser, @@ -223,7 +213,7 @@ export const addDiagrams = () => { }, pieDetector ); - registerDiagramAndDetector( + registerDiagram( 'requirement', { parser: requirementParser, @@ -233,7 +223,7 @@ export const addDiagrams = () => { }, requirementDetector ); - registerDiagramAndDetector( + registerDiagram( 'sequence', { parser: sequenceParser, @@ -256,7 +246,7 @@ export const addDiagrams = () => { }, sequenceDetector ); - registerDiagramAndDetector( + registerDiagram( 'state', { parser: stateParser, @@ -273,7 +263,7 @@ export const addDiagrams = () => { }, stateDetector ); - registerDiagramAndDetector( + registerDiagram( 'stateDiagram', { parser: stateParser, @@ -290,7 +280,7 @@ export const addDiagrams = () => { }, stateDetectorV2 ); - registerDiagramAndDetector( + registerDiagram( 'journey', { parser: journeyParser, @@ -305,7 +295,7 @@ export const addDiagrams = () => { journeyDetector ); - registerDiagramAndDetector( + registerDiagram( 'flowchart', { parser: flowParser, @@ -325,7 +315,7 @@ export const addDiagrams = () => { }, flowDetector ); - registerDiagramAndDetector( + registerDiagram( 'flowchart-v2', { parser: flowParser, @@ -346,14 +336,9 @@ export const addDiagrams = () => { }, flowDetectorV2 ); - registerDiagramAndDetector( + registerDiagram( 'gitGraph', { parser: gitGraphParser, db: gitGraphDb, renderer: gitGraphRenderer, styles: gitGraphStyles }, gitGraphDetector ); - // registerDiagram( - // 'mindmap', - // { parser: mindmapParser, db: mindmapDb, renderer: mindmapRenderer, styles: mindmapStyles }, - // mindmapDetector - // ); }; diff --git a/packages/mermaid/src/diagram-api/diagramAPI.spec.ts b/packages/mermaid/src/diagram-api/diagramAPI.spec.ts index 98e38c5c5..ea546fbb6 100644 --- a/packages/mermaid/src/diagram-api/diagramAPI.spec.ts +++ b/packages/mermaid/src/diagram-api/diagramAPI.spec.ts @@ -1,5 +1,5 @@ import { detectType } from './detectType'; -import { getDiagram, registerDiagram, registerDetector } from './diagramAPI'; +import { getDiagram, registerDiagram } from './diagramAPI'; import { addDiagrams } from './diagram-orchestration'; import { DiagramDetector } from './types'; @@ -22,13 +22,16 @@ describe('DiagramAPI', () => { const detector: DiagramDetector = (str: string) => { return str.match('loki') !== null; }; - registerDetector('loki', detector); - registerDiagram('loki', { - db: {}, - parser: {}, - renderer: {}, - styles: {}, - }); + registerDiagram( + 'loki', + { + db: {}, + parser: {}, + renderer: {}, + styles: {}, + }, + detector + ); expect(getDiagram('loki')).not.toBeNull(); expect(detectType('loki diagram')).toBe('loki'); }); diff --git a/packages/mermaid/src/diagram-api/diagramAPI.ts b/packages/mermaid/src/diagram-api/diagramAPI.ts index 7db0ecabd..ceb098ce3 100644 --- a/packages/mermaid/src/diagram-api/diagramAPI.ts +++ b/packages/mermaid/src/diagram-api/diagramAPI.ts @@ -23,13 +23,10 @@ export interface Detectors { [key: string]: DiagramDetector; } -export const registerDetector = (id: string, detector: DiagramDetector) => { - addDetector(id, detector, null); -}; - export const registerDiagram = ( id: string, diagram: DiagramDefinition, + detector: DiagramDetector, callback?: ( _log: any, _setLogLevel: any, @@ -39,9 +36,10 @@ export const registerDiagram = ( ) => void ) => { if (diagrams[id]) { - log.warn(`Diagram ${id} already registered.`); + throw new Error(`Diagram ${id} already registered.`); } diagrams[id] = diagram; + addDetector(id, detector); addStylesForDiagram(id, diagram.styles); if (typeof callback !== 'undefined') { callback(log, setLogLevel, getConfig, sanitizeText, setupGraphViewbox); diff --git a/packages/mermaid/src/mermaid.ts b/packages/mermaid/src/mermaid.ts index 875c5411a..b2f346b18 100644 --- a/packages/mermaid/src/mermaid.ts +++ b/packages/mermaid/src/mermaid.ts @@ -53,7 +53,6 @@ const init = async function ( callback?: Function ) { try { - log.info('Detectors in init', mermaid.detectors); // eslint-disable-line const conf = mermaidAPI.getConfig(); if (conf?.lazyLoadedDiagrams && conf.lazyLoadedDiagrams.length > 0) { // Load all lazy loaded diagrams in parallel @@ -64,9 +63,6 @@ const init = async function ( }) ); } - mermaid.detectors.forEach(({ id, detector, path }) => { - addDetector(id, detector, path); - }); await initThrowsErrors(config, nodes, callback); } catch (e) { log.warn('Syntax Error rendering'); @@ -251,7 +247,6 @@ const mermaid: { contentLoaded: typeof contentLoaded; setParseErrorHandler: typeof setParseErrorHandler; // Array of functions to use for detecting diagram types - detectors: Array; // eslint-disable-line @typescript-eslint/no-explicit-any connectDiagram: (id: string, diagram: DiagramDefinition, callback: (id: string) => void) => void; } = { startOnLoad: true, @@ -265,7 +260,6 @@ const mermaid: { parseError: undefined, contentLoaded, setParseErrorHandler, - detectors: [], connectDiagram: connectDiagram, }; diff --git a/packages/mermaid/src/mermaidAPI.ts b/packages/mermaid/src/mermaidAPI.ts index f9544ee44..7c967e5fd 100644 --- a/packages/mermaid/src/mermaidAPI.ts +++ b/packages/mermaid/src/mermaidAPI.ts @@ -18,7 +18,6 @@ import { compile, serialize, stringify } from 'stylis'; import pkg from '../package.json'; import * as configApi from './config'; import { addDiagrams } from './diagram-api/diagram-orchestration'; -import { addDetector } from './diagram-api/detectType'; import classDb from './diagrams/class/classDb'; import flowDb from './diagrams/flowchart/flowDb'; import flowRenderer from './diagrams/flowchart/flowRenderer'; @@ -34,18 +33,13 @@ import DOMPurify from 'dompurify'; import { MermaidConfig } from './config.type'; import { evaluate } from './diagrams/common/common'; -let hasLoadedDiagrams = false; - /** * @param text * @param parseError */ // eslint-disable-next-line @typescript-eslint/ban-types function parse(text: string, parseError?: Function): boolean { - if (!hasLoadedDiagrams) { - addDiagrams(); - hasLoadedDiagrams = true; - } + addDiagrams(); const diagram = new Diagram(text, parseError); return diagram.parse(text, parseError); } @@ -122,10 +116,7 @@ const render = async function ( cb: (svgCode: string, bindFunctions?: (element: Element) => void) => void, container?: Element ): Promise { - if (!hasLoadedDiagrams) { - addDiagrams(); - hasLoadedDiagrams = true; - } + addDiagrams(); configApi.reset(); text = text.replace(/\r\n?/g, '\n'); // parser problems on CRLF ignore all CR and leave LF;; const graphInit = utils.detectInit(text); @@ -486,11 +477,7 @@ async function initialize(options: MermaidConfig) { typeof options === 'object' ? configApi.setSiteConfig(options) : configApi.getSiteConfig(); setLogLevel(config.logLevel); - - if (!hasLoadedDiagrams) { - addDiagrams(); - hasLoadedDiagrams = true; - } + addDiagrams(); } export const mermaidAPI = Object.freeze({