fix(cli): resolve react-native script subpaths through the exports map - #57709
fix(cli): resolve react-native script subpaths through the exports map#57709chrfalch wants to merge 3 commits into
Conversation
The `spm` and `codegen` command wrappers reach into the react-native
package with require.resolve('react-native/...'). Those specifiers go
through react-native's `exports` map, which — unlike legacy CJS
resolution — neither appends extensions nor falls back to a directory's
index.js. Both specifiers relied on exactly that, so each threw
MODULE_NOT_FOUND as soon as the command ran:
npx react-native spm ... -> Cannot find module
'.../node_modules/react-native/scripts/setup-apple-spm'
npx react-native codegen -> same, for
'.../scripts/codegen/generate-artifacts-executor' (a directory)
Point them at the real files: `setup-apple-spm.js` and
`generate-artifacts-executor/index.js`.
Adds a regression test that scans the command wrappers for
react-native/* specifiers and resolves each one in a real node process —
Jest's moduleNameMapper remaps react-native to the source tree and
bypasses the exports map, so an in-band resolve passes even when
production fails.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
readdirSync's withFileTypes overload types Dirent.name as `string | Buffer`, which flow-check rejected at three call sites. Use the plain readdirSync overload (Array<string>) with a statSync isFile check, and switch the requires to the node: protocol per the lint rule. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Verified end-to-end on a clean Before (main, unmodified): After (same worktree, only the two specifier lines changed): Gets past module loading into real artifact downloading (I stopped it with a 180s timeout rather than waiting for the full fetch). Runs to completion, writing real artifacts ( No Worth noting |
Drop the helper functions and the long explanatory comment; the scan and the subprocess check (the part Jest's moduleNameMapper would otherwise defeat) collapse into two statements. 70 lines -> 43. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
@fabriziocucci has imported this pull request. If you are a Meta employee, you can view this in D113895593. |
|
Superseded by #57718. |
Summary: Pull Request resolved: #57718 **Context** Replaces #57709, which identified a real bug in 0.87 from the combination of: - #57276 - #57652 ``` $ npx react-native spm add error Cannot find module '.../node_modules/react-native/scripts/setup-apple-spm' $ npx react-native codegen error Cannot find module '.../node_modules/react-native/scripts/codegen/generate-artifacts-executor' ``` **This diff** - Fix — and exclusively switch to — extensionless imports rather than requiring `.js`. - Update in-repo consumers. The previous single mapping is now an extension-aware mapping: - `./scripts/*` now appends `.js`, so `react-native/scripts/foo` resolves to `foo.js`. - `.sh` and `.rb` stay reachable via explicit `./scripts/*.sh` and `./scripts/*.rb` passthrough patterns. **Impact** - Explicit `react-native/scripts/*.js` specifiers no longer resolve, so JavaScript paths must be imported without an extension. - Files under `scripts/` with extensions other than `.js`, `.sh`, or `.rb` are no longer exposed through `./scripts/*`. - These have no open source consumers. Changelog: [General][Fixed] - (RC4 only, drop for main changelog): `react-native/scripts/*` imports once again expand `.js` extensions [General][Breaking] - Extensionless `react-native/scripts/*` imports are now **mandated**; explicit `.js` import specifiers are rejected. Reviewed By: rubennorte Differential Revision: D113898792 fbshipit-source-id: d72f60be2c08ab97871e336645856c9029e74ae2
Summary:
Two CLI commands are broken on
mainright now. Both fail the moment you run them:What happened. #57652 moved these two command wrappers into
community-cli-plugin. Each one loads a helper script out of thereact-nativepackage by name:Anything starting with
react-native/is looked up through theexportslist in that package'spackage.json. This lookup is strict — it takes the path exactly as written. It will not add a missing.js, and it will not find theindex.jsinside a folder. Node's older lookup style did both of those automatically, and both wrappers were relying on it:scripts/setup-apple-spmsetup-apple-spm.js.json the endscripts/codegen/generate-artifacts-executorindex.js/index.json the endThe fix. Write both paths out in full. That's a one-line change in each wrapper; nothing else about the commands changes.
This was found by the new SwiftPM iOS CI job in #57659, where every build failed on the
spmcommand.Changelog:
[GENERAL] [FIXED] - Fix
react-native spmandreact-native codegenfailing with "Cannot find module"Test Plan:
Added
packages/community-cli-plugin/src/commands/__tests__/reactNativeSubpathResolution-test.js. It reads the command wrapper files, picks out everyreact-native/...path they reference, and checks each one can actually be loaded. That covers both commands today and any wrapper added later.Why the test runs
nodein a subprocess: Jest redirectsreact-nativeto the source folder, which skips theexportslist altogether. A test that does the lookup inside Jest therefore passes even while the real command is broken — I wrote that version first and it went green against the broken code. Running a separatenodeprocess is what makes the test meaningful.Test fails before the fix, passes after:
Same result checking the paths directly, outside Jest:
flow focus-check, ESLint and Prettier are clean on the changed files.