Skip to content

perf(core): keep admin-only code off a site's first request - #4596

Draft
eisenbruch wants to merge 1 commit into
emdash-cms:mainfrom
eisenbruch:perf/lazy-runtime-handlers
Draft

eisenbruch wants to merge 1 commit into
emdash-cms:mainfrom
eisenbruch:perf/lazy-runtime-handlers

Conversation

@eisenbruch

Copy link
Copy Markdown
Contributor

What does this PR do?

Refs #3313 (our issue). Two small changes that shrink what a site evaluates when its middleware first loads:

  1. emdash-runtime.ts imported its content, media and revision handlers and the schema registry through ./index.js, the package's main barrel. Those names now come from their own modules.
  2. packages/core/package.json declares sideEffects. Without it a bundler must keep every module the barrel reaches, so a site that imports getEmDashCollection from emdash (every site) evaluated the API schemas, the WordPress importer, the seed applier and similar code before its first page. The list is **/*.astro and **/*.css (component styles) plus ./src/import/index.ts, the one source module that does work at import time: it registers the built-in import sources. Without that entry the registrations vanish from the build silently. I hit this while testing.

A new test, tests/unit/package-side-effects.test.ts, fails if a source module with a top-level call is missing from the list (I checked that it fails without the importer entry), or if the runtime imports the barrel again.

Nothing is removed from the bundle; the code moves to chunks loaded by the admin, API and import routes that use it.

Draft because the real-Workers gain is unproven. Measured on our site (EmDash 1.4.0 with this change applied, Astro 7, Cloudflare):

before after
static closure of core's dist/astro/middleware.mjs (on main) 174 files, 3.09 MiB 143 files, 2.34 MiB
site Worker closure with the middleware forced into startup 200 files, 4.16 MiB 179 files, 3.52 MiB
wrangler check startup, same forced build, median of 5 (laptop) 75 ms 54 ms
Cloudflare "Worker Startup Time", same forced build, 3 uploads each 180, 214, 213 ms 91, 170, 98 ms
billed CPU of the first request on a new isolate, dev, A/B/A then B/A/B in one hour median 153 ms (n=21) median 158 ms (n=28)

So the startup measures #3313 used move clearly, but with the middleware loaded lazily as Astro does by default, I could not see a change in billed first-request CPU or wall time. My guess is that Cloudflare caches compiled code across isolates, so evaluation is cheaper in production than a startup measurement suggests, but I have not confirmed that. My issue said this cost lands on most requests; this data does not support that, and I will correct it on the issue. The change still lowers what counts against the startup limit for any setup that evaluates the middleware at startup.

Rendered output was identical: 26 pages on our dev site (home, lists, articles, events, listings, topics, search, sitemaps) compared across the A/B/A after removing per-request ids. The admin login page, MCP reads and a cron run worked on the changed build.

Type of change

  • Performance improvement

Your connection to this change

  • I use EmDash and ran into the problem this PR addresses

Checklist

  • I have read CONTRIBUTING.md
  • pnpm typecheck passes (core)
  • pnpm lint passes (oxlint --type-aware --deny-warnings, repo-wide)
  • pnpm test passes (or targeted tests for my change): core unit tests, 494 files, 6,384 tests
  • pnpm format has been run (oxfmt --check clean repo-wide)
  • I have added/updated tests for my changes (if applicable)
  • User-visible strings in the admin UI are wrapped for translation (if applicable): not applicable
  • I have added and reviewed the user-facing changeset (if this PR changes a published package)
  • New features link to their merged design PR: not a feature
  • I have included screenshots below if this PR changes the UI: no UI change

AI assistance disclosure

  • This PR includes AI-generated code or text — model/tool: Claude Opus 5.5 (Claude Code)

Screenshots / test output

Not applicable.

🤖 Generated with Claude Code

https://claude.ai/code/session_01RktNvhjty22ohh1GSHXGMq

emdash-runtime imported its handlers through the package's main barrel, and
the package declared no sideEffects, so any site importing from "emdash"
evaluated the API schemas, the WordPress importer, the seed applier and more
before rendering a page. Import the handlers from their modules and declare
sideEffects, listing src/import/index.ts, which registers the built-in import
sources when it loads. A test fails if a module doing work at import time is
left off the list, or if the runtime goes back to the barrel.

Refs emdash-cms#3313

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RktNvhjty22ohh1GSHXGMq
@changeset-bot

changeset-bot Bot commented Nov 2, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 15dee04

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 12 packages
Name Type
emdash Patch
@emdash-cms/cloudflare Patch
@emdash-cms/plugin-test Patch
@emdash-cms/sandbox-workerd Patch
@emdash-cms/admin Patch
@emdash-cms/auth Patch
@emdash-cms/blocks Patch
create-emdash Patch
@emdash-cms/gutenberg-to-portable-text Patch
@emdash-cms/x402 Patch
@emdash-cms/auth-atproto Patch
@emdash-cms/plugin-embeds Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@pkg-pr-new

pkg-pr-new Bot commented Nov 2, 2026

Copy link
Copy Markdown

Open in StackBlitz

@emdash-cms/admin

npm i https://pkg.pr.new/@emdash-cms/admin@4596

@emdash-cms/auth

npm i https://pkg.pr.new/@emdash-cms/auth@4596

@emdash-cms/auth-atproto

npm i https://pkg.pr.new/@emdash-cms/auth-atproto@4596

@emdash-cms/blocks

npm i https://pkg.pr.new/@emdash-cms/blocks@4596

@emdash-cms/cloudflare

npm i https://pkg.pr.new/@emdash-cms/cloudflare@4596

@emdash-cms/contentful-to-portable-text

npm i https://pkg.pr.new/@emdash-cms/contentful-to-portable-text@4596

emdash

npm i https://pkg.pr.new/emdash@4596

create-emdash

npm i https://pkg.pr.new/create-emdash@4596

@emdash-cms/gutenberg-to-portable-text

npm i https://pkg.pr.new/@emdash-cms/gutenberg-to-portable-text@4596

@emdash-cms/plugin-cli

npm i https://pkg.pr.new/@emdash-cms/plugin-cli@4596

@emdash-cms/plugin-test

npm i https://pkg.pr.new/@emdash-cms/plugin-test@4596

@emdash-cms/plugin-types

npm i https://pkg.pr.new/@emdash-cms/plugin-types@4596

@emdash-cms/registry-client

npm i https://pkg.pr.new/@emdash-cms/registry-client@4596

@emdash-cms/registry-lexicons

npm i https://pkg.pr.new/@emdash-cms/registry-lexicons@4596

@emdash-cms/registry-loader

npm i https://pkg.pr.new/@emdash-cms/registry-loader@4596

@emdash-cms/registry-moderation

npm i https://pkg.pr.new/@emdash-cms/registry-moderation@4596

@emdash-cms/registry-verification

npm i https://pkg.pr.new/@emdash-cms/registry-verification@4596

upgrade-emdash

npm i https://pkg.pr.new/upgrade-emdash@4596

@emdash-cms/sandbox-workerd

npm i https://pkg.pr.new/@emdash-cms/sandbox-workerd@4596

@emdash-cms/x402

npm i https://pkg.pr.new/@emdash-cms/x402@4596

@emdash-cms/plugin-ai-moderation

npm i https://pkg.pr.new/@emdash-cms/plugin-ai-moderation@4596

@emdash-cms/plugin-ai-search

npm i https://pkg.pr.new/@emdash-cms/plugin-ai-search@4596

@emdash-cms/plugin-atproto

npm i https://pkg.pr.new/@emdash-cms/plugin-atproto@4596

@emdash-cms/plugin-audit-log

npm i https://pkg.pr.new/@emdash-cms/plugin-audit-log@4596

@emdash-cms/plugin-color

npm i https://pkg.pr.new/@emdash-cms/plugin-color@4596

@emdash-cms/plugin-embeds

npm i https://pkg.pr.new/@emdash-cms/plugin-embeds@4596

@emdash-cms/plugin-field-kit

npm i https://pkg.pr.new/@emdash-cms/plugin-field-kit@4596

@emdash-cms/plugin-forms

npm i https://pkg.pr.new/@emdash-cms/plugin-forms@4596

@emdash-cms/plugin-webhook-notifier

npm i https://pkg.pr.new/@emdash-cms/plugin-webhook-notifier@4596

commit: 15dee04

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant