From 4f8703d61ccefb61823d4f7bac67f142759d81ca Mon Sep 17 00:00:00 2001 From: Miroma Date: Thu, 30 Jul 2026 12:25:24 +0200 Subject: [PATCH] perf(md): bypass gray-matter's unbounded cache gray-matter memoizes every parsed result in a plain cache object keyed by the full input string, except when it is passed an options object. https://github.com/jonschlinkert/gray-matter/blob/310f9349381775d10a221cef903989eb5acc8843/index.js#L44-L47 such cache is never bounded, or cleared, so on large sites memory usage skyrockets. with this change, we are always passing an empty options object on every call to matter() to bypass its internal cache. Co-authored-by: Calum H. (IMB11) Original-patch-by: Calum H. (IMB11) --- src/node/markdown/markdown.ts | 4 ++++ src/node/utils/processIncludes.ts | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/node/markdown/markdown.ts b/src/node/markdown/markdown.ts index 7ffe1e6d..c067e52a 100644 --- a/src/node/markdown/markdown.ts +++ b/src/node/markdown/markdown.ts @@ -510,6 +510,10 @@ export async function createMarkdownRenderer( if (options.component !== false) { componentPlugin(md, normalizePluginOptions(options.component)) } + // pass an empty options object to gray-matter, otherwise it would memoize + // the results in an unbounded cache, where the key is the full file content. + // https://github.com/jonschlinkert/gray-matter/blob/310f9349381775d10a221cef903989eb5acc8843/index.js#L44-L47 + ;(options.frontmatter ??= {}).grayMatterOptions ??= {} frontmatterPlugin(md, options.frontmatter) if (options.headers) { headersPlugin(md, { diff --git a/src/node/utils/processIncludes.ts b/src/node/utils/processIncludes.ts index afc86b1a..08e02d32 100644 --- a/src/node/utils/processIncludes.ts +++ b/src/node/utils/processIncludes.ts @@ -53,7 +53,7 @@ export function processIncludes( // region not found, it might be a header const headerContent = path.extname(includePath) === '.md' - ? matter(content).content + ? matter(content, {}).content : content const headerLines = headerContent.split(/\r?\n/) const tokens = md @@ -95,7 +95,7 @@ export function processIncludes( } if (!hasMeta && path.extname(includePath) === '.md') { - content = matter(content).content + content = matter(content, {}).content } includes.push(slash(includePath))