diff --git a/change/react-native-windows-9d93df46-79f8-4116-b0c8-7985a9c67d91.json b/change/react-native-windows-9d93df46-79f8-4116-b0c8-7985a9c67d91.json
new file mode 100644
index 00000000000..3442cc7a9b0
--- /dev/null
+++ b/change/react-native-windows-9d93df46-79f8-4116-b0c8-7985a9c67d91.json
@@ -0,0 +1,7 @@
+{
+ "type": "prerelease",
+ "comment": "Fix project compilation",
+ "packageName": "react-native-windows",
+ "email": "vmorozov@microsoft.com",
+ "dependentChangeType": "patch"
+}
diff --git a/packages/playground/metro.config.js b/packages/playground/metro.config.js
index 9c43518fdb7..943efd6016e 100644
--- a/packages/playground/metro.config.js
+++ b/packages/playground/metro.config.js
@@ -9,13 +9,23 @@ const {makeMetroConfig} = require('@rnw-scripts/metro-dev-config');
const fs = require('fs');
const path = require('path');
-const rnwPath = fs.realpathSync(
+// On Windows, require.resolve through symlinks (e.g. yarn workspace links) can
+// return paths with a different drive letter case than process.cwd(). Metro's
+// file system lookup is case-sensitive, so we normalize to match cwd.
+function normalizePathDrive(p) {
+ if (process.platform === 'win32' && p.length >= 2 && p[1] === ':') {
+ return process.cwd()[0] + p.slice(1);
+ }
+ return p;
+}
+
+const rnwPath = normalizePathDrive(fs.realpathSync(
path.dirname(require.resolve('react-native-windows/package.json')),
-);
+));
-const rnwTesterPath = fs.realpathSync(
+const rnwTesterPath = normalizePathDrive(fs.realpathSync(
path.dirname(require.resolve('@react-native-windows/tester/package.json')),
-);
+));
const devPackages = {
'react-native': path.normalize(rnwPath),
@@ -144,8 +154,25 @@ function tryResolveDevRelativeImport(
return null;
}
-module.exports = makeMetroConfig({
+const baseConfig = makeMetroConfig({
resolver: {
resolveRequest: devResolveRequest,
},
});
+
+// The getModulesRunBeforeMainModule paths (from @rnx-kit/metro-config) may have
+// wrong drive letter case on Windows due to require.resolve through symlinks.
+// Metro compares these paths via strict equality against module paths in the
+// bundle graph, so the case must match exactly.
+const originalGetModulesRunBeforeMainModule =
+ baseConfig.serializer.getModulesRunBeforeMainModule;
+baseConfig.serializer = {
+ ...baseConfig.serializer,
+ getModulesRunBeforeMainModule: (...args) => {
+ return originalGetModulesRunBeforeMainModule(...args).map(p =>
+ normalizePathDrive(fs.realpathSync(p)),
+ );
+ },
+};
+
+module.exports = baseConfig;
diff --git a/packages/playground/package.json b/packages/playground/package.json
index 49656a45caa..7d2daee1d1b 100644
--- a/packages/playground/package.json
+++ b/packages/playground/package.json
@@ -3,10 +3,10 @@
"version": "0.0.54",
"private": true,
"scripts": {
- "start": "npx @react-native-community/cli rnx-start",
+ "start": "react-native rnx-start",
"lint:fix": "rnw-scripts lint:fix",
"lint": "rnw-scripts lint",
- "windows": "npx @react-native-community/cli run-windows"
+ "windows": "react-native run-windows"
},
"dependencies": {
"@react-native-picker/picker": "2.11.0",
diff --git a/packages/playground/windows/playground-composition.sln b/packages/playground/windows/playground-composition.sln
index 76256ed5464..7948bdf2265 100644
--- a/packages/playground/windows/playground-composition.sln
+++ b/packages/playground/windows/playground-composition.sln
@@ -29,6 +29,9 @@ EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Include", "..\..\..\vnext\include\Include.vcxitems", "{EF074BA1-2D54-4D49-A28E-5E040B47CD2E}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SampleCustomComponent", "..\..\sample-custom-component\windows\SampleCustomComponent\SampleCustomComponent.vcxproj", "{A8DA218C-4CB5-48CB-A9EE-9E6337165D07}"
+ ProjectSection(ProjectDependencies) = postProject
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136} = {F7D32BD0-2749-483E-9A0D-1635EF7E3136}
+ EndProjectSection
EndProject
GlobalSection(SharedMSBuildProjectFiles) = preSolution
..\..\..\vnext\Shared\Shared.vcxitems*{2049dbe9-8d13-42c9-ae4b-413ae38fffd0}*SharedItemsImports = 9
diff --git a/vnext/Directory.Build.targets b/vnext/Directory.Build.targets
index a2ab4fd389c..f844708fea0 100644
--- a/vnext/Directory.Build.targets
+++ b/vnext/Directory.Build.targets
@@ -4,21 +4,29 @@
-
-
+
+
-
+
diff --git a/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj b/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj
index f30c1e60de7..ea2daf49df4 100644
--- a/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj
+++ b/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj
@@ -411,9 +411,6 @@
-
-
-
{fca38f3c-7c73-4c47-be4e-32f77fa8538d}
diff --git a/vnext/PropertySheets/Autolink.props b/vnext/PropertySheets/Autolink.props
index a58a0721d8d..27438bd96ae 100644
--- a/vnext/PropertySheets/Autolink.props
+++ b/vnext/PropertySheets/Autolink.props
@@ -7,7 +7,7 @@
true
- npx --yes @react-native-community/cli autolink-windows
+ npx --yes --no-workspaces @react-native-community/cli autolink-windows
$([MSBuild]::GetDirectoryNameOfFileAbove($(ProjectDir), 'package.json'))
--check --sln "$([MSBuild]::MakeRelative($(AutolinkCommandWorkingDir), $(SolutionPath)))" --proj "$([MSBuild]::MakeRelative($(AutolinkCommandWorkingDir), $(ProjectPath)))"
--check
diff --git a/vnext/PropertySheets/Bundle.props b/vnext/PropertySheets/Bundle.props
index 4b08d67e031..156492da23b 100644
--- a/vnext/PropertySheets/Bundle.props
+++ b/vnext/PropertySheets/Bundle.props
@@ -39,7 +39,7 @@
--minify false
- npx @react-native-community/cli bundle
+ npx --yes --no-workspaces @react-native-community/cli bundle
$([MSBuild]::GetDirectoryNameOfFileAbove($(ProjectDir), 'package.json'))
diff --git a/vnext/PropertySheets/Codegen.props b/vnext/PropertySheets/Codegen.props
index 78d3ad39967..5669bc9ea3e 100644
--- a/vnext/PropertySheets/Codegen.props
+++ b/vnext/PropertySheets/Codegen.props
@@ -7,7 +7,7 @@
true
- npx --yes @react-native-community/cli codegen-windows
+ npx --yes --no-workspaces @react-native-community/cli codegen-windows
$([MSBuild]::GetDirectoryNameOfFileAbove($(ProjectDir), 'package.json'))
--logging
diff --git a/vnext/PropertySheets/NuGet.LockFile.props b/vnext/PropertySheets/NuGet.LockFile.props
index 0cfb6b016ed..842fc28a3d7 100644
--- a/vnext/PropertySheets/NuGet.LockFile.props
+++ b/vnext/PropertySheets/NuGet.LockFile.props
@@ -9,6 +9,14 @@
true
+
+ false
packages
$(NuGetLockFileName).experimentalwinui3
diff --git a/vnext/template/metro.config.js b/vnext/template/metro.config.js
index fa46717d0b5..682fb941e77 100644
--- a/vnext/template/metro.config.js
+++ b/vnext/template/metro.config.js
@@ -3,9 +3,19 @@ const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config');
const fs = require('fs');
const path = require('path');
-const rnwPath = fs.realpathSync(
+// On Windows, require.resolve through yarn workspace junctions can return paths
+// with a different drive letter case than process.cwd(). Metro's internal file
+// system lookup is case-sensitive, so we normalize to match cwd.
+function normalizePathDrive(p) {
+ if (process.platform === 'win32' && p.length >= 2 && p[1] === ':') {
+ return process.cwd()[0] + p.slice(1);
+ }
+ return p;
+}
+
+const rnwPath = normalizePathDrive(fs.realpathSync(
path.resolve(require.resolve('react-native-windows/package.json'), '..'),
-);
+));
//{{#devMode}} [devMode
const rnwRootNodeModules = path.resolve(rnwPath, '..', 'node_modules');
diff --git a/vnext/templates/cpp-app/metro.config.js b/vnext/templates/cpp-app/metro.config.js
index e33b62b8e9c..ea6a25d7d12 100644
--- a/vnext/templates/cpp-app/metro.config.js
+++ b/vnext/templates/cpp-app/metro.config.js
@@ -3,9 +3,19 @@ const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config');
const fs = require('fs');
const path = require('node:path');
-const rnwPath = fs.realpathSync(
+// On Windows, require.resolve through yarn workspace junctions can return paths
+// with a different drive letter case than process.cwd(). Metro's internal file
+// system lookup is case-sensitive, so we normalize to match cwd.
+function normalizePathDrive(p) {
+ if (process.platform === 'win32' && p.length >= 2 && p[1] === ':') {
+ return process.cwd()[0] + p.slice(1);
+ }
+ return p;
+}
+
+const rnwPath = normalizePathDrive(fs.realpathSync(
path.resolve(require.resolve('react-native-windows/package.json'), '..'),
-);
+));
//{{#devMode}} [devMode
const rnwRootNodeModules = path.resolve(rnwPath, '..', 'node_modules');
diff --git a/vnext/templates/cpp-lib/example/metro.config.js b/vnext/templates/cpp-lib/example/metro.config.js
index 126ff52201c..24f4d29b489 100644
--- a/vnext/templates/cpp-lib/example/metro.config.js
+++ b/vnext/templates/cpp-lib/example/metro.config.js
@@ -7,9 +7,19 @@ const pack = require('../package.json');
const root = path.resolve(__dirname, '..');
const modules = Object.keys({ ...pack.peerDependencies });
-const rnwPath = fs.realpathSync(
+// On Windows, require.resolve through yarn workspace junctions can return paths
+// with a different drive letter case than process.cwd(). Metro's internal file
+// system lookup is case-sensitive, so we normalize to match cwd.
+function normalizePathDrive(p) {
+ if (process.platform === 'win32' && p.length >= 2 && p[1] === ':') {
+ return process.cwd()[0] + p.slice(1);
+ }
+ return p;
+}
+
+const rnwPath = normalizePathDrive(fs.realpathSync(
path.resolve(require.resolve('react-native-windows/package.json'), '..'),
-);
+));
//{{#devMode}} [devMode
const rnwRootNodeModules = path.resolve(rnwPath, '..', 'node_modules');