perf: load document libraries only when needed

This commit is contained in:
tdurieux
2026-09-09 13:28:44 +02:00
parent 984906a89a
commit e68ab037eb
15 changed files with 151 additions and 53 deletions
+7 -2
View File
@@ -1,6 +1,11 @@
{
"core.min.js": "core.c5bd53363a.min.js",
"vendor.min.js": "vendor.abcdded7b8.min.js",
"vendor.min.js": "vendor.af902bc3b4.min.js",
"mermaid.min.js": "mermaid.f848a72d16.min.js",
"all.min.css": "all.076c089579.min.css"
"all.min.css": "all.076c089579.min.css",
"markdown.min.js": "markdown.ad7b1d71c3.min.js",
"pdf.min.js": "pdf.eaa7573247.min.js",
"notebook.min.js": "notebook.8844e2735f.min.js",
"org.min.js": "org.f4e2a3f59f.min.js",
"editor.min.js": "editor.e243722d87.min.js"
}
+25 -9
View File
@@ -1,4 +1,5 @@
import { h, ref, watch, onMounted, onBeforeUnmount, nextTick } from "vue";
import { loadLibrary, loadEditor } from "./lazy-assets.js";
import { h, ref, watch, onMounted, onBeforeUnmount, nextTick, defineAsyncComponent } from "vue";
import HtmlDoc from "./html-doc.js";
import PdfViewer from "./pdf-viewer.js";
@@ -44,6 +45,7 @@ const Notebook = {
request = new AbortController();
try {
const json = props.content ? JSON.parse(props.content) : await fetch(props.file?.download_url || props.file, { signal: request.signal }).then(r => { if (!r.ok) throw Error("Notebook request failed"); return r.json(); });
await loadLibrary("notebook");
if (current !== generation) return;
host.value.innerHTML = DOMPurify.sanitize(nb.parse(json).render());
host.value.querySelectorAll("pre code").forEach(el => window.Prism?.highlightElement(el));
@@ -64,21 +66,35 @@ const Loc = {
};
},
};
export const components = { Markdown, GistFile, Notebook, Loc, HtmlDoc, Pdfviewer: PdfViewer };
export const components = { Markdown, GistFile, Notebook, Loc, HtmlDoc, Pdfviewer: defineAsyncComponent(async () => {
await loadLibrary("pdf");
pdfjsLib.GlobalWorkerOptions.workerSrc = "/script/external/pdf.worker.js";
return PdfViewer;
}) };
export const codeEditor = {
mounted(el, { value }) {
const editor = ace.edit(el);
el._editor = editor;
editor.setValue(String(value.content ?? ""), -1);
applyEditorOptions(el, value.options);
value.options?.onLoad?.(editor);
async mounted(el, { value }) {
el._editorValue = value;
try {
await loadEditor();
if (el._editorDisposed) return;
const latest = el._editorValue;
const editor = ace.edit(el);
el._editor = editor;
editor.setValue(String(latest.content ?? ""), -1);
applyEditorOptions(el, latest.options);
latest.options?.onLoad?.(editor);
} catch (error) {
if (!el._editorDisposed) el.textContent = error.message;
}
},
updated(el, { value }) {
el._editorValue = value;
if (!el._editor) return;
if (el._editor.getValue() !== String(value.content ?? "")) el._editor.setValue(String(value.content ?? ""), -1);
applyEditorOptions(el, value.options);
},
beforeUnmount(el) { el._editor.destroy(); },
beforeUnmount(el) { el._editorDisposed = true; el._editor?.destroy(); },
};
function applyEditorOptions(el, options = {}) {
if (options.mode) el._editor.session.setMode("ace/mode/" + options.mode);
+1
View File
File diff suppressed because one or more lines are too long
+24
View File
@@ -0,0 +1,24 @@
const pending = new Map();
// Generated from the completed library bundles, so deployments invalidate caches.
const assets = __LAZY_ASSETS__;
export function loadLibrary(name) {
if (!pending.has(name)) {
const script = document.createElement("script");
script.src = assets[name];
const promise = new Promise((resolve, reject) => {
script.onload = resolve;
script.onerror = () => {
pending.delete(name);
script.remove();
reject(new Error(`Unable to load ${name}. Please retry.`));
};
});
pending.set(name, promise);
document.head.appendChild(script);
}
return pending.get(name);
}
export async function loadEditor() {
await loadLibrary("editor");
ace.config.set("basePath", "/script/external/ace/");
}
+8 -3
View File
@@ -1,3 +1,4 @@
import { loadLibrary } from "./lazy-assets.js";
import { createApp, h, watch, provide, inject, onBeforeUnmount } from "vue";
import { createRouter, createWebHistory, RouterView } from "vue-router";
import { pageRoutes } from "./routes.js";
@@ -116,7 +117,13 @@ export function mountApplication(target = "#app", options = {}) {
app.directive("code-editor", codeEditor);
app.directive("paper-scrollspy", paperScrollspy);
app.use(router);
router.beforeEach(() => { root?.emit("routeLeave"); });
router.beforeEach(async to => {
root?.emit("routeLeave");
if (/^\/(r|repository|anonymize|pull-request-anonymize|gist-anonymize|pr|gist)(\/|$)/.test(to.path)) {
await loadLibrary("markdown");
}
if (/^\/(r|repository)\//.test(to.path)) await loadLibrary("org");
});
router.afterEach(to => {
if (!root) return;
root.title = to.meta.title;
@@ -129,6 +136,4 @@ export function mountApplication(target = "#app", options = {}) {
return { app, router, state: root };
}
ace.config.set("basePath", "/script/external/ace/");
pdfjsLib.GlobalWorkerOptions.workerSrc = "/script/external/pdf.worker.js";
if (document.querySelector("#app")) window.anonymousApp = mountApplication();
+1
View File
File diff suppressed because one or more lines are too long
+1
View File
File diff suppressed because one or more lines are too long
+1
View File
File diff suppressed because one or more lines are too long
+2
View File
File diff suppressed because one or more lines are too long
+20 -22
View File
File diff suppressed because one or more lines are too long