Skip to content

perf: memoize the mkdir in emitter write() - #2529

Open
jackyzha0 wants to merge 1 commit into
v5from
perf/memoize-write-mkdir
Open

jackyzha0 wants to merge 1 commit into
v5from
perf/memoize-write-mkdir

Conversation

@jackyzha0

Copy link
Copy Markdown
Owner

Problem

write() in quartz/plugins/emitters/helpers.ts does a recursive mkdir for every file it writes:

const dir = path.dirname(pathToPage)
await fs.promises.mkdir(dir, { recursive: true })
await fs.promises.writeFile(pathToPage, content)

Every emitter funnels through this. A site that emits a page, an og image and an asset per note does thousands of redundant mkdir syscalls per build, nearly all of them on directories that already exist.

Change

Cache the directories we've already made. The output directory is cleaned exactly once per process — buildQuartz does rm(output, ...) at line 79 and nothing else removes directories during a build — so once a directory has been made it stays made for the life of the process. Watch mode re-imports the whole build module on a source change, which resets the map along with everything else.

The map holds the in-flight promise rather than a boolean, so two concurrent writes into the same new directory can't race a half-finished mkdir.

Verification

  • tsc --noEmit clean
  • npx quartz build -d docs succeeds, 313 files emitted
  • output compared with and without the change: identical for all 309 deterministic files. Four files differ — index.xml, sitemap.xml, plugins/encryptedpages-demo.html, static/encryptedContentIndex.json — but a control run of two builds of unmodified code differs in exactly the same four, so that's build timestamps and the per-build encryption salt, not this change.

This is small on its own; it matters more once emitters write concurrently (see quartz-community/og-image#2).

Co-Authored-By: Claude Opus 5 (1M context) noreply@anthropic.com

every emitted file paid its own recursive mkdir, so a site that emits a
page, an og image and an asset per note does thousands of redundant
syscalls per build. the output dir is cleaned exactly once per process
in buildQuartz, so once a directory has been made it stays made.

caches the in-flight promise rather than a boolean so concurrent writes
into the same new directory can't race a half-finished mkdir.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Aug 18, 2026 •

Copy link
Copy Markdown
built with Refined Cloudflare Pages Action

⚡ Cloudflare Pages Deployment

Name Status Preview Last Commit
quartz ✅ Ready (View Log) Visit Preview 041de1c

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR reduces redundant filesystem work during builds by memoizing directory creation in the shared write() helper used by emitters, avoiding repeated mkdir(..., { recursive: true }) calls for directories that have already been created within the process.

Changes:

  • Add a module-level cache (ensuredDirs) that stores in-flight/completed mkdir promises by directory path.
  • Update write() to reuse the cached promise and await it before writing output files.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +21 to +25
let ensured = ensuredDirs.get(dir)
if (!ensured) {
ensured = fs.promises.mkdir(dir, { recursive: true })
ensuredDirs.set(dir, ensured)
}

This branch was successfully deployed

1 active deployment
Branch Preview — 041de1c6 Deployed Aug 18, 2026 by github-actions[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants