Skip to content

Commit 21565ff

Browse files
authored
sync-react: Handle version bumps across SemVer minors and release channels (#74091)
1 parent 58d3982 commit 21565ff

File tree

1 file changed

+46
-40
lines changed

1 file changed

+46
-40
lines changed

scripts/sync-react.js

Lines changed: 46 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ const pullRequestReviewers = ['eps1lon']
2121
*/
2222
const pagesRouterReact = '^19.0.0'
2323

24+
const defaultLatestChannel = 'canary'
2425
const filesReferencingReactPeerDependencyVersion = [
2526
'run-tests.js',
2627
'packages/create-next-app/templates/index.ts',
@@ -38,6 +39,24 @@ const appManifestsInstallingNextjsPeerDependencies = [
3839
'test/e2e/next-test/first-time-setup-ts/package.json',
3940
]
4041

42+
async function getSchedulerVersion(reactVersion) {
43+
const url = `https://registry.npmjs.org/react-dom/${reactVersion}`
44+
const response = await fetch(url, {
45+
headers: {
46+
Accept: 'application/json',
47+
},
48+
})
49+
if (!response.ok) {
50+
throw new Error(
51+
`${url}: ${response.status} ${response.statusText}\n${await response.text()}`
52+
)
53+
}
54+
55+
const manifest = await response.json()
56+
57+
return manifest.dependencies['scheduler']
58+
}
59+
4160
// Use this script to update Next's vendored copy of React and related packages:
4261
//
4362
// Basic usage (defaults to most recent React canary version):
@@ -46,13 +65,7 @@ const appManifestsInstallingNextjsPeerDependencies = [
4665
// Update package.json but skip installing the dependencies automatically:
4766
// pnpm run sync-react --no-install
4867

49-
async function sync({
50-
channel,
51-
newVersionStr,
52-
newSha,
53-
newDateString,
54-
noInstall,
55-
}) {
68+
async function sync({ channel, newVersionStr, noInstall }) {
5669
const useExperimental = channel === 'experimental'
5770
const cwd = process.cwd()
5871
const pkgJson = JSON.parse(
@@ -64,38 +77,35 @@ async function sync({
6477
useExperimental ? 'react-experimental-builtin' : 'react-builtin'
6578
].replace(/^npm:react@/, '')
6679

67-
const baseVersionInfo = extractInfoFromReactVersion(baseVersionStr)
68-
if (!baseVersionInfo) {
69-
throw new Error(
70-
'Base react version does not match expected format: ' + baseVersionStr
71-
)
72-
}
73-
74-
const {
75-
sha: baseSha,
76-
releaseLabel: baseReleaseLabel,
77-
dateString: baseDateString,
78-
} = baseVersionInfo
79-
80-
console.log(`Updating "react@${channel}" to ${newSha}...\n`)
81-
if (newSha === baseSha) {
80+
console.log(`Updating "react@${channel}" to ${newVersionStr}...`)
81+
if (newVersionStr === baseVersionStr) {
8282
console.log('Already up to date.')
8383
return
8484
}
8585

86+
const baseSchedulerVersionStr = devDependencies[
87+
useExperimental ? 'scheduler-experimental-builtin' : 'scheduler-builtin'
88+
].replace(/^npm:scheduler@/, '')
89+
const newSchedulerVersionStr = await getSchedulerVersion(newVersionStr)
90+
console.log(`Updating "scheduler@${channel}" to ${newSchedulerVersionStr}...`)
91+
8692
for (const [dep, version] of Object.entries(devDependencies)) {
87-
if (version.endsWith(`${baseReleaseLabel}-${baseSha}-${baseDateString}`)) {
93+
if (version.endsWith(baseVersionStr)) {
94+
devDependencies[dep] = version.replace(baseVersionStr, newVersionStr)
95+
} else if (version.endsWith(baseSchedulerVersionStr)) {
8896
devDependencies[dep] = version.replace(
89-
`${baseReleaseLabel}-${baseSha}-${baseDateString}`,
90-
`${channel}-${newSha}-${newDateString}`
97+
baseSchedulerVersionStr,
98+
newSchedulerVersionStr
9199
)
92100
}
93101
}
94102
for (const [dep, version] of Object.entries(pnpmOverrides)) {
95-
if (version.endsWith(`${baseReleaseLabel}-${baseSha}-${baseDateString}`)) {
103+
if (version.endsWith(baseVersionStr)) {
104+
pnpmOverrides[dep] = version.replace(baseVersionStr, newVersionStr)
105+
} else if (version.endsWith(baseSchedulerVersionStr)) {
96106
pnpmOverrides[dep] = version.replace(
97-
`${baseReleaseLabel}-${baseSha}-${baseDateString}`,
98-
`${channel}-${newSha}-${newDateString}`
107+
baseSchedulerVersionStr,
108+
newSchedulerVersionStr
99109
)
100110
}
101111
}
@@ -224,7 +234,7 @@ async function main() {
224234
) {
225235
const { stdout, stderr } = await execa(
226236
'npm',
227-
['--silent', 'view', 'react@canary', 'version'],
237+
['--silent', 'view', `react@${defaultLatestChannel}`, 'version'],
228238
{
229239
// Avoid "Usage Error: This project is configured to use pnpm".
230240
cwd: '/tmp',
@@ -236,7 +246,7 @@ async function main() {
236246
}
237247
newVersionStr = stdout.trim()
238248
console.log(
239-
`--version was not provided. Using react@canary: ${newVersionStr}`
249+
`--version was not provided. Using react@${defaultLatestChannel}: ${newVersionStr}`
240250
)
241251
}
242252

@@ -253,7 +263,7 @@ Or, run this command with no arguments to use the most recently published versio
253263
}
254264
const { sha: newSha, dateString: newDateString } = newVersionInfo
255265

256-
const branchName = `update/react/${newSha}-${newDateString}`
266+
const branchName = `update/react/${newVersionStr}`
257267
if (createPull) {
258268
const { exitCode, all, command } = await execa(
259269
'git',
@@ -292,24 +302,20 @@ Or, run this command with no arguments to use the most recently published versio
292302
)
293303

294304
await sync({
295-
newDateString,
296-
newSha,
297-
newVersionStr,
305+
newVersionStr: `0.0.0-experimental-${newSha}-${newDateString}`,
298306
noInstall: !install,
299307
channel: 'experimental',
300308
})
301309
if (commit) {
302310
await commitEverything('Update `react@experimental`')
303311
}
304312
await sync({
305-
newDateString,
306-
newSha,
307313
newVersionStr,
308314
noInstall: !install,
309-
channel: 'rc',
315+
channel: '<framework-stable>',
310316
})
311317
if (commit) {
312-
await commitEverything('Update `react@rc`')
318+
await commitEverything('Update `react`')
313319
}
314320

315321
const baseVersionInfo = extractInfoFromReactVersion(baseVersionStr)
@@ -394,9 +400,9 @@ Or, run this command with no arguments to use the most recently published versio
394400

395401
// Install the updated dependencies and build the vendored React files.
396402
if (!install) {
397-
console.log('Skipping install step because --no-install flag was passed.\n')
403+
console.log('Skipping install step because --no-install flag was passed.')
398404
} else {
399-
console.log('Installing dependencies...\n')
405+
console.log('Installing dependencies...')
400406

401407
const installSubprocess = execa('pnpm', [
402408
'install',

0 commit comments

Comments
 (0)