You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Async chunk URLs drop the file extension, so .cjs async imports fail with "Requiring unknown module" #1959
With lazy bundling, an import() of a package that resolves to dist/index.cjs throws at runtime: Requiring unknown module "11122".
getModuleParams builds the chunk URL from the resolved path but strips its extension (Serializers/helpers/js.js):
constbundlePath=path.relative(options.serverRoot,dependency.absolutePath);paths[id]='/'+path.join(path.dirname(bundlePath),path.basename(bundlePath,path.extname(bundlePath)),// `.cjs` is lost here)+'.bundle?'+searchParams.toString();
The dependency resolved to dist/index.cjs is addressed as /…/dist/index.bundle, and when the server resolves that entry it picks dist/index.js via sourceExts — a different file, a different module id. The served chunk never defines the id baked into the importing bundle.
Measured on an Android dev bundle (Metro 0.84.4, Expo SDK 57) for @walletconnect/core (just one example — any package with this exports shape is affected), whose exports map is { ".": { "module": "./dist/index.js", "default": "./dist/index.cjs" } }:
module id
file
main bundle expects
11122
dist/index.cjs
served chunk defines
11125
dist/index.js
If the current behavior is a bug, please provide the steps to reproduce and a minimal repository on GitHub that we can yarn install and yarn test.
npx create-expo-app with expo-dev-client
yarn add @walletconnect/core
await import('@walletconnect/core') on a path that runs at startup
start the dev server and open the app
Any package shipping dual builds with different extensions and no require/import conditions hits this. .mjs should be affected the same way.
What is the expected behavior?
The chunk URL addresses the file that was actually resolved, so the chunk registers the same module id as the importing bundle.
Possible fix
Keep the extension. parseBundleOptionsFromBundleRequestUrl already strips exactly one trailing extension (.replace(/\.[^/.]+$/, '')), so both index.cjs.bundle → index.cjs and today's exports.ts.bundle → exports.ts resolve exactly, and no server-side change is needed:
I patched exactly this in @expo/metro-config's fork of the file (serializer/fork/js.ts, identical code, carrying a // TODO: This is not the proper Metro URL encoding of a file path) and re-measured the same app: the @walletconnect/core chunk now registers 11122 → dist/index.cjs, and an existing .ts async boundary in the same bundle still matched (id 11117). The split also fixes the backslashes path.join would produce on Windows. Not tested with web splitChunks, worker async type, or on Windows.
Please provide your exact Metro configuration and mention your Metro, node, yarn/npm version and operating system.
Metro 0.84.4, Expo SDK 57 (expo 57.0.8), React Native 0.86, Node 24, Yarn 4.18, macOS. Default Expo Metro config plus a custom resolveRequest that does not touch these packages.
I reproduced this on main with a small fixture: import('./dual.cjs') next to a dual.js. The chunk URL becomes dual.bundle, the server serves dual.js, and the app throws "Requiring unknown module".
I opened #1990 with the fix you suggested (keep the extension in the chunk URL), plus a test that reads the URL back to the same file.
Activity
matejkriz commentedon Sep 22, 2026
minimal reproduction repo https://github.com/matejkriz/metro-async-chunk-cjs-repro
dasjideepak commentedon Sep 28, 2026
I reproduced this on
mainwith a small fixture:import('./dual.cjs')next to adual.js. The chunk URL becomesdual.bundle, the server servesdual.js, and the app throws "Requiring unknown module".I opened #1990 with the fix you suggested (keep the extension in the chunk URL), plus a test that reads the URL back to the same file.
Keep the file extension in async bundle paths