fix(app-tools): stop writing the ESM loader files twice - #8819
Merged
Conversation
`src/esm` is matched by the `./src/**` entry, so the bundler emits those
files itself. It also sits in `output.copy`, and in the ESM outputs both land
on the same `.mjs` paths — two writers for one file. When the writes
interleave the file is left truncated, and since `bin/modern.js` loads
`dist/esm-node` for any project with `"type": "module"`, a corrupt loader
takes the whole project down at startup:
SyntaxError: Unexpected token '}'
at compileSourceTextModule (node:internal/modules/esm/utils)
Windows CI hit exactly that, with dist/esm-node/esm/register-esm.mjs and
ts-node-loader.mjs unparsable while the CommonJS fixtures were unaffected —
the CJS output emits `.js`, so nothing collides there.
Keep the copy only for the CJS output, which is where it is the sole source
of the `.mjs` loaders `register()` resolves by name. Rebuilding with this
change produces a byte-identical dist, so the duplicate write was the only
thing removed.
The deploy templates are already excluded from the entry for the same reason.
Co-Authored-By: Riff
✅ Deploy Preview for modernjs-byted ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
🦋 Changeset detectedLatest commit: 4556fdb The changes in this PR will be included in the next version bump. This PR includes changesets to release 119 packages
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 |
Contributor
Rsdoctor Bundle Diff Analysis📊 Quick Summary
Generated by Rsdoctor GitHub Action |
zllkjc
approved these changes
Aug 25, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Summary
src/esmis matched by the./src/**entry, so the bundler emits those files itself. It also sits inoutput.copy, and in the ESM outputs both land on the same.mjspaths — two writers for one file. When the writes interleave the file is left truncated.bin/modern.jsloadsdist/esm-nodefor any project with"type": "module", so a corrupt loader takes the whole project down at startup:Evidence
Windows CI had been red since Aug 13. Every failing fixture was
"type": "module"; every passing one was CommonJS — including tailwind v2/v3 passing in the same suite where v4 failed. Parsing the published ESM build during a failing run named the files:The CJS output emits
.js, so nothing collides there — which is why CommonJS projects were never affected.Fix
Keep the copy only for the CJS output, where it is the sole source of the
.mjsloadersregister()resolves by name. Removing it entirely breaks CJS; excludingsrc/esmfrom the entry breaks CJS too, becausedist/cjs/utils/register.jsimports../esm/register-esm.js, which only exists as a bundled entry.Rebuilding with this change produces a byte-identical dist (
diff -rqbefore/after: 0 differences), so the duplicate write was the only thing removed.The deploy templates are already excluded from the entry for exactly this reason;
src/esmwas missed.Verification
Windows integration tests on this fix (plus #8816 for an unrelated test-side failure): 87 passed | 4 skipped, 0 failed —
SyntaxError,compileSourceTextModuleandERR_CONNECTION_REFUSEDall gone.Note this is not test-only: these files ship inside the npm package, and a release build runs the same racy config.
@modern-js/app-tools@3.8.2on the registry is currently clean (all 100esm-node.mjsparse), but a release that loses the race would publish a broken loader and break every"type": "module"user project at startup.Co-Authored-By: Riff