Make the PowerShell path lookup lazy again, to stop spamming errors on macOS when react-native.config.js is loaded - #16430
Conversation
|
Azure Pipelines: There may be pipelines that require an authorized user to comment /azp run to run. |
|
Azure Pipelines: There may be pipelines that require an authorized user to comment /azp run to run. |
There was a problem hiding this comment.
🟡 Changes recommended
PowerShell lookup failures bypass existing command and health-check error handling.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Defers PowerShell discovery to avoid failures when loading RNW configuration without Windows tooling.
Changes:
- Lazily caches PowerShell paths during command and health-check execution.
- Adds a prerelease change record.
File summaries
| File | Description |
|---|---|
commandWithProgress.ts |
Defers PowerShell discovery until command execution. |
healthChecks.ts |
Defers discovery until diagnostics or repair. |
| Change JSON | Records the CLI prerelease change. |
Review details
- Files reviewed: 3/3 changed files
- Comments generated: 2
- Review effort level: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
🟡 Changes recommended
PowerShell discovery failures lose actionable diagnostics or bypass health-check failure handling.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
Suppressed comments (1)
packages/@react-native-windows/cli/src/commands/healthCheck/healthChecks.ts:82
findPowerShell()can throw when the tool is absent, but this lookup occurs before the callback's failure-handlingtry. In that caserunAutomaticFixrejects without callingloader.fail()or reporting manual-installation guidance, unlike allexecafailures below. Include discovery in the handled path and fail the loader cleanly when no executable can be found.
powershell ??= findPowerShell();
- Files reviewed: 3/3 changed files
- Comments generated: 1
- Review effort level: Balanced
There was a problem hiding this comment.
🔵 Needs a closer look
PowerShell lookup failures bypass the operation-specific error handling, and the health-check block needs formatting corrections.
Review details
Suppressed comments (2)
packages/@react-native-windows/cli/src/utils/commandWithProgress.ts:61
- Keep the lazy lookup inside the existing
try. As written, a missing PowerShell executable throws before this function converts failures to the suppliedCodedErrorcategory, so callers report anUnknownresult/exit code instead of the operation-specific failure (for example,EnableDevModeFailure).
powershell ??= findPowerShell();
packages/@react-native-windows/cli/src/commands/healthCheck/healthChecks.ts:89
- This newly added block does not follow the repository's TypeScript formatting rules: it uses double quotes, omits the trailing property comma, and is not wrapped as Prettier would format it. It also spells the product name as “Powershell” rather than “PowerShell”; please format this before merging so the formatting check passes.
const errorMessage = error instanceof Error ? error.message : undefined;
logManualInstallation({
healthcheck: `react-native-windows dependency "${id}"`,
message: `Error finding PowerShell${errorMessage ? `: ${errorMessage}` : ""}`
});
- Files reviewed: 3/3 changed files
- Comments generated: 0 new
- Review effort level: Balanced
There was a problem hiding this comment.
🔵 Needs a closer look
PowerShell lookup bypasses coded-error handling, and the health-check addition fails repository formatting conventions.
Review details
Suppressed comments (2)
Previously missed (1) — in code that hasn't changed since the last review.
packages/@react-native-windows/cli/src/commands/healthCheck/healthChecks.ts:89
- This added block does not match the repository's required Prettier style: it uses double quotes, omits the trailing comma, and leaves expressions unwrapped. As written, the formatting check will reject the file.
packages/@react-native-windows/cli/src/utils/commandWithProgress.ts:61
findPowerShell()can throw when PowerShell is unavailable, but this lookup is outside the function'stry. That failure therefore escapes as a plainErrorinstead of the requestedCodedError, bypassing the caller's error category and the function's existing failure handling. Include the lazy lookup in thetryblock.
powershell ??= findPowerShell();
- Files reviewed: 3/3 changed files
- Comments generated: 0 new
- Review effort level: Balanced
|
/azp run |
|
Azure Pipelines: Successfully started running 1 pipeline(s). |
I didn't file an issue for this yet, so I'll begin by introducing the problem before describing the solution that this PR implements.
Problem
When you try to run
rnc-cli starton a Mac, in a project withreact-native-windowsinstalled, using@rnx-kit/metro-configas your Metro config, it eagerly looks for .NET and Powershell, naturally fails to find them, and makes a lot of noise:This eager search happens when
@rnx-kit/metro-configdiscovers platforms from the dependencies at packages/tools-react-native/src/context.ts#L147. It ends up evaluatingreact-native-windows/react-native.config.jsin a child process, which callsfindPowerShell().(CC Tommy Nguyen (@tido64) – I think it's reasonable to fix it in
react-native-windows, but tagging just in case it'd be preferable to fix it on thernx-kitside).History
There was no such problem in
react-native-windows@0.81.27. The regression was introduced when #16075 was backported to0.81.28in #16235, with changes such as this one, to line 50 ofpackages/@react-native-windows/cli/src/utils/commandWithProgress.ts:Expressions that used to just be static strings became eager file system lookups, causing side-effects on non-Windows machines.
Solution
This PR makes it so that we resolve and cache the path to PowerShell only when actually about to execute a PowerShell command. i.e. it changes it from eager to lazy.
Reproduction
Repro repository, based on Expo Desktop:
In my case, I used Node.js 24 and Bun 1.3.11.
See the
codex/fixbranch, which applies this proposed change as a patch.Backporting
While this PR is opened against
main, please consider backporting to0.81-stableso that I can release Expo Desktop in best condition.Testing
Astra initially wrote a whole test suite for this. I think they're a bit over the top, though, so I've pushed an extra commit to drop them. If the reviewer wants, I can restore them just by reverting that commit.
10 Jest tests pass: import/serialization on simulated macOS and Windows, deferred lookup, successful caching, retry after failure, and diagnostic/repair execution. The import regressions fail against the original source on both simulated hosts.CLI TypeScript build and ESLint pass; changed files formatted with Prettier.Repro CI on real macOS and Windows: baseline confirms the bug; patched branch passes. Checks forbid PowerShell discovery, require empty stderr after patching, and verify both platforms remain available.Changelog
Yes: Defer PowerShell discovery until a command or health check needs it, allowing CLI configuration to load without Windows build tools.
Microsoft Reviewers: Open in CodeFlow