From 509c7a112d99b418dee14ac1347a8bdd27e53775 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 11 Jun 2025 09:00:56 +0000
Subject: [PATCH 1/4] Initial plan for issue
From b03c55079e7aff3211b52f45e12cb4e46ab59f39 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 11 Jun 2025 09:08:35 +0000
Subject: [PATCH 2/4] Remove deprecated autolink functionality to copy
useWinUI3 flags from react-native.config.js
Co-authored-by: anupriya13 <54227869+anupriya13@users.noreply.github.com>
---
.../autolinkWindows/autolinkWindows.ts | 23 +-----
.../cli/src/e2etest/autolink.test.ts | 74 -------------------
.../cli/src/e2etest/projectConfig.test.ts | 45 -----------
3 files changed, 2 insertions(+), 140 deletions(-)
diff --git a/packages/@react-native-windows/cli/src/commands/autolinkWindows/autolinkWindows.ts b/packages/@react-native-windows/cli/src/commands/autolinkWindows/autolinkWindows.ts
index 075ab1901dc..7592278db43 100644
--- a/packages/@react-native-windows/cli/src/commands/autolinkWindows/autolinkWindows.ts
+++ b/packages/@react-native-windows/cli/src/commands/autolinkWindows/autolinkWindows.ts
@@ -712,7 +712,6 @@ export class AutoLinkWindows {
public async ensureXAMLDialect() {
let changesNeeded = false;
- const useWinUI3FromConfig = this.getWindowsConfig().useWinUI3;
const experimentalFeatures = this.getExperimentalFeaturesPropsXml();
if (experimentalFeatures) {
const useWinUI3FromExperimentalFeatures =
@@ -729,30 +728,12 @@ export class AutoLinkWindows {
experimentalFeatures.content,
'WinUI3Version',
);
- // Use the UseWinUI3 value in react-native.config.js, or if not present, the value from ExperimentalFeatures.props
+ // Use the UseWinUI3 value from ExperimentalFeatures.props
changesNeeded = await this.updatePackagesConfigXAMLDialect(
- useWinUI3FromConfig !== undefined
- ? useWinUI3FromConfig
- : useWinUI3FromExperimentalFeatures,
+ useWinUI3FromExperimentalFeatures,
targetWinUI2xVersion,
targetWinUI3xVersion,
);
- if (useWinUI3FromConfig !== undefined) {
- // Make sure ExperimentalFeatures.props matches the value that comes from react-native.config.js
- const node =
- experimentalFeatures.content.getElementsByTagName('UseWinUI3');
- const newValue = useWinUI3FromConfig ? 'true' : 'false';
- changesNeeded = node.item(0)?.textContent !== newValue || changesNeeded;
- if (!this.options.check && changesNeeded) {
- node.item(0)!.textContent = newValue;
- const experimentalFeaturesOutput =
- new XMLSerializer().serializeToString(experimentalFeatures.content);
- await this.updateFile(
- experimentalFeatures.path,
- experimentalFeaturesOutput,
- );
- }
- }
}
return changesNeeded;
}
diff --git a/packages/@react-native-windows/cli/src/e2etest/autolink.test.ts b/packages/@react-native-windows/cli/src/e2etest/autolink.test.ts
index ac78d004fa4..25bb0a1e575 100644
--- a/packages/@react-native-windows/cli/src/e2etest/autolink.test.ts
+++ b/packages/@react-native-windows/cli/src/e2etest/autolink.test.ts
@@ -249,81 +249,7 @@ test('one valid cs autolink dependency', () => {
);
});
-test('ensureXAMLDialect - useWinUI3=true in react-native.config.js, useWinUI3=false in ExperimentalFeatures.props', async () => {
- const folder = path.resolve('src/e2etest/projects/WithWinUI3');
-
- // Create project with UseWinUI3 == false in ExperimentalFeatures.props
- await ensureCppAppProject(folder, 'WithWinUI3', false, false, false);
-
- const rnc = require(path.join(folder, 'react-native.config.js'));
-
- const config = projectConfigWindows(folder, rnc.project.windows)!;
- // Set useWinUI3=true in react-native.config.js
- config.useWinUI3 = true;
-
- const al = new AutoLinkTest(
- {windows: config},
- {},
- {
- check: false,
- logging: false,
- },
- );
- al.experimentalFeaturesProps = `false`;
- al.packagesConfig = ``;
-
- const exd = await al.ensureXAMLDialect();
- expect(exd).toBeTruthy();
-
- const expectedExperimentalFeatures =
- 'true';
- expect(al.experimentalFeaturesProps).toEqual(expectedExperimentalFeatures);
-
- // example packages.config:
- //
- //
- //
- //
- //
- expect(al.packagesConfig).toContain('Microsoft.WindowsAppSDK');
- expect(al.packagesConfig).toContain('');
- expect(al.packagesConfig).not.toContain('Microsoft.UI.Xaml');
-});
-
-test('ensureXAMLDialect - useWinUI3=false in react-native.config.js, useWinUI3=true in ExperimentalFeatures.props', async () => {
- const folder = path.resolve('src/e2etest/projects/WithWinUI3');
- const rnc = require(path.join(folder, 'react-native.config.js'));
-
- const config = projectConfigWindows(folder, rnc.project.windows)!;
- config.useWinUI3 = false;
- const al = new AutoLinkTest(
- {windows: config},
- {},
- {
- check: false,
- logging: false,
- },
- );
- al.experimentalFeaturesProps = `true`;
- al.packagesConfig = ``;
- const exd = await al.ensureXAMLDialect();
- expect(exd).toBeTruthy();
-
- const expectedExperimentalFeatures =
- 'false';
- expect(al.experimentalFeaturesProps).toEqual(expectedExperimentalFeatures);
-
- // example packages.config:
- //
- //
- //
- //
- //
- expect(al.packagesConfig).not.toContain('Microsoft.WindowsAppSDK');
- expect(al.packagesConfig).toContain('');
- expect(al.packagesConfig).toContain('Microsoft.UI.Xaml');
-});
test('ensureXAMLDialect - useWinUI3 not in react-native.config.js, useWinUI3=true in ExperimentalFeatures.props', async () => {
const folder = path.resolve('src/e2etest/projects/WithWinUI3');
diff --git a/packages/@react-native-windows/cli/src/e2etest/projectConfig.test.ts b/packages/@react-native-windows/cli/src/e2etest/projectConfig.test.ts
index c04bdd4ee66..b6d9bba84fc 100644
--- a/packages/@react-native-windows/cli/src/e2etest/projectConfig.test.ts
+++ b/packages/@react-native-windows/cli/src/e2etest/projectConfig.test.ts
@@ -119,48 +119,3 @@ test.each(projects)(
}
},
);
-
-// Skipping this test as the feature is broken and needs to be removed, see https://github.com/microsoft/react-native-windows/issues/14601
-test.skip('useWinUI3=true in react-native.config.js, UseWinUI3=false in ExperimentalFeatures.props', async () => {
- const folder = path.resolve('src/e2etest/projects/WithWinUI3');
-
- // Create project with UseWinUI3 == false in ExperimentalFeatures.props
- await ensureCppAppProject(folder, 'WithWinUI3', false, false, false);
-
- const rnc = require(path.join(folder, 'react-native.config.js'));
-
- const config = projectConfigWindows(folder, rnc.project.windows)!;
- // Set useWinUI3=true in react-native.config.js
- config.useWinUI3 = true;
-
- const experimentalFeaturesPropsFile = path.join(
- folder,
- 'windows/ExperimentalFeatures.props',
- );
-
- // Verify starting props file
- const startingExperimentalFeatures = (
- await fs.readFile(experimentalFeaturesPropsFile)
- ).toString();
- expect(startingExperimentalFeatures.replace(/\r/g, '')).toMatchSnapshot();
-
- // Run Autolink to sync the files
- const al = new AutoLinkWindows(
- {windows: config},
- {},
- {
- check: false,
- logging: false,
- },
- );
-
- const exd = await al.ensureXAMLDialect();
- expect(exd).toBeTruthy();
-
- // Verify ending props file
- const finalExperimentalFeatures = (
- await fs.readFile(experimentalFeaturesPropsFile)
- ).toString();
-
- expect(finalExperimentalFeatures.replace(/\r/g, '')).toMatchSnapshot();
-});
From 5af8740e297f4321d045821de14dbc152b0eee84 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 11 Jun 2025 09:35:20 +0000
Subject: [PATCH 3/4] Add change file for deprecating autolink useWinUI3
functionality
---
...e-windows-cli-d7a7f24d-f06e-4a41-b87a-1def406d65f2.json | 7 +++++++
1 file changed, 7 insertions(+)
create mode 100644 change/@react-native-windows-cli-d7a7f24d-f06e-4a41-b87a-1def406d65f2.json
diff --git a/change/@react-native-windows-cli-d7a7f24d-f06e-4a41-b87a-1def406d65f2.json b/change/@react-native-windows-cli-d7a7f24d-f06e-4a41-b87a-1def406d65f2.json
new file mode 100644
index 00000000000..3a49fdad25c
--- /dev/null
+++ b/change/@react-native-windows-cli-d7a7f24d-f06e-4a41-b87a-1def406d65f2.json
@@ -0,0 +1,7 @@
+{
+ "type": "prerelease",
+ "comment": "Remove deprecated autolink functionality to copy useWinUI3 flags from react-native.config.js into ExperimentalFeatures.props",
+ "packageName": "@react-native-windows/cli",
+ "email": "copilot@github.com",
+ "dependentChangeType": "prerelease"
+}
\ No newline at end of file
From 7ce01eefcffad7fd30ad777b3adeb16b9e498078 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 1 Jul 2025 21:03:23 +0000
Subject: [PATCH 4/4] Completely remove ensureXAMLDialect() function and its
functionality
Co-authored-by: jonthysell <10852185+jonthysell@users.noreply.github.com>
---
.../autolinkWindows/autolinkWindows.ts | 162 +-----------------
.../cli/src/e2etest/autolink.test.ts | 101 +----------
2 files changed, 3 insertions(+), 260 deletions(-)
diff --git a/packages/@react-native-windows/cli/src/commands/autolinkWindows/autolinkWindows.ts b/packages/@react-native-windows/cli/src/commands/autolinkWindows/autolinkWindows.ts
index 7592278db43..91835a3b132 100644
--- a/packages/@react-native-windows/cli/src/commands/autolinkWindows/autolinkWindows.ts
+++ b/packages/@react-native-windows/cli/src/commands/autolinkWindows/autolinkWindows.ts
@@ -13,9 +13,9 @@ import fs from '@react-native-windows/fs';
import path from 'path';
import chalk from 'chalk';
import {performance} from 'perf_hooks';
-import {XMLSerializer} from '@xmldom/xmldom';
+
import {Ora} from 'ora';
-const formatter = require('xml-formatter');
+
import type {
Command,
@@ -114,9 +114,6 @@ export class AutoLinkWindows {
verboseMessage('Parsing dependencies...', verbose);
- this.changesNecessary =
- (await this.ensureXAMLDialect()) || this.changesNecessary;
-
// Generating cs/cpp files for app code consumption
if (projectLang === 'cs') {
this.changesNecessary =
@@ -693,161 +690,6 @@ export class AutoLinkWindows {
return changesNecessary;
}
- protected getExperimentalFeaturesPropsXml() {
- const experimentalFeaturesProps = path.join(
- path.dirname(this.getSolutionFile()),
- 'ExperimentalFeatures.props',
- );
- if (fs.existsSync(experimentalFeaturesProps)) {
- const experimentalFeaturesContents = configUtils.readProjectFile(
- experimentalFeaturesProps,
- );
- return {
- path: experimentalFeaturesProps,
- content: experimentalFeaturesContents,
- };
- }
- return undefined;
- }
-
- public async ensureXAMLDialect() {
- let changesNeeded = false;
- const experimentalFeatures = this.getExperimentalFeaturesPropsXml();
- if (experimentalFeatures) {
- const useWinUI3FromExperimentalFeatures =
- configUtils
- .tryFindPropertyValue(experimentalFeatures.content, 'UseWinUI3')
- ?.toLowerCase() === 'true';
- // Check if WinUI2xVersion is specified in experimental features
- const targetWinUI2xVersion = configUtils.tryFindPropertyValue(
- experimentalFeatures.content,
- 'WinUI2xVersion',
- );
- // Check if WinUI3Version is specified in experimental features
- const targetWinUI3xVersion = configUtils.tryFindPropertyValue(
- experimentalFeatures.content,
- 'WinUI3Version',
- );
- // Use the UseWinUI3 value from ExperimentalFeatures.props
- changesNeeded = await this.updatePackagesConfigXAMLDialect(
- useWinUI3FromExperimentalFeatures,
- targetWinUI2xVersion,
- targetWinUI3xVersion,
- );
- }
- return changesNeeded;
- }
-
- protected getPackagesConfigXml() {
- const projectFile = this.getProjectFile();
- const packagesConfig = path.join(
- path.dirname(projectFile),
- 'packages.config',
- );
-
- if (fs.existsSync(packagesConfig)) {
- return {
- path: packagesConfig,
- content: configUtils.readProjectFile(packagesConfig),
- };
- }
- return undefined;
- }
-
- private async updatePackagesConfigXAMLDialect(
- useWinUI3: boolean,
- targetWinUI2xVersion: string | null,
- targetWinUI3xVersion: string | null,
- ) {
- let changed = false;
- const packagesConfig = this.getPackagesConfigXml();
- if (packagesConfig) {
- // if we don't have a packages.config, then this is a C# project, in which case we use and dynamically pick the right XAML package.
- const project = this.getWindowsConfig();
-
- const winUIPropsPath = path.join(
- resolveRnwRoot(project),
- 'PropertySheets/WinUI.props',
- );
- const winuiPropsContents = configUtils.readProjectFile(winUIPropsPath);
-
- // Use the given WinUI2xVersion, otherwise fallback to WinUI.props
- const winui2xVersion =
- targetWinUI2xVersion ??
- configUtils.tryFindPropertyValue(winuiPropsContents, 'WinUI2xVersion');
-
- // Use the given WinUI3Version, otherwise fallback to WinUI.props
- const winui3Version =
- targetWinUI3xVersion ??
- configUtils.tryFindPropertyValue(winuiPropsContents, 'WinUI3Version');
-
- const dialects = [
- {id: 'Microsoft.WindowsAppSDK', version: winui3Version!},
- {id: 'Microsoft.UI.Xaml', version: winui2xVersion!},
- ];
- const keepPkg = useWinUI3 ? dialects[0] : dialects[1];
- const removePkg = useWinUI3 ? dialects[1] : dialects[0];
-
- changed = this.updatePackagesConfig(
- packagesConfig,
- [removePkg],
- [keepPkg],
- );
-
- if (!this.options.check && changed) {
- const serializer = new XMLSerializer();
- const output = serializer.serializeToString(packagesConfig.content);
- const formattedXml = formatter(output, {indentation: ' '});
- await this.updateFile(packagesConfig.path, formattedXml);
- }
- }
- return changed;
- }
-
- private updatePackagesConfig(
- packagesConfig: {path: string; content: Document},
- removePkgs: {id: string; version: string}[],
- keepPkgs: {id: string; version: string}[],
- ) {
- let changed = false;
- const packageElements =
- packagesConfig.content.documentElement.getElementsByTagName('package');
-
- const nodesToRemove: Element[] = [];
-
- for (let i = 0; i < packageElements.length; i++) {
- const packageElement = packageElements.item(i)!;
- const idAttr = packageElement!.getAttributeNode('id');
- const id = idAttr!.value;
- const keepPkg = keepPkgs.find(pkg => pkg.id === id);
- if (removePkgs.find(pkg => pkg.id === id)) {
- nodesToRemove.push(packageElement);
- changed = true;
- } else if (keepPkg) {
- changed =
- changed || keepPkg.version !== packageElement.getAttribute('version');
- packageElement.setAttribute('version', keepPkg.version!);
- keepPkgs = keepPkgs.filter(pkg => pkg.id !== keepPkg.id);
- }
- }
-
- nodesToRemove.forEach(pkg =>
- packagesConfig.content.documentElement.removeChild(pkg),
- );
-
- keepPkgs.forEach(keepPkg => {
- const newPkg = packagesConfig.content.createElement('package');
-
- Object.entries(keepPkg).forEach(([attr, value]) => {
- newPkg.setAttribute(attr, value as string);
- });
- newPkg.setAttribute('targetFramework', 'native');
- packagesConfig.content.documentElement.appendChild(newPkg);
- changed = true;
- });
- return changed;
- }
-
/** @return The CLI command to invoke autolink-windows independently */
public getAutolinkWindowsCommand() {
const folder = this.windowsAppConfig.folder;
diff --git a/packages/@react-native-windows/cli/src/e2etest/autolink.test.ts b/packages/@react-native-windows/cli/src/e2etest/autolink.test.ts
index 25bb0a1e575..1c92146161e 100644
--- a/packages/@react-native-windows/cli/src/e2etest/autolink.test.ts
+++ b/packages/@react-native-windows/cli/src/e2etest/autolink.test.ts
@@ -6,14 +6,12 @@
import path from 'path';
import {commanderNameToOptionName} from '@react-native-windows/telemetry';
-import {projectConfigWindows} from '../commands/config/projectConfig';
import {AutoLinkWindows} from '../commands/autolinkWindows/autolinkWindows';
import {
AutoLinkOptions,
autolinkOptions,
} from '../commands/autolinkWindows/autolinkWindowsOptions';
-import {DOMParser} from '@xmldom/xmldom';
-import {ensureCppAppProject, ensureWinUI3Project} from './projectConfig.utils';
+import {ensureWinUI3Project} from './projectConfig.utils';
test('autolink with no windows project', () => {
expect(() => {
@@ -37,34 +35,7 @@ class AutoLinkTest extends AutoLinkWindows {
public getWindowsProjectConfig() {
return this.windowsAppConfig;
}
- public packagesConfig = '';
- public experimentalFeaturesProps = '';
- protected getPackagesConfigXml() {
- return {
- path: 'packages.config',
- content: new DOMParser().parseFromString(
- this.packagesConfig,
- 'application/xml',
- ),
- };
- }
- protected getExperimentalFeaturesPropsXml() {
- return {
- path: 'ExperimentalFeatures.props',
- content: new DOMParser().parseFromString(
- this.experimentalFeaturesProps,
- 'application/xml',
- ),
- };
- }
protected async updateFile(filepath: string, content: string) {
- if (filepath === 'packages.config') {
- this.packagesConfig = content;
- } else if (filepath === 'ExperimentalFeatures.props') {
- this.experimentalFeaturesProps = content;
- } else {
- throw new Error(`Unknown path: ${filepath}`);
- }
return true;
}
}
@@ -250,76 +221,6 @@ test('one valid cs autolink dependency', () => {
});
-
-test('ensureXAMLDialect - useWinUI3 not in react-native.config.js, useWinUI3=true in ExperimentalFeatures.props', async () => {
- const folder = path.resolve('src/e2etest/projects/WithWinUI3');
- const rnc = require(path.join(folder, 'react-native.config.js'));
-
- const config = projectConfigWindows(folder, rnc.project.windows)!;
- delete config.useWinUI3;
- const al = new AutoLinkTest(
- {windows: config},
- {},
- {
- check: false,
- logging: false,
- },
- );
- al.experimentalFeaturesProps = `true`;
- al.packagesConfig = ``;
-
- const exd = await al.ensureXAMLDialect();
- expect(exd).toBeTruthy();
-
- const expectedExperimentalFeatures =
- 'true';
- expect(al.experimentalFeaturesProps).toEqual(expectedExperimentalFeatures);
-
- // example packages.config:
- //
- //
- //
- //
- //
- expect(al.packagesConfig).toContain('Microsoft.WindowsAppSDK');
- expect(al.packagesConfig).toContain('');
- expect(al.packagesConfig).not.toContain('Microsoft.UI.Xaml');
-});
-
-test('ensureXAMLDialect - useWinUI3 not in react-native.config.js, useWinUI3=false in ExperimentalFeatures.props', async () => {
- const folder = path.resolve('src/e2etest/projects/WithWinUI3');
- const rnc = require(path.join(folder, 'react-native.config.js'));
-
- const config = projectConfigWindows(folder, rnc.project.windows)!;
- delete config.useWinUI3;
- const al = new AutoLinkTest(
- {windows: config},
- {},
- {
- check: false,
- logging: false,
- },
- );
- al.experimentalFeaturesProps = `false`;
- al.packagesConfig = ``;
-
- const exd = await al.ensureXAMLDialect();
- expect(exd).toBeTruthy();
-
- const expectedExperimentalFeatures = `false`;
- expect(al.experimentalFeaturesProps).toEqual(expectedExperimentalFeatures);
-
- // example packages.config:
- //
- //
- //
- //
- //
- expect(al.packagesConfig).not.toContain('Microsoft.WindowsAppSDK');
- expect(al.packagesConfig).toContain('');
- expect(al.packagesConfig).toContain('Microsoft.UI.Xaml');
-});
-
test('Indirect autolink dependency', () => {
const autolink = new AutoLinkTest(
{windows: {folder: __dirname, sourceDir: '.', solutionFile: 'foo.sln'}},