Merge pull request #33422 from backstage/rugvip/drop-react-17-packages-ui

Drop React 17 support from `@backstage/ui`
This commit is contained in:
Patrik Oldsberg
2026-03-18 17:30:17 +01:00
committed by GitHub
5 changed files with 39 additions and 11 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/ui': minor
---
**BREAKING**: Dropped support for React 17. The minimum supported React version is now 18.
@@ -0,0 +1,5 @@
---
'@backstage/repo-tools': patch
---
Added support for packages that only support React 18+ in the `peer-deps` command.
@@ -39,6 +39,16 @@ const peerDependencies = {
'react-router-dom': '^6.30.2',
};
// Packages that have dropped React 17 support and only support React 18+
const peerDependenciesReact18Only = {
'@types/react': '^18.0.0',
react: '^18.0.0',
'react-dom': '^18.0.0',
'react-router-dom': '^6.30.2',
};
const react18OnlyPackages = new Set(['@backstage/ui']);
const groupsOfPeerDependencies = [['@types/react', 'react', 'react-dom']];
const optionalPeerDependencies = new Set(['@types/react']);
@@ -79,14 +89,21 @@ const matchesDependency = (dep: string, packageJson: ExtendedPackageJSON) => {
);
};
const getExpectedPeerDependencies = (packageJson: ExtendedPackageJSON) => {
if (react18OnlyPackages.has(packageJson.name!)) {
return peerDependenciesReact18Only;
}
return peerDependencies;
};
const matchesPeerDependency = (
dep: string,
packageJson: ExtendedPackageJSON,
) => {
const expected = getExpectedPeerDependencies(packageJson);
return (
packageJson.peerDependencies &&
packageJson.peerDependencies[dep] ===
peerDependencies[dep as keyof typeof peerDependencies]
packageJson.peerDependencies[dep] === expected[dep as keyof typeof expected]
);
};
@@ -125,6 +142,7 @@ export default async ({ fix }: { fix: boolean }) => {
for (const pkg of packagesWithRelevantDependencies) {
const packageJson = pkg.packageJson as ExtendedPackageJSON;
const expectedPeerDeps = getExpectedPeerDependencies(packageJson);
for (const dep of Object.keys(peerDependencies)) {
// Validate that the peer dependencies are present.
if (isPeerDependency(dep, packageJson)) {
@@ -182,7 +200,7 @@ export default async ({ fix }: { fix: boolean }) => {
packageJson.peerDependencies =
packageJson.peerDependencies || {};
packageJson.peerDependencies[groupDep] =
peerDependencies[groupDep as keyof typeof peerDependencies];
expectedPeerDeps[groupDep as keyof typeof expectedPeerDeps];
});
}
}
@@ -209,7 +227,7 @@ export default async ({ fix }: { fix: boolean }) => {
attemptToApplyFix(() => {
packageJson.peerDependencies = packageJson.peerDependencies || {};
packageJson.peerDependencies[dep] =
peerDependencies[dep as keyof typeof peerDependencies];
expectedPeerDeps[dep as keyof typeof expectedPeerDeps];
});
}
} else {
@@ -219,7 +237,7 @@ export default async ({ fix }: { fix: boolean }) => {
attemptToApplyFix(() => {
packageJson.peerDependencies = packageJson.peerDependencies || {};
packageJson.peerDependencies[dep] =
peerDependencies[dep as keyof typeof peerDependencies];
expectedPeerDeps[dep as keyof typeof expectedPeerDeps];
});
}
}
+3 -3
View File
@@ -67,9 +67,9 @@
"storybook": "^10.3.0-alpha.1"
},
"peerDependencies": {
"@types/react": "^17.0.0 || ^18.0.0",
"react": "^17.0.0 || ^18.0.0",
"react-dom": "^17.0.0 || ^18.0.0",
"@types/react": "^18.0.0",
"react": "^18.0.0",
"react-dom": "^18.0.0",
"react-router-dom": "^6.30.2"
},
"peerDependenciesMeta": {
+3 -3
View File
@@ -7949,9 +7949,9 @@ __metadata:
storybook: "npm:^10.3.0-alpha.1"
use-sync-external-store: "npm:^1.4.0"
peerDependencies:
"@types/react": ^17.0.0 || ^18.0.0
react: ^17.0.0 || ^18.0.0
react-dom: ^17.0.0 || ^18.0.0
"@types/react": ^18.0.0
react: ^18.0.0
react-dom: ^18.0.0
react-router-dom: ^6.30.2
peerDependenciesMeta:
"@types/react":