Skip to content

fix: resolve plugin source entry before dist to prevent workspace destruction#537

Merged
ascorbic merged 3 commits intoemdash-cms:mainfrom
Glacier-Luo:main
Apr 13, 2026
Merged

fix: resolve plugin source entry before dist to prevent workspace destruction#537
ascorbic merged 3 commits intoemdash-cms:mainfrom
Glacier-Luo:main

Conversation

@Glacier-Luo
Copy link
Copy Markdown
Contributor

What does this PR do?

resolveSourceEntry() checked the direct dist path (e.g. dist/index.mjs) before trying to resolve back to source (src/index.ts). After a full pnpm build, the dist path exists and short-circuits the lookup, causing two problems:

  1. plugin bundle always failsTS_EXT_RE (/\.tsx?$/) cannot strip the .mjs extension, so findBuildOutput searches for index.mjs.mjs which never exists.
  2. Workspace source files destroyed — tsdown receives the .mjs entry and under certain timing conditions triggers a recursive clean that wipes source files across the entire packages/ directory (observed: all of admin, auth, blocks, core, etc. deleted).

The fix reorders resolveSourceEntry() to try src/ paths first and fall back to the direct path only when no source equivalent exists. This matches the function's documented intent (dist/foo.mjs → src/foo.ts).

Why CI didn't catch this: The test job uses --filter emdash... build which only builds core and its dependencies — not the plugins. So dist/index.mjs never exists in CI, and the bug never triggers.

Reproduction: find . -type d \( -name dist -o -name node_modules \) -exec rm -rf {} +pnpm installpnpm buildpnpm test:unit (repeat 2–3 times). Without the fix, marketplace tests fail every run and source files are intermittently destroyed.

Type of change

  • Bug fix

Checklist

  • I have read CONTRIBUTING.md
  • pnpm typecheck passes
  • pnpm lint passes
  • pnpm test passes (or targeted tests for my change)
  • pnpm format has been run
  • I have added/updated tests for my changes (if applicable)
  • User-visible strings in the admin UI are wrapped for translation and pnpm locale:extract has been run (if applicable)
  • I have added a changeset (if this PR changes a published package)
  • New features link to an approved Discussion: https://github.com/emdash-cms/emdash/discussions/...

AI-generated code disclosure

  • This PR includes AI-generated code

Screenshots / test output

Without fix (after pnpm buildpnpm test:unit, 2–3 rounds):

FAIL  tests/publish-e2e.test.ts
Error: Failed to build main entry — no output found in .emdash-bundle-tmp/main
Test Files  1 failed | 4 passed (5)
# Source files destroyed: packages/admin, packages/auth, packages/blocks, packages/core...

With fix (3 rounds of pnpm buildpnpm test:unit):

Test Files  5 passed (5)
Tests       48 passed (48)
# Source file count stable at 1173 across all rounds

…truction

resolveSourceEntry() checked the direct dist path (e.g. dist/index.mjs)
before trying to resolve back to source (src/index.ts). After a full
`pnpm build`, the dist path exists and short-circuits the lookup —
returning a .mjs path that downstream code cannot handle:

1. TS_EXT_RE (/\.tsx?$/) fails to strip the .mjs extension, so
   findBuildOutput searches for index.mjs.mjs (never exists).
2. tsdown receives the .mjs entry with config:false but still reads
   tsconfig.json from CWD. Under certain timing conditions this
   triggers a clean cycle that recursively deletes source files across
   the entire packages/ directory (observed: 73k+ files wiped).

The fix reorders resolveSourceEntry() to try src/ paths first and fall
back to the direct path only when no source equivalent exists. This
matches the function's documented intent ("dist/foo.mjs → src/foo.ts").

Reproduction: clean install → pnpm build → pnpm test:unit (repeat 2-3
times). Without the fix, marketplace publish-e2e tests fail on every
run and source files are intermittently destroyed.
@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Apr 13, 2026

🦋 Changeset detected

Latest commit: c806f29

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

This PR includes changesets to release 9 packages
Name Type
emdash Patch
@emdash-cms/cloudflare Patch
@emdash-cms/admin Patch
@emdash-cms/auth Patch
@emdash-cms/blocks Patch
@emdash-cms/gutenberg-to-portable-text Patch
@emdash-cms/x402 Patch
create-emdash 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

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 13, 2026

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

Copy link
Copy Markdown
Collaborator

@ascorbic ascorbic left a comment

Choose a reason for hiding this comment

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

Yikes. Good find. Thanks

@ascorbic
Copy link
Copy Markdown
Collaborator

Can you add a changeset and sign the CLA

@Glacier-Luo
Copy link
Copy Markdown
Contributor Author

I have read the CLA Document and I hereby sign the CLA

github-actions bot added a commit that referenced this pull request Apr 13, 2026
@Glacier-Luo
Copy link
Copy Markdown
Contributor Author

Sorry about that — I wasn't familiar with the changeset workflow. I've added one now (f96bcdb). Thanks for the heads-up!

@ascorbic ascorbic enabled auto-merge (squash) April 13, 2026 19:56
@ascorbic
Copy link
Copy Markdown
Collaborator

Great, thanks!

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new bot commented Apr 13, 2026

Open in StackBlitz

@emdash-cms/admin

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

@emdash-cms/auth

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

@emdash-cms/blocks

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

@emdash-cms/cloudflare

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

emdash

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

create-emdash

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

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

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

@emdash-cms/x402

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

@emdash-cms/plugin-ai-moderation

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

@emdash-cms/plugin-atproto

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

@emdash-cms/plugin-audit-log

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

@emdash-cms/plugin-color

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

@emdash-cms/plugin-embeds

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

@emdash-cms/plugin-forms

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

@emdash-cms/plugin-webhook-notifier

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

commit: c806f29

@ascorbic ascorbic merged commit 1acf174 into emdash-cms:main Apr 13, 2026
26 checks passed
@emdashbot emdashbot bot mentioned this pull request Apr 13, 2026
fmhall pushed a commit to fmhall/emdash that referenced this pull request Apr 13, 2026
…truction (emdash-cms#537)

* fix: resolve plugin source entry before dist to prevent workspace destruction

resolveSourceEntry() checked the direct dist path (e.g. dist/index.mjs)
before trying to resolve back to source (src/index.ts). After a full
`pnpm build`, the dist path exists and short-circuits the lookup —
returning a .mjs path that downstream code cannot handle:

1. TS_EXT_RE (/\.tsx?$/) fails to strip the .mjs extension, so
   findBuildOutput searches for index.mjs.mjs (never exists).
2. tsdown receives the .mjs entry with config:false but still reads
   tsconfig.json from CWD. Under certain timing conditions this
   triggers a clean cycle that recursively deletes source files across
   the entire packages/ directory (observed: 73k+ files wiped).

The fix reorders resolveSourceEntry() to try src/ paths first and fall
back to the direct path only when no source equivalent exists. This
matches the function's documented intent ("dist/foo.mjs → src/foo.ts").

Reproduction: clean install → pnpm build → pnpm test:unit (repeat 2-3
times). Without the fix, marketplace publish-e2e tests fail on every
run and source files are intermittently destroyed.

* chore: add changeset for bundle source entry fix

---------

Co-authored-by: Matt Kane <mkane@cloudflare.com>
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.

2 participants