Skip to content

Fix playground composition for Node.js 24.x#15983

Merged
vmoroz merged 8 commits intomicrosoft:mainfrom
vmoroz:PR/start-fixing-playground-composition
Apr 21, 2026
Merged

Fix playground composition for Node.js 24.x#15983
vmoroz merged 8 commits intomicrosoft:mainfrom
vmoroz:PR/start-fixing-playground-composition

Conversation

@vmoroz
Copy link
Copy Markdown
Member

@vmoroz vmoroz commented Apr 10, 2026

Description

Type of Change

  • Bug fix

Why

Fix regressions introduced by PR #15979 ("Use fork-sync for Folly and FastFloat") and compatibility issues with Node v24 / npm v11 that broke the playground-composition solution: build failures, Metro bundler crashes, and runtime errors preventing the RNTester UI from loading.

What

1. Remove stale Folly project references after fork-sync migration

PR #15979 moved Folly into vnext/external/folly/folly.vcxitems (a shared items project), but left behind direct references to the old standalone Folly.vcxproj in several places. These caused duplicate item errors and missing project errors:

  • Microsoft.ReactNative.vcxproj: removed <Natvis> and <ProjectReference> entries pointing at the old Folly.vcxproj
  • Microsoft.ReactNative.vcxproj.filters: updated Natvis path from $(ReactNativeWindowsDir)Folly\ to $(ExternalDir)folly\
  • Playground-Composition.vcxproj: removed stale <Natvis> reference to $(ReactNativeWindowsDir)Folly\Folly.natvis
  • playground-composition.sln: removed the Folly project entry and its build configurations; removed the ReactCommon -> Folly dependency
  • React.Cpp.props: updated AdditionalIncludeDirectories from $(FollyDir) / $(FastFloatDir)include to $(ExternalDir)folly / $(ExternalDir)fast-float\include
  • NuGet lock files (packages.lock.json, packages.experimentalwinui3.lock.json) in Microsoft.ReactNative, playground-composition, and playground-composition.Package: removed stale Folly project dependency entries

2. Fix build order in playground-composition.sln

SampleCustomComponent processes DrawingIsland.idl which imports Microsoft.ReactNative.winmd. Because SampleCustomComponent had no declared dependency on Microsoft.ReactNative, Visual Studio could start building it before Microsoft.ReactNative was ready, causing:

midlrt : error MIDL1001: cannot open input file Microsoft.ReactNative.winmd

Fix: added ProjectDependencies section to the SampleCustomComponent project entry in the solution file, declaring a dependency on Microsoft.ReactNative.

3. Fix yarn start / yarn windows for the playground package

The start and windows scripts used npx @react-native-community/cli <cmd>, which invokes npm 11's arborist to scan the workspace tree. npm 11 crashes with Cannot read properties of null (reading 'package') when it encounters the Yarn-managed node_modules structure.

Fix: replaced npx @react-native-community/cli with the react-native binary directly, which is provided by @react-native-community/cli (already a devDependency) and is available on PATH when run via yarn without going through npm's arborist.

4. Fix MSBuild CLI invocations crashing with npm v11 in yarn workspaces

Three MSBuild property sheets run npx @react-native-community/cli <command> during build. In npm v11.8.0 (bundled with Node v24), npx calls Exec.execWorkspaces which tries to build an npm arborist tree. Since this repo uses Yarn workspaces, the arborist fails:

error MSB3073: The command "npx --yes @react-native-community/cli codegen-windows --logging" exited with code 1.

Fix: added --no-workspaces flag to all three property sheets to skip npm's workspace tree resolution, which is not needed for running the CLI:

  • Codegen.props: codegen-windows command
  • Autolink.props: autolink-windows command
  • Bundle.props: bundle command

5. Fix Metro resolver failing to find react-native modules (Node v24 + Windows)

On Windows, require.resolve() through yarn workspace junctions (e.g. node_modules/react-native-windows -> vnext/) returns paths with a different drive letter case than process.cwd() in Node v24. Metro's internal file system tree derives its paths from process.cwd(), and fileSystemLookup uses case-sensitive string comparison, so all resolved module paths from the playground's custom devResolveRequest resolver failed to match:

Error: Unable to resolve module react-native

Fix: added normalizePathDrive() helper in the playground's metro.config.js and the three app/lib template metro configs (vnext/template/metro.config.js, vnext/templates/cpp-app/metro.config.js, vnext/templates/cpp-lib/example/metro.config.js) to normalize the drive letter to match process.cwd() after fs.realpathSync / require.resolve.

6. Fix InitializeCore.js not running before main module (Node v24 + Windows)

The getModulesRunBeforeMainModule paths (computed by @rnx-kit/metro-config via require.resolve) also had the wrong drive letter case. Metro's getAppendScripts compares these paths against module paths in the bundle graph using strict equality (===). The case mismatch caused InitializeCore.js to silently not be required before the main module, so setUpGlobals.js never ran global.window = global, leading to:

[runtime not ready]: ReferenceError: Property 'window' doesn't exist

Fix: overrode getModulesRunBeforeMainModule in the playground's metro.config.js to normalize paths through fs.realpathSync + normalizePathDrive(), ensuring they match the resolved module paths in the bundle graph.

7. Fix Universal solution (Microsoft.ReactNative.NewArch.sln) compilation in Visual Studio

VS's NuGet restore fails with NU1004 for Microsoft.ReactNative.CsWinRT.csproj because VS uses the CPS nomination API to evaluate project references, while the lock files are generated by msbuild /t:Restore which fully evaluates vcxproj targets. When a .csproj references a .vcxproj, VS's NuGet restore only discovers ProjectReferences (Common.vcxproj, ReactCommon.vcxproj), but the lock file also contains the vcxproj's PackageReferences (boost, Hermes, SourceLink, etc.) — causing a mismatch.

Two fixes:

  • NuGet.LockFile.props: disable RestoreLockedMode for .csproj files when BuildingInsideVisualStudio=true, so VS's initial NuGet restore succeeds and package targets load correctly. CI is unaffected because it passes /p:RestoreLockedMode=true as a global property which overrides project-level settings.
  • Directory.Build.targets: extend the existing BeforeResolveReferences workaround (which already handles vcxproj PackageReference restore in VS) to also cover .csproj files, providing an explicit msbuild /t:Restore fallback during the build.

Screenshots

N/A

Testing

  • Built packages/playground/windows/playground-composition.sln (Debug|x64) successfully.
  • yarn start from packages/playground launches the Metro bundler without errors.
  • The RNTester UI loads and renders correctly in the playground-composition app.
  • Built vnext/Microsoft.ReactNative.NewArch.sln (Debug|x64) in Visual Studio successfully.

Changelog

Should this change be included in the release notes: no

@vmoroz vmoroz requested a review from a team as a code owner April 10, 2026 23:33
@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 11, 2026

Performance Test Results

Branch: PR/start-fixing-playground-composition
Commit: 494090ca
Time: 2026-04-21T01:58:21.950Z
Tests: 161/161 passed

✅ Passed

161 scenario(s) across 28 suite(s) — no regressions

SectionList

Scenario Mean Median StdDev Renders vs Baseline
SectionList mount 5.40ms 5.00ms ±2.12ms 1 +0.0%
SectionList unmount 0.30ms 0.00ms ±0.48ms 0 +0.0%
SectionList rerender 12.20ms 12.00ms ±2.44ms 2 +14.3%
SectionList with-3-sections-15-items 7.10ms 7.00ms ±2.13ms 1 +27.3%
SectionList with-5-sections-50-items 6.60ms 6.00ms ±1.84ms 1 +0.0%
SectionList with-10-sections-200-items 6.00ms 5.50ms ±1.41ms 1 +0.0%
SectionList with-20-sections-200-items 5.30ms 5.00ms ±2.41ms 1 +0.0%
SectionList with-section-separator 1.90ms 2.00ms ±0.57ms 1 +0.0%
SectionList with-item-separator 2.90ms 3.00ms ±0.99ms 1 +50.0%
SectionList with-header-footer 2.70ms 2.50ms ±0.82ms 1 +25.0%
SectionList with-section-footer 1.90ms 2.00ms ±0.74ms 1 +0.0%
SectionList with-sticky-section-headers 3.20ms 2.50ms ±1.93ms 1 +25.0%
SectionList with-empty-list 0.60ms 1.00ms ±0.52ms 1 +0.0%
SectionList with-50-sections-1000-items 1.60ms 2.00ms ±0.52ms 1 +0.0%

FlatList

Scenario Mean Median StdDev Renders vs Baseline
FlatList mount 4.70ms 4.00ms ±1.25ms 1 +0.0%
FlatList unmount 0.00ms 0.00ms ±0.00ms 0 +0.0%
FlatList rerender 11.40ms 11.00ms ±1.84ms 2 +22.2%
FlatList with-10-items 4.90ms 5.00ms ±0.32ms 1 +25.0%
FlatList with-100-items 6.10ms 5.50ms ±1.73ms 1 +10.0%
FlatList with-500-items 5.20ms 5.00ms ±1.14ms 1 +25.0%
FlatList with-1000-items 5.70ms 5.00ms ±1.95ms 1 +25.0%
FlatList horizontal 5.00ms 4.50ms ±1.76ms 1 -10.0%
FlatList with-separator 2.10ms 2.00ms ±0.88ms 1 +0.0%
FlatList with-header-footer 2.80ms 2.00ms ±1.55ms 1 +0.0%
FlatList with-empty-list 0.50ms 0.50ms ±0.53ms 1 +0.0%
FlatList with-get-item-layout 2.10ms 2.00ms ±0.57ms 1 +100.0%
FlatList inverted 2.70ms 2.00ms ±2.00ms 1 +33.3%
FlatList with-num-columns 2.60ms 3.00ms ±0.52ms 1 +0.0%

TouchableOpacity

Scenario Mean Median StdDev Renders vs Baseline
TouchableOpacity mount 0.90ms 1.00ms ±0.57ms 1 +0.0%
TouchableOpacity unmount 0.10ms 0.00ms ±0.32ms 0 +0.0%
TouchableOpacity rerender 1.20ms 1.00ms ±0.42ms 2 +0.0%
TouchableOpacity custom-active-opacity 0.90ms 1.00ms ±0.32ms 1 +0.0%
TouchableOpacity disabled 0.60ms 1.00ms ±0.52ms 1 +0.0%
TouchableOpacity with-all-handlers 0.80ms 1.00ms ±0.42ms 1 +0.0%
TouchableOpacity with-hit-slop 1.30ms 1.00ms ±1.70ms 1 +0.0%
TouchableOpacity with-delay 1.00ms 1.00ms ±0.00ms 1 +0.0%
TouchableOpacity nested 1.60ms 2.00ms ±0.52ms 1 +100.0%
TouchableOpacity multiple-10 7.80ms 8.00ms ±1.37ms 1 +33.3%
TouchableOpacity multiple-50 30.60ms 30.00ms ±4.40ms 1 +3.4%
TouchableOpacity multiple-100 47.73ms 49.00ms ±11.98ms 1 -2.0%

ScrollView

Scenario Mean Median StdDev Renders vs Baseline
ScrollView mount 0.50ms 0.50ms ±0.53ms 1 +Infinity%
ScrollView unmount 0.10ms 0.00ms ±0.32ms 0 +0.0%
ScrollView rerender 0.60ms 1.00ms ±0.52ms 2 +0.0%
ScrollView children-20 2.93ms 3.00ms ±0.59ms 1 -25.0%
ScrollView children-100 19.00ms 17.00ms ±4.55ms 1 +6.3%
ScrollView horizontal 4.00ms 4.00ms ±1.25ms 1 +0.0%
ScrollView sticky-headers 2.90ms 3.00ms ±1.20ms 1 +0.0%
ScrollView scroll-indicators 0.80ms 1.00ms ±0.42ms 1 +0.0%
ScrollView nested 1.40ms 1.00ms ±0.70ms 1 +0.0%
ScrollView content-container-style 1.30ms 1.00ms ±1.70ms 1 +0.0%
ScrollView children-500 23.07ms 20.00ms ±5.50ms 1 +5.3%

TouchableHighlight

Scenario Mean Median StdDev Renders vs Baseline
TouchableHighlight mount 0.40ms 0.00ms ±0.52ms 1 -100.0%
TouchableHighlight unmount 0.00ms 0.00ms ±0.00ms 0 +0.0%
TouchableHighlight rerender 0.60ms 1.00ms ±0.52ms 2 +0.0%
TouchableHighlight custom-underlay-color 0.60ms 1.00ms ±0.52ms 1 +Infinity%
TouchableHighlight custom-active-opacity 0.40ms 0.00ms ±0.52ms 1 +0.0%
TouchableHighlight disabled 0.50ms 0.50ms ±0.53ms 1 +Infinity%
TouchableHighlight with-all-handlers 0.40ms 0.00ms ±0.52ms 1 +0.0%
TouchableHighlight with-hit-slop 0.30ms 0.00ms ±0.48ms 1 +0.0%
TouchableHighlight nested-touchables 0.70ms 1.00ms ±0.48ms 1 +0.0%
TouchableHighlight multiple-touchables-10 3.60ms 3.00ms ±1.26ms 1 +0.0%
TouchableHighlight multiple-touchables-50 14.80ms 14.00ms ±2.20ms 1 +12.0%
TouchableHighlight multiple-touchables-100 28.40ms 28.00ms ±4.48ms 1 +24.4%

Pressable

Scenario Mean Median StdDev Renders vs Baseline
Pressable mount 0.70ms 1.00ms ±0.48ms 1 +Infinity%
Pressable unmount 0.10ms 0.00ms ±0.32ms 0 +0.0%
Pressable rerender 0.60ms 1.00ms ±0.52ms 2 +100.0%
Pressable with-all-handlers 0.50ms 0.50ms ±0.53ms 1 +Infinity%
Pressable with-style-function 0.40ms 0.00ms ±0.52ms 1 +0.0%
Pressable disabled 0.50ms 0.50ms ±0.53ms 1 +Infinity%
Pressable with-hit-slop 0.40ms 0.00ms ±0.52ms 1 +0.0%
Pressable nested 0.80ms 1.00ms ±0.42ms 1 +0.0%
Pressable multiple-10 3.40ms 3.00ms ±1.18ms 1 +0.0%
Pressable multiple-50 17.60ms 17.00ms ±2.85ms 1 +21.4%
Pressable multiple-100 18.67ms 13.00ms ±11.31ms 1 +8.3%

Modal

Scenario Mean Median StdDev Renders vs Baseline
Modal mount 0.60ms 1.00ms ±0.52ms 1 +Infinity%
Modal unmount 0.00ms 0.00ms ±0.00ms 0 +0.0%
Modal rerender 0.70ms 1.00ms ±0.67ms 2 +Infinity%
Modal slide-animation 0.40ms 0.00ms ±0.52ms 1 +0.0%
Modal fade-animation 0.20ms 0.00ms ±0.42ms 1 +0.0%
Modal transparent 0.20ms 0.00ms ±0.42ms 1 +0.0%
Modal with-callbacks 0.30ms 0.00ms ±0.48ms 1 +0.0%
Modal rich-content 2.00ms 2.00ms ±0.67ms 1 +0.0%
Modal with-accessibility 0.40ms 0.00ms ±0.52ms 1 +0.0%

Image

Scenario Mean Median StdDev Renders vs Baseline
Image mount 0.20ms 0.00ms ±0.42ms 1 +0.0%
Image unmount 0.00ms 0.00ms ±0.00ms 0 +0.0%
Image rerender 0.20ms 0.00ms ±0.42ms 2 +0.0%
Image with-resize-mode 0.20ms 0.00ms ±0.42ms 1 +0.0%
Image with-border-radius 0.20ms 0.00ms ±0.42ms 1 +0.0%
Image with-tint-color 0.20ms 0.00ms ±0.42ms 1 +0.0%
Image with-blur-radius 0.00ms 0.00ms ±0.00ms 1 +0.0%
Image with-accessibility 0.30ms 0.00ms ±0.48ms 1 +0.0%
Image multiple-10 1.07ms 1.00ms ±0.26ms 1 +0.0%
Image multiple-50 3.87ms 4.00ms ±0.83ms 1 +33.3%
Image multiple-100 9.33ms 8.00ms ±2.97ms 1 +0.0%

ActivityIndicator

Scenario Mean Median StdDev Renders vs Baseline
ActivityIndicator mount 0.20ms 0.00ms ±0.42ms 1 +0.0%
ActivityIndicator unmount 0.00ms 0.00ms ±0.00ms 0 +0.0%
ActivityIndicator rerender 0.10ms 0.00ms ±0.32ms 2 +0.0%
ActivityIndicator size-large 0.30ms 0.00ms ±0.48ms 1 +0.0%
ActivityIndicator size-small 0.10ms 0.00ms ±0.32ms 1 +0.0%
ActivityIndicator with-color 0.10ms 0.00ms ±0.32ms 1 +0.0%
ActivityIndicator not-animating 0.10ms 0.00ms ±0.32ms 1 +0.0%
ActivityIndicator with-accessibility 0.20ms 0.00ms ±0.42ms 1 +0.0%
ActivityIndicator multiple-10 0.80ms 1.00ms ±0.41ms 1 +0.0%
ActivityIndicator multiple-50 4.13ms 4.00ms ±1.25ms 1 +0.0%
ActivityIndicator multiple-100 9.27ms 9.00ms ±1.44ms 1 +28.6%

Switch

Scenario Mean Median StdDev Renders vs Baseline
Switch mount 0.10ms 0.00ms ±0.32ms 1 +0.0%
Switch unmount 0.00ms 0.00ms ±0.00ms 0 +0.0%
Switch rerender 0.20ms 0.00ms ±0.42ms 2 -100.0%
Switch value-true 0.10ms 0.00ms ±0.32ms 1 +0.0%
Switch disabled 0.30ms 0.00ms ±0.48ms 1 +0.0%
Switch custom-colors 0.30ms 0.00ms ±0.48ms 1 +0.0%
Switch on-value-change 0.10ms 0.00ms ±0.32ms 1 +0.0%
Switch with-accessibility 0.30ms 0.00ms ±0.48ms 1 +0.0%
Switch multiple-10 1.93ms 2.00ms ±1.75ms 1 +0.0%
Switch multiple-50 11.47ms 10.00ms ±4.37ms 1 +11.1%
Switch multiple-100 20.20ms 18.00ms ±4.95ms 1 +12.5%

Button

Scenario Mean Median StdDev Renders vs Baseline
Button mount 0.60ms 1.00ms ±0.52ms 1 +0.0%
Button unmount 0.10ms 0.00ms ±0.32ms 0 +0.0%
Button rerender 1.10ms 1.00ms ±0.74ms 2 +0.0%
Button disabled 0.70ms 1.00ms ±0.48ms 1 +0.0%
Button with-color 0.60ms 1.00ms ±0.52ms 1 +100.0%
Button with-accessibility 0.60ms 1.00ms ±0.52ms 1 +0.0%
Button multiple-10 7.00ms 7.00ms ±1.60ms 1 +16.7%
Button multiple-50 23.47ms 26.00ms ±8.98ms 1 -3.7%
Button multiple-100 18.33ms 17.00ms ±5.19ms 1 -10.5%

TextInput

Scenario Mean Median StdDev Renders vs Baseline
TextInput mount 0.20ms 0.00ms ±0.42ms 1 +0.0%
TextInput unmount 0.00ms 0.00ms ±0.00ms 0 +0.0%
TextInput rerender 0.40ms 0.00ms ±0.52ms 2 +0.0%
TextInput multiline 0.10ms 0.00ms ±0.32ms 1 +0.0%
TextInput with-value 0.20ms 0.00ms ±0.42ms 1 +0.0%
TextInput styled 0.10ms 0.00ms ±0.32ms 1 +0.0%
TextInput multiple-100 9.33ms 9.00ms ±2.69ms 1 +28.6%

View

Scenario Mean Median StdDev Renders vs Baseline
View mount 0.20ms 0.00ms ±0.42ms 1 +0.0%
View unmount 0.20ms 0.00ms ±0.42ms 0 +0.0%
View rerender 0.30ms 0.00ms ±0.48ms 2 +0.0%
View nested-50 4.40ms 4.00ms ±1.80ms 1 +33.3%
View nested-100 10.07ms 9.00ms ±2.28ms 1 +28.6%
View shadow 0.20ms 0.00ms ±0.42ms 1 +0.0%
View border-radius 0.10ms 0.00ms ±0.32ms 1 +0.0%
View nested-500 19.13ms 12.00ms ±14.15ms 1 +20.0%

Text

Scenario Mean Median StdDev Renders vs Baseline
Text mount 0.20ms 0.00ms ±0.42ms 1 +0.0%
Text unmount 0.00ms 0.00ms ±0.00ms 0 +0.0%
Text rerender 0.10ms 0.00ms ±0.32ms 2 +0.0%
Text long-1000 0.10ms 0.00ms ±0.32ms 1 +0.0%
Text nested 0.20ms 0.00ms ±0.42ms 1 +0.0%
Text styled 0.20ms 0.00ms ±0.42ms 1 +0.0%
Text multiple-100 9.33ms 9.00ms ±1.91ms 1 +28.6%

SectionList.native-perf-test.ts

Scenario Mean Median StdDev Renders vs Baseline
SectionList native mount 7.32ms 7.74ms ±1.37ms 1 +19.0%

FlatList.native-perf-test.ts

Scenario Mean Median StdDev Renders vs Baseline
FlatList native mount 6.61ms 6.40ms ±1.05ms 1 -30.7%

TouchableHighlight.native-perf-test.ts

Scenario Mean Median StdDev Renders vs Baseline
TouchableHighlight native mount 1.91ms 1.84ms ±0.22ms 1 -11.7%

TouchableOpacity.native-perf-test.ts

Scenario Mean Median StdDev Renders vs Baseline
TouchableOpacity native mount 2.21ms 2.13ms ±0.27ms 1 -32.2%

Pressable.native-perf-test.ts

Scenario Mean Median StdDev Renders vs Baseline
Pressable native mount 1.96ms 1.90ms ±0.23ms 1 -24.5%

ScrollView.native-perf-test.ts

Scenario Mean Median StdDev Renders vs Baseline
ScrollView native mount 4.34ms 3.89ms ±1.09ms 1 -3.9%

ActivityIndicator.native-perf-test.ts

Scenario Mean Median StdDev Renders vs Baseline
ActivityIndicator native mount 1.75ms 1.72ms ±0.18ms 1 -30.9%

TextInput.native-perf-test.ts

Scenario Mean Median StdDev Renders vs Baseline
TextInput native mount 2.71ms 2.64ms ±0.44ms 1 -35.4%

Switch.native-perf-test.ts

Scenario Mean Median StdDev Renders vs Baseline
Switch native mount 1.57ms 1.47ms ±0.33ms 1 -15.5%

Button.native-perf-test.ts

Scenario Mean Median StdDev Renders vs Baseline
Button native mount 2.52ms 2.27ms ±0.61ms 1 -12.7%

Modal.native-perf-test.ts

Scenario Mean Median StdDev Renders vs Baseline
Modal native mount 1.33ms 1.29ms ±0.25ms 1 +5.9%

Image.native-perf-test.ts

Scenario Mean Median StdDev Renders vs Baseline
Image native mount 2.09ms 2.08ms ±0.35ms 1 -8.0%

View.native-perf-test.ts

Scenario Mean Median StdDev Renders vs Baseline
View native mount 1.48ms 1.37ms ±0.39ms 1 -4.3%

Text.native-perf-test.ts

Scenario Mean Median StdDev Renders vs Baseline
Text native mount 1.68ms 1.61ms ±0.22ms 1 -7.6%

@vmoroz vmoroz force-pushed the PR/start-fixing-playground-composition branch from 25b00f9 to d711a3b Compare April 20, 2026 16:59
@vmoroz vmoroz changed the title Start fixing playground composition Fix playground composition for Node.js 24.x Apr 20, 2026
@vmoroz vmoroz enabled auto-merge (squash) April 20, 2026 19:10
@vmoroz vmoroz force-pushed the PR/start-fixing-playground-composition branch from 7031750 to 1fbf70c Compare April 20, 2026 23:34
@vmoroz vmoroz merged commit 975ff30 into microsoft:main Apr 21, 2026
32 checks passed
@vmoroz vmoroz deleted the PR/start-fixing-playground-composition branch April 21, 2026 04:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants