diff --git a/change/@react-native-windows-cli-543cf36f-0ce7-4df7-a391-285985d3f62c.json b/change/@react-native-windows-cli-543cf36f-0ce7-4df7-a391-285985d3f62c.json
new file mode 100644
index 00000000000..0552570c866
--- /dev/null
+++ b/change/@react-native-windows-cli-543cf36f-0ce7-4df7-a391-285985d3f62c.json
@@ -0,0 +1,7 @@
+{
+ "type": "prerelease",
+ "comment": "Upgrade to Visual Studio 2026",
+ "packageName": "@react-native-windows/cli",
+ "email": "julio.rocha@microsoft.com",
+ "dependentChangeType": "patch"
+}
diff --git a/change/react-native-windows-2a20c629-48b2-458d-80e6-26b5546c04e0.json b/change/react-native-windows-2a20c629-48b2-458d-80e6-26b5546c04e0.json
new file mode 100644
index 00000000000..74bc56dcc93
--- /dev/null
+++ b/change/react-native-windows-2a20c629-48b2-458d-80e6-26b5546c04e0.json
@@ -0,0 +1,7 @@
+{
+ "type": "prerelease",
+ "comment": "Upgrade to Visual Studio 2026",
+ "packageName": "react-native-windows",
+ "email": "julio.rocha@microsoft.com",
+ "dependentChangeType": "patch"
+}
diff --git a/packages/@react-native-windows/cli/src/commands/healthCheck/healthCheckList.ts b/packages/@react-native-windows/cli/src/commands/healthCheck/healthCheckList.ts
index 6e34f37cfe2..c4451f5019b 100644
--- a/packages/@react-native-windows/cli/src/commands/healthCheck/healthCheckList.ts
+++ b/packages/@react-native-windows/cli/src/commands/healthCheck/healthCheckList.ts
@@ -11,8 +11,8 @@ export const HealthCheckList = [
[true, 'WindowsVersion', 'Windows version >= 10.0.17763.0'],
[true, 'DeveloperMode', 'Developer mode is on'],
[true, 'LongPath', 'Long path support is enabled'],
- [true, 'VSUWP', 'Visual Studio 2022 (>= 17.11.0) & req. components'],
+ [true, 'VSUWP', 'Visual Studio 2026 (>= 18.6.1) & req. components'],
[true, 'Node', 'Node.js (LTS, >= 22.0)'],
[true, 'Yarn', 'Yarn'],
- [true, 'DotNetCore', '.NET SDK (LTS, = 8.0)'],
+ [true, 'DotNetCore', '.NET SDK (LTS, = 10.0)'],
];
diff --git a/vnext/Desktop.UnitTests/React.Windows.Desktop.UnitTests.vcxproj b/vnext/Desktop.UnitTests/React.Windows.Desktop.UnitTests.vcxproj
index 366f7a86e4f..31aa7684925 100644
--- a/vnext/Desktop.UnitTests/React.Windows.Desktop.UnitTests.vcxproj
+++ b/vnext/Desktop.UnitTests/React.Windows.Desktop.UnitTests.vcxproj
@@ -79,7 +79,7 @@
$(VCInstallDir)UnitTest\include;
%(AdditionalIncludeDirectories)
- %(AdditionalOptions) /await
+ %(AdditionalOptions) /await
- /await %(AdditionalOptions) /bigobj /FS
+ %(AdditionalOptions) /bigobj /FS
+ %(AdditionalOptions) /await
true
Cdecl
diff --git a/vnext/Microsoft.ReactNative.NewArch.sln b/vnext/Microsoft.ReactNative.NewArch.sln
index 9ae89cca183..d22858bcccf 100644
--- a/vnext/Microsoft.ReactNative.NewArch.sln
+++ b/vnext/Microsoft.ReactNative.NewArch.sln
@@ -1,11 +1,9 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 17
-VisualStudioVersion = 17.3.32929.385
+# Visual Studio Version 18
+VisualStudioVersion = 18.6.11819.183 stable
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.ReactNative", "Microsoft.ReactNative\Microsoft.ReactNative.vcxproj", "{F7D32BD0-2749-483E-9A0D-1635EF7E3136}"
- ProjectSection(ProjectDependencies) = postProject
- EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Common", "Common\Common.vcxproj", "{FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}"
EndProject
@@ -106,11 +104,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.ReactNative.CsWin
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|ARM64 = Debug|ARM64
Debug|x64 = Debug|x64
+ Debug|ARM64 = Debug|ARM64
Debug|x86 = Debug|x86
- Release|ARM64 = Release|ARM64
Release|x64 = Release|x64
+ Release|ARM64 = Release|ARM64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
diff --git a/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj b/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj
index b41c838404b..4502a7a703b 100644
--- a/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj
+++ b/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj
@@ -96,7 +96,8 @@
$(IntDir)pch.pch
pch.h
Level4
- /await %(AdditionalOptions) /bigobj /ZH:SHA_256
+ %(AdditionalOptions) /bigobj /ZH:SHA_256
+ %(AdditionalOptions) /await
$(ExternalDir)fmt\include;
$(ReactNativeWindowsDir)Microsoft.ReactNative;
diff --git a/vnext/Microsoft.ReactNative/Utils/LocalBundleReader.cpp b/vnext/Microsoft.ReactNative/Utils/LocalBundleReader.cpp
index 5194f68f6de..e12c9d45b59 100644
--- a/vnext/Microsoft.ReactNative/Utils/LocalBundleReader.cpp
+++ b/vnext/Microsoft.ReactNative/Utils/LocalBundleReader.cpp
@@ -54,7 +54,8 @@ std::string GetBundleFromEmbeddedResource(const winrt::Windows::Foundation::Uri
return std::string(start, start + size);
}
-std::future LocalBundleReader::LoadBundleAsync(const std::wstring bundleUri) {
+winrt::Windows::Foundation::IAsyncOperation LocalBundleReader::LoadBundleAsync(
+ const std::wstring bundleUri) {
try {
co_await winrt::resume_background();
@@ -66,7 +67,7 @@ std::future LocalBundleReader::LoadBundleAsync(const std::wstring b
file = co_await winrt::Windows::Storage::StorageFile::GetFileFromApplicationUriAsync(uri);
} else if (bundleUri.starts_with(L"resource://")) {
winrt::Windows::Foundation::Uri uri(bundleUri);
- co_return GetBundleFromEmbeddedResource(uri);
+ co_return winrt::to_hstring(GetBundleFromEmbeddedResource(uri));
} else {
file = co_await winrt::Windows::Storage::StorageFile::GetFileFromPathAsync(bundleUri);
}
@@ -87,20 +88,20 @@ std::future LocalBundleReader::LoadBundleAsync(const std::wstring b
reinterpret_cast(&script[0]), reinterpret_cast(&script[script.length()])});
dataReader.Close();
- co_return script;
+ co_return winrt::to_hstring(script);
}
// RuntimeScheduler only handles std::exception or jsi::JSError
catch (winrt::hresult_error const &e) {
- throw std::exception(winrt::to_string(e.message()).c_str());
+ throw std::runtime_error(winrt::to_string(e.message()));
}
}
std::string LocalBundleReader::LoadBundle(const std::wstring &bundlePath) {
- return LoadBundleAsync(bundlePath).get();
+ return winrt::to_string(LoadBundleAsync(bundlePath).get());
}
StorageFileBigString::StorageFileBigString(const std::wstring &path) {
- m_futureBuffer = LocalBundleReader::LoadBundleAsync(path);
+ m_pendingLoad = LocalBundleReader::LoadBundleAsync(path);
}
bool StorageFileBigString::isAscii() const {
@@ -118,8 +119,9 @@ size_t StorageFileBigString::size() const {
}
void StorageFileBigString::ensure() const {
- if (m_string.empty()) {
- m_string = m_futureBuffer.get();
+ if (m_pendingLoad) {
+ m_string = winrt::to_string(m_pendingLoad.get());
+ m_pendingLoad = nullptr;
}
}
diff --git a/vnext/Microsoft.ReactNative/Utils/LocalBundleReader.h b/vnext/Microsoft.ReactNative/Utils/LocalBundleReader.h
index 8671ebf59ee..1166fc709fb 100644
--- a/vnext/Microsoft.ReactNative/Utils/LocalBundleReader.h
+++ b/vnext/Microsoft.ReactNative/Utils/LocalBundleReader.h
@@ -3,14 +3,14 @@
#pragma once
#include
-#include
+#include
#include
namespace Microsoft::ReactNative {
class LocalBundleReader {
public:
- static std::future LoadBundleAsync(const std::wstring bundlePath);
+ static winrt::Windows::Foundation::IAsyncOperation LoadBundleAsync(const std::wstring bundlePath);
static std::string LoadBundle(const std::wstring &bundlePath);
};
@@ -24,7 +24,7 @@ class StorageFileBigString : public facebook::react::JSBigString {
void ensure() const;
private:
- mutable std::future m_futureBuffer;
+ mutable winrt::Windows::Foundation::IAsyncOperation m_pendingLoad;
mutable std::string m_string;
};
diff --git a/vnext/Mso.UnitTests/Mso.UnitTests.vcxproj b/vnext/Mso.UnitTests/Mso.UnitTests.vcxproj
index 74fb6cc93fa..1609c75d257 100644
--- a/vnext/Mso.UnitTests/Mso.UnitTests.vcxproj
+++ b/vnext/Mso.UnitTests/Mso.UnitTests.vcxproj
@@ -94,7 +94,8 @@
/bigobj -
/FS - Force Synchronous PDB writes. Useful when setting MultiProcCL.
-->
- /await %(AdditionalOptions) /bigobj /FS
+ %(AdditionalOptions) /bigobj /FS
+ %(AdditionalOptions) /await
true
Cdecl
diff --git a/vnext/PropertySheets/React.Cpp.props b/vnext/PropertySheets/React.Cpp.props
index ae3fb63bd19..edabc4a699e 100644
--- a/vnext/PropertySheets/React.Cpp.props
+++ b/vnext/PropertySheets/React.Cpp.props
@@ -136,7 +136,8 @@
ProgramDatabase
true
true
- /utf-8 %(AdditionalOptions) /await
+ /utf-8 %(AdditionalOptions)
+ %(AdditionalOptions) /await
Guard
Spectre
diff --git a/vnext/Scripts/rnw-dependencies.ps1 b/vnext/Scripts/rnw-dependencies.ps1
index a57d7809f5c..6ec18cf8140 100644
--- a/vnext/Scripts/rnw-dependencies.ps1
+++ b/vnext/Scripts/rnw-dependencies.ps1
@@ -8,7 +8,7 @@ param(
[string]$Check = [CheckId]::All,
[Parameter(ValueFromRemainingArguments)]
- [ValidateSet('appDev', 'rnwDev', 'buildLab', 'vs2022', 'clone')]
+ [ValidateSet('appDev', 'rnwDev', 'buildLab', 'vs2026', 'clone')]
[String[]]$Tags = @('appDev'),
[switch]$Enterprise = $false
)
@@ -94,7 +94,6 @@ $vsComponents = @('Microsoft.Component.MSBuild',
$vcToolsComponent,
'Microsoft.VisualStudio.ComponentGroup.UWP.Support',
'Microsoft.VisualStudio.ComponentGroup.NativeDesktop.Core',
- 'Microsoft.VisualStudio.Component.Windows10SDK.19041',
'Microsoft.VisualStudio.Component.Windows11SDK.22621');
# UWP.VC is not needed to build the projects with msbuild, but the VS IDE requires it.
@@ -113,12 +112,12 @@ $wingetver = "1.7.11261";
# The minimum VS version to check for
# Note: For install to work, whatever min version you specify here must be met by the current package available on winget.
-$vsver = "17.11.0";
+$vsver = "18.6.1";
# The exact .NET SDK version to check for
-$dotnetver = "8.0";
+$dotnetver = "10.0";
# Version name of the winget package
-$wingetDotNetVer = "8";
+$wingetDotNetVer = "10";
$v = [System.Environment]::OSVersion.Version;
if ($env:Agent_BuildDirectory) {
@@ -242,9 +241,9 @@ function InstallVS {
if ($Enterprise) {
# The CI machines need the enterprise version of VS as that is what is hardcoded in all the scripts
- WinGetInstall Microsoft.VisualStudio.2022.Enterprise
+ WinGetInstall Microsoft.VisualStudio.Enterprise
} else {
- WinGetInstall Microsoft.VisualStudio.2022.Community
+ WinGetInstall Microsoft.VisualStudio.Community
}
$vsWhere = Get-VSWhere;
@@ -458,8 +457,8 @@ $requirements = @(
},
@{
Id=[CheckId]::VSUWP;
- Name = "Visual Studio 2022 (>= $vsver) & req. components";
- Tags = @('appDev', 'vs2022');
+ Name = "Visual Studio 2026 (>= $vsver) & req. components";
+ Tags = @('appDev', 'vs2026');
Valid = { CheckVS; }
Install = { InstallVS };
HasVerboseOutput = $true;
@@ -491,7 +490,7 @@ $requirements = @(
$downloadPath = "$env:TEMP\WindowsApplicationDriver.msi"
Write-Verbose "Downloading WinAppDriver from $url";
Invoke-WebRequest -UseBasicParsing $url -OutFile $downloadPath
-
+
# SDL Compliance: Verify signature (Work Item 58386093)
$signature = Get-AuthenticodeSignature $downloadPath
if ($signature.Status -ne "Valid") {
@@ -499,10 +498,10 @@ $requirements = @(
throw "WinAppDriver signature verification failed"
}
if ($signature.SignerCertificate.Subject -notlike "*Microsoft*") {
- Remove-Item $downloadPath -ErrorAction SilentlyContinue
+ Remove-Item $downloadPath -ErrorAction SilentlyContinue
throw "WinAppDriver not signed by Microsoft"
}
-
+
& $downloadPath /q
Remove-Item $downloadPath -ErrorAction SilentlyContinue
};
@@ -600,7 +599,7 @@ function WinGetInstall {
Write-Verbose "Executing `winget install `"$wingetPackage`"";
& winget install "$wingetPackage" --accept-source-agreements --accept-package-agreements
}
-
+
# Refresh PATH environment variable to pick up newly installed tools
$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User")
}
@@ -693,12 +692,12 @@ foreach ($req in $filteredRequirements)
try {
$validAfterInstall = Invoke-Command $req.Valid;
} catch { }
-
+
if ($validAfterInstall) {
$Installed++;
continue; # go to the next item
}
-
+
if ($LASTEXITCODE -ne 0) {
throw "Last exit code was non-zero: $LASTEXITCODE - $outputFromInstall";
}
@@ -737,4 +736,4 @@ if ($NeedsRerun -ne 0) {
$Tags | Out-File $MarkerFile;
if (!$ShellInvocation) { Read-Host 'Press Enter to exit' }
exit 0;
-}
\ No newline at end of file
+}
diff --git a/vnext/Shared/DevSupportManager.cpp b/vnext/Shared/DevSupportManager.cpp
index b485fc1b304..f04ed78ff6f 100644
--- a/vnext/Shared/DevSupportManager.cpp
+++ b/vnext/Shared/DevSupportManager.cpp
@@ -33,7 +33,6 @@
#include
#pragma warning(pop)
-#include
#include
#include
@@ -47,61 +46,65 @@ using namespace facebook::react;
namespace Microsoft::ReactNative {
-std::future> GetJavaScriptFromServerAsync(const std::string &url) {
- winrt::Windows::Web::Http::Filters::HttpBaseProtocolFilter filter;
- filter.CacheControl().ReadBehavior(winrt::Windows::Web::Http::Filters::HttpCacheReadBehavior::NoCache);
- winrt::Windows::Web::Http::HttpClient httpClient(filter);
- winrt::Windows::Foundation::Uri uri(Microsoft::Common::Unicode::Utf8ToUtf16(url));
+winrt::Windows::Foundation::IAsyncOperation GetJavaScriptFromServerAsync(const std::string &url) {
+ try {
+ winrt::Windows::Web::Http::Filters::HttpBaseProtocolFilter filter;
+ filter.CacheControl().ReadBehavior(winrt::Windows::Web::Http::Filters::HttpCacheReadBehavior::NoCache);
+ winrt::Windows::Web::Http::HttpClient httpClient(filter);
+ winrt::Windows::Foundation::Uri uri(Microsoft::Common::Unicode::Utf8ToUtf16(url));
- co_await winrt::resume_background();
+ co_await winrt::resume_background();
- winrt::Windows::Web::Http::HttpRequestMessage request(winrt::Windows::Web::Http::HttpMethod::Get(), uri);
- auto asyncRequest = httpClient.SendRequestAsync(request);
+ winrt::Windows::Web::Http::HttpRequestMessage request(winrt::Windows::Web::Http::HttpMethod::Get(), uri);
+ auto asyncRequest = httpClient.SendRequestAsync(request);
#ifdef DEFAULT_CPPWINRT_EXCEPTIONS
- try {
winrt::Windows::Web::Http::HttpResponseMessage response = co_await asyncRequest;
- } catch (winrt::hresult_error const &e) {
- co_return std::make_pair(
- Microsoft::Common::Unicode::Utf16ToUtf8(e.message().c_str(), e.message().size()).c_str(), false);
- }
#else
- co_await lessthrow_await_adapter>{asyncRequest};
+ co_await lessthrow_await_adapter>{asyncRequest};
+
+ HRESULT hr = asyncRequest.ErrorCode();
+ if (FAILED(hr)) {
+ std::string error;
+ if (hr == WININET_E_CANNOT_CONNECT) {
+ error =
+ fmt::format("A connection with the server {} could not be established.\n\nIs the packager running?", url);
+ } else {
+ error = fmt::format("Error 0x{:x} downloading {}.", static_cast(asyncRequest.ErrorCode()), url);
+ }
+ throw std::runtime_error(error);
+ }
- HRESULT hr = asyncRequest.ErrorCode();
- if (FAILED(hr)) {
- std::string error;
- if (hr == WININET_E_CANNOT_CONNECT) {
- error = fmt::format("A connection with the server {} could not be established.\n\nIs the packager running?", url);
+ winrt::Windows::Web::Http::HttpResponseMessage response = asyncRequest.GetResults();
+#endif
+
+ winrt::Windows::Storage::Streams::IBuffer buffer = co_await response.Content().ReadAsBufferAsync();
+ auto reader = winrt::Windows::Storage::Streams::DataReader::FromBuffer(buffer);
+
+ reader.UnicodeEncoding(winrt::Windows::Storage::Streams::UnicodeEncoding::Utf8);
+ uint32_t len = reader.UnconsumedBufferLength();
+ std::string resultStr;
+ if (len > 0 || response.IsSuccessStatusCode()) {
+ std::string data;
+ data.resize(len);
+ auto buf = reinterpret_cast(data.data());
+ static_assert(
+ sizeof(buf[0]) == sizeof(data[0]), "perf optimization relies on uint8_t and char being the same size");
+ reader.ReadBytes(winrt::array_view(buf, buf + len));
+ resultStr = std::move(data);
} else {
- error = fmt::format("Error 0x{:x} downloading {}.", static_cast(asyncRequest.ErrorCode()), url);
+ resultStr = fmt::format("HTTP Error {} downloading {}.", static_cast(response.StatusCode()), url);
}
- co_return std::make_pair(error, false);
- }
- winrt::Windows::Web::Http::HttpResponseMessage response = asyncRequest.GetResults();
-#endif
+ if (!response.IsSuccessStatusCode()) {
+ throw std::runtime_error(resultStr);
+ }
- winrt::Windows::Storage::Streams::IBuffer buffer = co_await response.Content().ReadAsBufferAsync();
- auto reader = winrt::Windows::Storage::Streams::DataReader::FromBuffer(buffer);
-
- reader.UnicodeEncoding(winrt::Windows::Storage::Streams::UnicodeEncoding::Utf8);
- uint32_t len = reader.UnconsumedBufferLength();
- std::string result;
- if (len > 0 || response.IsSuccessStatusCode()) {
- std::string data;
- data.resize(len);
- auto buf = reinterpret_cast(data.data());
- static_assert(
- sizeof(buf[0]) == sizeof(data[0]), "perf optimization relies on uint8_t and char being the same size");
- reader.ReadBytes(winrt::array_view(buf, buf + len));
- result = std::move(data);
- } else {
- result = fmt::format("HTTP Error {} downloading {}.", static_cast(response.StatusCode()), url);
+ co_return winrt::to_hstring(resultStr);
+ } catch (winrt::hresult_error const &e) {
+ throw std::runtime_error(Microsoft::Common::Unicode::Utf16ToUtf8(e.message().c_str(), e.message().size()));
}
-
- co_return std::make_pair(std::move(result), response.IsSuccessStatusCode());
}
void LaunchDevTools(const facebook::react::DevSettings &settings) {
@@ -185,7 +188,8 @@ std::string GetPackageName(const std::string &bundleAppId) {
return packageName;
}
-std::future PollForLiveReload(const std::string &url) {
+winrt::Windows::Foundation::IAsyncOperation PollForLiveReload(
+ const std::string &url) {
winrt::Windows::Web::Http::HttpClient httpClient;
winrt::Windows::Foundation::Uri uri(Microsoft::Common::Unicode::Utf8ToUtf16(url));
httpClient.DefaultRequestHeaders().Connection().TryParseAdd(L"keep-alive");
@@ -299,7 +303,9 @@ std::pair GetJavaScriptFromServer(
inlineSourceMap,
hermesBytecodeVersion);
try {
- return GetJavaScriptFromServerAsync(bundleUrl).get();
+ return std::make_pair(winrt::to_string(GetJavaScriptFromServerAsync(bundleUrl).get()), true);
+ } catch (std::exception const &e) {
+ return std::make_pair(std::string{"Error: "} + e.what(), false);
} catch (winrt::hresult_error const &e) {
return std::make_pair(
"Error: " + Microsoft::Common::Unicode::Utf16ToUtf8(e.message().c_str(), e.message().size()), false);
diff --git a/vnext/Shared/DevSupportManager.h b/vnext/Shared/DevSupportManager.h
index 216bd6c4932..849ec08203b 100644
--- a/vnext/Shared/DevSupportManager.h
+++ b/vnext/Shared/DevSupportManager.h
@@ -10,7 +10,6 @@
#include
#include
#include
-#include
#include
#include
diff --git a/vnext/Shared/Networking/WinRTWebSocketResource.h b/vnext/Shared/Networking/WinRTWebSocketResource.h
index 8ebdd3b14d0..eafb1c6fbe9 100644
--- a/vnext/Shared/Networking/WinRTWebSocketResource.h
+++ b/vnext/Shared/Networking/WinRTWebSocketResource.h
@@ -27,8 +27,12 @@ class WinRTWebSocketResource2 : public IWebSocketResource,
void operator=(const TaskSequencer &) = delete;
private:
+// `experimental` is deprecated starting Visual Studio 2026
+#if _MSC_VER >= 1951
+ using CoroHandle = std::coroutine_handle<>;
+#else
using CoroHandle = std::experimental::coroutine_handle<>;
-
+#endif
struct Suspender {
CoroHandle m_handle;
diff --git a/vnext/Shared/Shared.vcxitems.filters b/vnext/Shared/Shared.vcxitems.filters
index 32c1cd327ec..58a17c7a665 100644
--- a/vnext/Shared/Shared.vcxitems.filters
+++ b/vnext/Shared/Shared.vcxitems.filters
@@ -198,6 +198,7 @@
+