mirror of
https://github.com/livebook-dev/livebook.git
synced 2025-10-24 12:26:07 +08:00
Cache mermaid graph rendering (#1023)
* Cache mermaid graph rendering * Bump mermaid * Update naming
This commit is contained in:
parent
ca0128d028
commit
f699575b45
3 changed files with 81 additions and 29 deletions
|
|
@ -1,3 +1,6 @@
|
|||
import { md5Base64 } from "../../lib/utils";
|
||||
import CacheLRU from "../../lib/cache_lru";
|
||||
|
||||
let idCount = 0;
|
||||
let getId = () => `mermaid-graph-${idCount++}`;
|
||||
|
||||
|
|
@ -5,6 +8,32 @@ let mermaidInitialized = false;
|
|||
|
||||
const fontAwesomeVersion = "5.15.4";
|
||||
|
||||
const cache = new CacheLRU(25);
|
||||
|
||||
/**
|
||||
* Renders SVG graph from mermaid definition.
|
||||
*/
|
||||
export function renderMermaid(definition) {
|
||||
const hash = md5Base64(definition);
|
||||
const svg = cache.get(hash);
|
||||
|
||||
if (svg) {
|
||||
return Promise.resolve(svg);
|
||||
}
|
||||
|
||||
return importMermaid().then((mermaid) => {
|
||||
injectFontAwesomeIfNeeded(definition);
|
||||
|
||||
try {
|
||||
const svg = mermaid.render(getId(), definition);
|
||||
cache.set(hash, svg);
|
||||
return svg;
|
||||
} catch (e) {
|
||||
return `<div class="error-box whitespace-pre-wrap"><span class="font-semibold">Mermaid</span>\n${e.message}</div>`;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function importMermaid() {
|
||||
return import(
|
||||
/* webpackChunkName: "mermaid" */
|
||||
|
|
@ -18,10 +47,13 @@ function importMermaid() {
|
|||
});
|
||||
}
|
||||
|
||||
const maybeInjectFontAwesome = (value) => {
|
||||
function injectFontAwesomeIfNeeded(definition) {
|
||||
const fontAwesomeUrl = `https://cdnjs.cloudflare.com/ajax/libs/font-awesome/${fontAwesomeVersion}/css/all.min.css`;
|
||||
|
||||
// Graphs may include Font Awesome icons via fa: prefix, so we
|
||||
// load the icon set if needed
|
||||
if (
|
||||
value.includes("fa:") &&
|
||||
definition.includes("fa:") &&
|
||||
!document.querySelector(`link[href="${fontAwesomeUrl}"]`)
|
||||
) {
|
||||
const link = document.createElement("link");
|
||||
|
|
@ -30,17 +62,4 @@ const maybeInjectFontAwesome = (value) => {
|
|||
link.href = fontAwesomeUrl;
|
||||
document.head.appendChild(link);
|
||||
}
|
||||
};
|
||||
|
||||
export function renderMermaid(value) {
|
||||
return importMermaid().then((mermaid) => {
|
||||
// Inject font-awesome when fa: prefix is used
|
||||
maybeInjectFontAwesome(value);
|
||||
|
||||
try {
|
||||
return mermaid.render(getId(), value);
|
||||
} catch (e) {
|
||||
return `<div class="error-box whitespace-pre-wrap"><span class="font-semibold">Mermaid</span>\n${e.message}</div>`;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
33
assets/js/lib/cache_lru.js
Normal file
33
assets/js/lib/cache_lru.js
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/**
|
||||
* A Map-based LRU cache.
|
||||
*/
|
||||
export default class CacheLRU {
|
||||
constructor(size) {
|
||||
this.size = size;
|
||||
this.cache = new Map();
|
||||
}
|
||||
|
||||
get(key) {
|
||||
if (this.cache.has(key)) {
|
||||
const value = this.cache.get(key);
|
||||
// Map keys are stored and iterated in insertion order,
|
||||
// so we reinsert on every access
|
||||
this.cache.delete(key);
|
||||
this.cache.set(key, value);
|
||||
return value;
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
set(key, value) {
|
||||
if (this.cache.has(key)) {
|
||||
this.cache.delete(key);
|
||||
} else if (this.cache.size === this.size) {
|
||||
const oldestKey = this.cache.keys().next().value;
|
||||
this.cache.delete(oldestKey);
|
||||
}
|
||||
|
||||
this.cache.set(key, value);
|
||||
}
|
||||
}
|
||||
28
assets/package-lock.json
generated
28
assets/package-lock.json
generated
|
|
@ -5007,9 +5007,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/dompurify": {
|
||||
"version": "2.3.4",
|
||||
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.3.4.tgz",
|
||||
"integrity": "sha512-6BVcgOAVFXjI0JTjEvZy901Rghm+7fDQOrNIcxB4+gdhj6Kwp6T9VBhBY/AbagKHJocRkDYGd6wvI+p4/10xtQ=="
|
||||
"version": "2.3.5",
|
||||
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.3.5.tgz",
|
||||
"integrity": "sha512-kD+f8qEaa42+mjdOpKeztu9Mfx5bv9gVLO6K9jRx4uGvh6Wv06Srn4jr1wPNY2OOUGGSKHNFN+A8MA3v0E0QAQ=="
|
||||
},
|
||||
"node_modules/domutils": {
|
||||
"version": "2.8.0",
|
||||
|
|
@ -8810,15 +8810,15 @@
|
|||
}
|
||||
},
|
||||
"node_modules/mermaid": {
|
||||
"version": "8.13.9",
|
||||
"resolved": "https://registry.npmjs.org/mermaid/-/mermaid-8.13.9.tgz",
|
||||
"integrity": "sha512-kMH676xEomSe/gzxMpDx91L+z9L+9iB3lvtPFA8aeOPRNNrfd3ZDvDCGFnuqQaJvPRCxs3Me2JDaVVNOZjojrg==",
|
||||
"version": "8.14.0",
|
||||
"resolved": "https://registry.npmjs.org/mermaid/-/mermaid-8.14.0.tgz",
|
||||
"integrity": "sha512-ITSHjwVaby1Li738sxhF48sLTxcNyUAoWfoqyztL1f7J6JOLpHOuQPNLBb6lxGPUA0u7xP9IRULgvod0dKu35A==",
|
||||
"dependencies": {
|
||||
"@braintree/sanitize-url": "^3.1.0",
|
||||
"d3": "^7.0.0",
|
||||
"dagre": "^0.8.5",
|
||||
"dagre-d3": "^0.6.4",
|
||||
"dompurify": "2.3.4",
|
||||
"dompurify": "2.3.5",
|
||||
"graphlib": "^2.1.8",
|
||||
"khroma": "^1.4.1",
|
||||
"moment-mini": "^2.24.0",
|
||||
|
|
@ -16445,9 +16445,9 @@
|
|||
}
|
||||
},
|
||||
"dompurify": {
|
||||
"version": "2.3.4",
|
||||
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.3.4.tgz",
|
||||
"integrity": "sha512-6BVcgOAVFXjI0JTjEvZy901Rghm+7fDQOrNIcxB4+gdhj6Kwp6T9VBhBY/AbagKHJocRkDYGd6wvI+p4/10xtQ=="
|
||||
"version": "2.3.5",
|
||||
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.3.5.tgz",
|
||||
"integrity": "sha512-kD+f8qEaa42+mjdOpKeztu9Mfx5bv9gVLO6K9jRx4uGvh6Wv06Srn4jr1wPNY2OOUGGSKHNFN+A8MA3v0E0QAQ=="
|
||||
},
|
||||
"domutils": {
|
||||
"version": "2.8.0",
|
||||
|
|
@ -19230,15 +19230,15 @@
|
|||
"integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="
|
||||
},
|
||||
"mermaid": {
|
||||
"version": "8.13.9",
|
||||
"resolved": "https://registry.npmjs.org/mermaid/-/mermaid-8.13.9.tgz",
|
||||
"integrity": "sha512-kMH676xEomSe/gzxMpDx91L+z9L+9iB3lvtPFA8aeOPRNNrfd3ZDvDCGFnuqQaJvPRCxs3Me2JDaVVNOZjojrg==",
|
||||
"version": "8.14.0",
|
||||
"resolved": "https://registry.npmjs.org/mermaid/-/mermaid-8.14.0.tgz",
|
||||
"integrity": "sha512-ITSHjwVaby1Li738sxhF48sLTxcNyUAoWfoqyztL1f7J6JOLpHOuQPNLBb6lxGPUA0u7xP9IRULgvod0dKu35A==",
|
||||
"requires": {
|
||||
"@braintree/sanitize-url": "^3.1.0",
|
||||
"d3": "^7.0.0",
|
||||
"dagre": "^0.8.5",
|
||||
"dagre-d3": "^0.6.4",
|
||||
"dompurify": "2.3.4",
|
||||
"dompurify": "2.3.5",
|
||||
"graphlib": "^2.1.8",
|
||||
"khroma": "^1.4.1",
|
||||
"moment-mini": "^2.24.0",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue