Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "Upgrade to Visual Studio 2026",
"packageName": "@react-native-windows/cli",
"email": "julio.rocha@microsoft.com",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "Upgrade to Visual Studio 2026",
"packageName": "react-native-windows",
"email": "julio.rocha@microsoft.com",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
Expand Up @@ -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)'],
];
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@
$(VCInstallDir)UnitTest\include;
%(AdditionalIncludeDirectories)
</AdditionalIncludeDirectories>
<AdditionalOptions>%(AdditionalOptions) /await</AdditionalOptions>
<AdditionalOptions Condition="$(PlatformToolsetVersion)&lt;145">%(AdditionalOptions) /await</AdditionalOptions>
</ClCompile>
<Link>
<!--
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@
<PreprocessorDefinitions>_CONSOLE;MSO_MOTIFCPP;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<WarningLevel>Level4</WarningLevel>
<AdditionalIncludeDirectories>$(MSBuildThisFileDirectory);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalOptions>/await %(AdditionalOptions) /bigobj</AdditionalOptions>
<AdditionalOptions>%(AdditionalOptions) /bigobj</AdditionalOptions>
<AdditionalOptions Condition="$(PlatformToolsetVersion)&lt;145">%(AdditionalOptions) /await</AdditionalOptions>
<ConformanceMode>true</ConformanceMode>
<CallingConvention>Cdecl</CallingConvention>
</ClCompile>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,8 @@
/bigobj -
/FS - Force Synchronous PDB writes. Useful when setting MultiProcCL.
-->
<AdditionalOptions>/await %(AdditionalOptions) /bigobj /FS</AdditionalOptions>
<AdditionalOptions>%(AdditionalOptions) /bigobj /FS</AdditionalOptions>
<AdditionalOptions Condition="$(PlatformToolsetVersion)&lt;145">%(AdditionalOptions) /await</AdditionalOptions>
<ConformanceMode>true</ConformanceMode>
<CallingConvention>Cdecl</CallingConvention>
<!-- We need RuntimeTypeInfo for JSI tests -->
Expand Down
3 changes: 2 additions & 1 deletion vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,8 @@
<PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile>
<ForcedIncludeFiles>pch.h</ForcedIncludeFiles>
<WarningLevel>Level4</WarningLevel>
<AdditionalOptions>/await %(AdditionalOptions) /bigobj /ZH:SHA_256</AdditionalOptions>
<AdditionalOptions>%(AdditionalOptions) /bigobj /ZH:SHA_256</AdditionalOptions>
<AdditionalOptions Condition="$(PlatformToolsetVersion)&lt;145">%(AdditionalOptions) /await</AdditionalOptions>
<AdditionalIncludeDirectories>
$(ExternalDir)fmt\include;
$(ReactNativeWindowsDir)Microsoft.ReactNative;
Expand Down
20 changes: 13 additions & 7 deletions vnext/Microsoft.ReactNative/Utils/LocalBundleReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@ std::string GetBundleFromEmbeddedResource(const winrt::Windows::Foundation::Uri
return std::string(start, start + size);
}

std::future<std::string> LocalBundleReader::LoadBundleAsync(const std::wstring bundleUri) {
winrt::Windows::Foundation::IAsyncAction LocalBundleReader::LoadBundleAsync(
const std::wstring bundleUri,
std::string &result) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does not look safe if someone would want to use it without thread lock. If we want to keep this function async, then it is better to use IAsyncOperation with hstring.

try {
co_await winrt::resume_background();

Expand All @@ -66,7 +68,8 @@ std::future<std::string> 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);
result = GetBundleFromEmbeddedResource(uri);
co_return;
} else {
file = co_await winrt::Windows::Storage::StorageFile::GetFileFromPathAsync(bundleUri);
}
Expand All @@ -87,7 +90,7 @@ std::future<std::string> LocalBundleReader::LoadBundleAsync(const std::wstring b
reinterpret_cast<uint8_t *>(&script[0]), reinterpret_cast<uint8_t *>(&script[script.length()])});
dataReader.Close();

co_return script;
result = std::move(script);
}
// RuntimeScheduler only handles std::exception or jsi::JSError
catch (winrt::hresult_error const &e) {
Expand All @@ -96,11 +99,13 @@ std::future<std::string> LocalBundleReader::LoadBundleAsync(const std::wstring b
}

std::string LocalBundleReader::LoadBundle(const std::wstring &bundlePath) {
return LoadBundleAsync(bundlePath).get();
std::string result;
LoadBundleAsync(bundlePath, result).get();
return result;
}

StorageFileBigString::StorageFileBigString(const std::wstring &path) {
m_futureBuffer = LocalBundleReader::LoadBundleAsync(path);
m_pendingLoad = LocalBundleReader::LoadBundleAsync(path, m_string);
}

bool StorageFileBigString::isAscii() const {
Expand All @@ -118,8 +123,9 @@ size_t StorageFileBigString::size() const {
}

void StorageFileBigString::ensure() const {
if (m_string.empty()) {
m_string = m_futureBuffer.get();
if (m_pendingLoad) {
m_pendingLoad.get();
m_pendingLoad = nullptr;
}
}

Expand Down
6 changes: 3 additions & 3 deletions vnext/Microsoft.ReactNative/Utils/LocalBundleReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@

#pragma once
#include <cxxreact/JSBigString.h>
#include <future>
#include <winrt/Windows.Foundation.h>
#include <string>

namespace Microsoft::ReactNative {

class LocalBundleReader {
public:
static std::future<std::string> LoadBundleAsync(const std::wstring bundlePath);
static winrt::Windows::Foundation::IAsyncAction LoadBundleAsync(const std::wstring bundlePath, std::string &result);
static std::string LoadBundle(const std::wstring &bundlePath);
};

Expand All @@ -24,7 +24,7 @@ class StorageFileBigString : public facebook::react::JSBigString {
void ensure() const;

private:
mutable std::future<std::string> m_futureBuffer;
mutable winrt::Windows::Foundation::IAsyncAction m_pendingLoad;
mutable std::string m_string;
};

Expand Down
3 changes: 2 additions & 1 deletion vnext/Mso.UnitTests/Mso.UnitTests.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,8 @@
/bigobj -
/FS - Force Synchronous PDB writes. Useful when setting MultiProcCL.
-->
<AdditionalOptions>/await %(AdditionalOptions) /bigobj /FS</AdditionalOptions>
<AdditionalOptions>%(AdditionalOptions) /bigobj /FS</AdditionalOptions>
<AdditionalOptions Condition="$(PlatformToolsetVersion)&lt;145">%(AdditionalOptions) /await</AdditionalOptions>
<ConformanceMode>true</ConformanceMode>
<CallingConvention>Cdecl</CallingConvention>
</ClCompile>
Expand Down
3 changes: 2 additions & 1 deletion vnext/PropertySheets/React.Cpp.props
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,8 @@
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<RuntimeTypeInfo>true</RuntimeTypeInfo>
<ShowIncludes Condition="'$(ShowIncludes)'=='true'">true</ShowIncludes>
<AdditionalOptions>/utf-8 %(AdditionalOptions) /await</AdditionalOptions>
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
<AdditionalOptions Condition="$(PlatformToolsetVersion)&lt;145">%(AdditionalOptions) /await</AdditionalOptions>
<ControlFlowGuard>Guard</ControlFlowGuard>
<SpectreMitigation>Spectre</SpectreMitigation>

Expand Down
31 changes: 15 additions & 16 deletions vnext/Scripts/rnw-dependencies.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -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
)
Expand Down Expand Up @@ -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.
Expand All @@ -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) {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -491,18 +490,18 @@ $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") {
Remove-Item $downloadPath -ErrorAction SilentlyContinue
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
};
Expand Down Expand Up @@ -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")
}
Expand Down Expand Up @@ -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";
}
Expand Down Expand Up @@ -737,4 +736,4 @@ if ($NeedsRerun -ne 0) {
$Tags | Out-File $MarkerFile;
if (!$ShellInvocation) { Read-Host 'Press Enter to exit' }
exit 0;
}
}
28 changes: 17 additions & 11 deletions vnext/Shared/DevSupportManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
#include <cxxreact/MessageQueueThread.h>
#pragma warning(pop)

#include <future>
#include <mutex>

#include <AppModel.h>
Expand All @@ -47,7 +46,9 @@ using namespace facebook::react;

namespace Microsoft::ReactNative {

std::future<std::pair<std::string, bool>> GetJavaScriptFromServerAsync(const std::string &url) {
winrt::Windows::Foundation::IAsyncAction GetJavaScriptFromServerAsync(
const std::string &url,
std::pair<std::string, bool> &result) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same here. We must not use the out parameters with async functions.

winrt::Windows::Web::Http::Filters::HttpBaseProtocolFilter filter;
filter.CacheControl().ReadBehavior(winrt::Windows::Web::Http::Filters::HttpCacheReadBehavior::NoCache);
winrt::Windows::Web::Http::HttpClient httpClient(filter);
Expand All @@ -61,8 +62,9 @@ std::future<std::pair<std::string, bool>> GetJavaScriptFromServerAsync(const std
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);
result =
std::make_pair(Microsoft::Common::Unicode::Utf16ToUtf8(e.message().c_str(), e.message().size()).c_str(), false);
co_return;
}
#else
co_await lessthrow_await_adapter<winrt::Windows::Foundation::IAsyncOperationWithProgress<
Expand All @@ -77,7 +79,8 @@ std::future<std::pair<std::string, bool>> GetJavaScriptFromServerAsync(const std
} else {
error = fmt::format("Error 0x{:x} downloading {}.", static_cast<int>(asyncRequest.ErrorCode()), url);
}
co_return std::make_pair(error, false);
result = std::make_pair(error, false);
co_return;
}

winrt::Windows::Web::Http::HttpResponseMessage response = asyncRequest.GetResults();
Expand All @@ -88,20 +91,20 @@ std::future<std::pair<std::string, bool>> GetJavaScriptFromServerAsync(const std

reader.UnicodeEncoding(winrt::Windows::Storage::Streams::UnicodeEncoding::Utf8);
uint32_t len = reader.UnconsumedBufferLength();
std::string result;
std::string resultStr;
if (len > 0 || response.IsSuccessStatusCode()) {
std::string data;
data.resize(len);
auto buf = reinterpret_cast<uint8_t *>(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);
resultStr = std::move(data);
} else {
result = fmt::format("HTTP Error {} downloading {}.", static_cast<int>(response.StatusCode()), url);
resultStr = fmt::format("HTTP Error {} downloading {}.", static_cast<int>(response.StatusCode()), url);
}

co_return std::make_pair(std::move(result), response.IsSuccessStatusCode());
result = std::make_pair(std::move(resultStr), response.IsSuccessStatusCode());
}

void LaunchDevTools(const facebook::react::DevSettings &settings) {
Expand Down Expand Up @@ -185,7 +188,8 @@ std::string GetPackageName(const std::string &bundleAppId) {
return packageName;
}

std::future<winrt::Windows::Web::Http::HttpStatusCode> PollForLiveReload(const std::string &url) {
winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::Web::Http::HttpStatusCode> 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");
Expand Down Expand Up @@ -299,7 +303,9 @@ std::pair<std::string, bool> GetJavaScriptFromServer(
inlineSourceMap,
hermesBytecodeVersion);
try {
return GetJavaScriptFromServerAsync(bundleUrl).get();
std::pair<std::string, bool> result;
GetJavaScriptFromServerAsync(bundleUrl, result).get();
return result;
} catch (winrt::hresult_error const &e) {
return std::make_pair(
"Error: " + Microsoft::Common::Unicode::Utf16ToUtf8(e.message().c_str(), e.message().size()), false);
Expand Down
1 change: 0 additions & 1 deletion vnext/Shared/DevSupportManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
#include <winrt/Windows.Networking.Sockets.h>
#include <atomic>
#include <functional>
#include <future>
#include <memory>
#include <string>

Expand Down
6 changes: 5 additions & 1 deletion vnext/Shared/Networking/WinRTWebSocketResource.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
Loading