From 4625efda7f61e3abf6f18d352ba341438cd21f21 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Thu, 8 Jan 2026 16:50:27 +0200 Subject: [PATCH] fix(note_list): skip rendering of included notes for performance (closes #8017) --- apps/client/src/services/content_renderer.ts | 2 ++ .../services/content_renderer_text.spec.ts | 21 +++++++++++++++++++ .../src/services/content_renderer_text.ts | 6 +++++- .../collections/legacy/ListOrGridView.tsx | 3 ++- 4 files changed, 30 insertions(+), 2 deletions(-) diff --git a/apps/client/src/services/content_renderer.ts b/apps/client/src/services/content_renderer.ts index 9b059101c..38bb779ac 100644 --- a/apps/client/src/services/content_renderer.ts +++ b/apps/client/src/services/content_renderer.ts @@ -23,6 +23,8 @@ export interface RenderOptions { imageHasZoom?: boolean; /** If enabled, it will prevent the default behavior in which an empty note would display a list of children. */ noChildrenList?: boolean; + /** If enabled, it will prevent rendering of included notes. */ + noIncludedNotes?: boolean; /** Set of note IDs that have already been seen during rendering to prevent infinite recursion. */ seenNoteIds?: Set; } diff --git a/apps/client/src/services/content_renderer_text.spec.ts b/apps/client/src/services/content_renderer_text.spec.ts index 3bd9b6554..6480e1991 100644 --- a/apps/client/src/services/content_renderer_text.spec.ts +++ b/apps/client/src/services/content_renderer_text.spec.ts @@ -27,6 +27,27 @@ describe("Text content renderer", () => { expect(contentEl.querySelectorAll("section.include-note p").length).toBe(1); }); + it("skips rendering included note", async () => { + const contentEl = document.createElement("div"); + const includedNote = buildNote({ + title: "Included note", + content: "

This is the included note.

" + }); + const note = buildNote({ + title: "New note", + content: trimIndentation` +

+ Hi there +

+
+   +
+ ` + }); + await renderText(note, $(contentEl), { noIncludedNotes: true }); + expect(contentEl.querySelectorAll("section.include-note").length).toBe(0); + }); + it("doesn't enter infinite loop on direct recursion", async () => { const contentEl = document.createElement("div"); const note = buildNote({ diff --git a/apps/client/src/services/content_renderer_text.ts b/apps/client/src/services/content_renderer_text.ts index 72d67d4d5..a3f277c49 100644 --- a/apps/client/src/services/content_renderer_text.ts +++ b/apps/client/src/services/content_renderer_text.ts @@ -18,7 +18,11 @@ export default async function renderText(note: FNote | FAttachment, $renderedCon const seenNoteIds = options.seenNoteIds ?? new Set(); seenNoteIds.add("noteId" in note ? note.noteId : note.attachmentId); - await renderIncludedNotes($renderedContent[0], seenNoteIds); + if (!options.noIncludedNotes) { + await renderIncludedNotes($renderedContent[0], seenNoteIds); + } else { + $renderedContent.find("section.include-note").remove(); + } if ($renderedContent.find("span.math-tex").length > 0) { renderMathInElement($renderedContent[0], { trust: true }); diff --git a/apps/client/src/widgets/collections/legacy/ListOrGridView.tsx b/apps/client/src/widgets/collections/legacy/ListOrGridView.tsx index 8180e6d65..9a0c7391d 100644 --- a/apps/client/src/widgets/collections/legacy/ListOrGridView.tsx +++ b/apps/client/src/widgets/collections/legacy/ListOrGridView.tsx @@ -153,7 +153,8 @@ function NoteContent({ note, trim, noChildrenList, highlightedTokens }: { note: useEffect(() => { content_renderer.getRenderedContent(note, { trim, - noChildrenList + noChildrenList, + noIncludedNotes: true }) .then(({ $renderedContent, type }) => { if (!contentRef.current) return;