@@ -5,6 +5,7 @@ const fsp = require('fs/promises')
5
5
const process = require ( 'process' )
6
6
const execa = require ( 'execa' )
7
7
const { Octokit } = require ( 'octokit' )
8
+ const SemVer = require ( 'semver' )
8
9
const yargs = require ( 'yargs' )
9
10
10
11
/** @type {any } */
@@ -17,9 +18,13 @@ const pullRequestReviewers = ['eps1lon']
17
18
/**
18
19
* Set to `null` to automatically sync the React version of Pages Router with App Router React version.
19
20
* Set to a specific version to override the Pages Router React version e.g. `^19.0.0`.
21
+ *
22
+ * "Active" just refers to our current development practice. While we do support
23
+ * React 18 in pages router, we don't focus our development process on it considering
24
+ * it does not receive new features.
20
25
* @type {string | null }
21
26
*/
22
- const pagesRouterReact = '^19.0.0'
27
+ const activePagesRouterReact = '^19.0.0'
23
28
24
29
const defaultLatestChannel = 'canary'
25
30
const filesReferencingReactPeerDependencyVersion = [
@@ -176,6 +181,31 @@ async function getChangelogFromGitHub(baseSha, newSha) {
176
181
return changelog . length > 0 ? changelog . join ( '\n' ) : null
177
182
}
178
183
184
+ async function findHighestNPMReactVersion ( versionLike ) {
185
+ const { stdout, stderr } = await execa (
186
+ 'npm' ,
187
+ [ '--silent' , 'view' , '--json' , `react@${ versionLike } ` , 'version' ] ,
188
+ {
189
+ // Avoid "Usage Error: This project is configured to use pnpm".
190
+ cwd : '/tmp' ,
191
+ }
192
+ )
193
+ if ( stderr ) {
194
+ console . error ( stderr )
195
+ throw new Error (
196
+ `Failed to read highest react@${ versionLike } version from npm.`
197
+ )
198
+ }
199
+
200
+ const result = JSON . parse ( stdout )
201
+
202
+ return typeof result === 'string'
203
+ ? result
204
+ : result . sort ( ( a , b ) => {
205
+ return SemVer . compare ( b , a )
206
+ } ) [ 0 ]
207
+ }
208
+
179
209
async function main ( ) {
180
210
const cwd = process . cwd ( )
181
211
const errors = [ ]
@@ -232,19 +262,7 @@ async function main() {
232
262
// TODO: Fork arguments in GitHub workflow to ensure `--version ""` is considered a mistake
233
263
newVersionStr === ''
234
264
) {
235
- const { stdout, stderr } = await execa (
236
- 'npm' ,
237
- [ '--silent' , 'view' , `react@${ defaultLatestChannel } ` , 'version' ] ,
238
- {
239
- // Avoid "Usage Error: This project is configured to use pnpm".
240
- cwd : '/tmp' ,
241
- }
242
- )
243
- if ( stderr ) {
244
- console . error ( stderr )
245
- throw new Error ( 'Failed to read latest React canary version from npm.' )
246
- }
247
- newVersionStr = stdout . trim ( )
265
+ newVersionStr = await findHighestNPMReactVersion ( defaultLatestChannel )
248
266
console . log (
249
267
`--version was not provided. Using react@${ defaultLatestChannel } : ${ newVersionStr } `
250
268
)
@@ -325,24 +343,28 @@ Or, run this command with no arguments to use the most recently published versio
325
343
)
326
344
}
327
345
328
- const syncPagesRouterReact = pagesRouterReact === null
329
- const pagesRouterReactVersion = syncPagesRouterReact
346
+ const syncPagesRouterReact = activePagesRouterReact === null
347
+ const newActivePagesRouterReactVersion = syncPagesRouterReact
330
348
? newVersionStr
331
- : pagesRouterReact
349
+ : activePagesRouterReact
350
+ const pagesRouterReactVersion = `^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ${ newActivePagesRouterReactVersion } `
351
+ const highestPagesRouterReactVersion = await findHighestNPMReactVersion (
352
+ pagesRouterReactVersion
353
+ )
332
354
const { sha : baseSha , dateString : baseDateString } = baseVersionInfo
333
355
334
356
if ( syncPagesRouterReact ) {
335
357
for ( const fileName of filesReferencingReactPeerDependencyVersion ) {
336
358
const filePath = path . join ( cwd , fileName )
337
359
const previousSource = await fsp . readFile ( filePath , 'utf-8' )
338
360
const updatedSource = previousSource . replace (
339
- ` const nextjsReactPeerVersion = "${ baseVersionStr } ";` ,
340
- `const nextjsReactPeerVersion = "${ pagesRouterReactVersion } ";`
361
+ / c o n s t n e x t j s R e a c t P e e r V e r s i o n = " [ ^ " ] + " ; / ,
362
+ `const nextjsReactPeerVersion = "${ highestPagesRouterReactVersion } ";`
341
363
)
342
- if ( pagesRouterReact === null && updatedSource === previousSource ) {
364
+ if ( activePagesRouterReact === null && updatedSource === previousSource ) {
343
365
errors . push (
344
366
new Error (
345
- `${ fileName } : Failed to update ${ baseVersionStr } to ${ pagesRouterReactVersion } . Is this file still referencing the React peer dependency version?`
367
+ `${ fileName } : Failed to update ${ baseVersionStr } to ${ highestPagesRouterReactVersion } . Is this file still referencing the React peer dependency version?`
346
368
)
347
369
)
348
370
} else {
@@ -356,10 +378,10 @@ Or, run this command with no arguments to use the most recently published versio
356
378
const packageJson = await fsp . readFile ( packageJsonPath , 'utf-8' )
357
379
const manifest = JSON . parse ( packageJson )
358
380
if ( manifest . dependencies [ 'react' ] ) {
359
- manifest . dependencies [ 'react' ] = pagesRouterReactVersion
381
+ manifest . dependencies [ 'react' ] = highestPagesRouterReactVersion
360
382
}
361
383
if ( manifest . dependencies [ 'react-dom' ] ) {
362
- manifest . dependencies [ 'react-dom' ] = pagesRouterReactVersion
384
+ manifest . dependencies [ 'react-dom' ] = highestPagesRouterReactVersion
363
385
}
364
386
await fsp . writeFile (
365
387
packageJsonPath ,
@@ -379,12 +401,10 @@ Or, run this command with no arguments to use the most recently published versio
379
401
const manifest = JSON . parse ( packageJson )
380
402
// Need to specify last supported RC version to avoid breaking changes.
381
403
if ( manifest . peerDependencies [ 'react' ] ) {
382
- manifest . peerDependencies [ 'react' ] =
383
- `^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ${ pagesRouterReactVersion } `
404
+ manifest . peerDependencies [ 'react' ] = pagesRouterReactVersion
384
405
}
385
406
if ( manifest . peerDependencies [ 'react-dom' ] ) {
386
- manifest . peerDependencies [ 'react-dom' ] =
387
- `^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ${ pagesRouterReactVersion } `
407
+ manifest . peerDependencies [ 'react-dom' ] = pagesRouterReactVersion
388
408
}
389
409
await fsp . writeFile (
390
410
packageJsonPath ,
0 commit comments