From 4e2206f8ed57e9af5986e94ef8896e94db15556b Mon Sep 17 00:00:00 2001 From: pedrobonamin Date: Wed, 23 Oct 2024 17:45:57 +0200 Subject: [PATCH 1/6] feat(cli): add warning and docs for react-19 and Next.Js combination --- .../src/actions/init-project/initProject.ts | 22 +++++++++++++++++++ .../actions/init-project/readPackageJson.ts | 18 +++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 packages/@sanity/cli/src/actions/init-project/readPackageJson.ts diff --git a/packages/@sanity/cli/src/actions/init-project/initProject.ts b/packages/@sanity/cli/src/actions/init-project/initProject.ts index dac97466649..5b0d521c8ce 100644 --- a/packages/@sanity/cli/src/actions/init-project/initProject.ts +++ b/packages/@sanity/cli/src/actions/init-project/initProject.ts @@ -9,6 +9,7 @@ import execa, {type CommonOptions} from 'execa' import {deburr, noop} from 'lodash' import pFilter from 'p-filter' import resolveFrom from 'resolve-from' +import semver from 'semver' import {evaluate, patch} from 'silver-fleece' import which from 'which' @@ -55,6 +56,7 @@ import { promptForNextTemplate, promptForStudioPath, } from './prompts/nextjs' +import {readPackageJson} from './readPackageJson' import {reconfigureV2Project} from './reconfigureV2Project' import templates from './templates' import { @@ -128,6 +130,8 @@ export default async function initSanity( const cliFlags = args.extOptions const unattended = cliFlags.y || cliFlags.yes const print = unattended ? noop : output.print + const warn = (msg: string) => output.warn(chalk.yellow.bgBlack(msg)) + const intendedPlan = cliFlags['project-plan'] const intendedCoupon = cliFlags.coupon const reconfigure = cliFlags.reconfigure @@ -327,6 +331,24 @@ export default async function initSanity( // Ensure we are using the output path provided by user outputPath = answers.outputPath + const packageJson = readPackageJson(`${outputPath}/package.json`) + const reactVersion = packageJson.dependencies?.react + const isUsingReact19 = semver.coerce(reactVersion)?.major === 19 + if ( + detectedFramework?.slug === 'nextjs' && + // @ts-expect-error - Detected version is not typed into Framework interface + detectedFramework?.detectedVersion?.startsWith('15') && + isUsingReact19 + ) { + warn('╭────────────────────────────────────────────────────────────╮') + warn('│ │') + warn('│ It looks like you are using Next.js 15 and React 19 │') + warn('│ Please read our compatibility guide. │') + warn('│ https://www.sanity.io/help/react-19 │') + warn('│ │') + warn('╰────────────────────────────────────────────────────────────╯') + } + if (initNext) { const useTypeScript = unattended ? true : await promptForTypeScript(prompt) trace.log({step: 'useTypeScript', selectedOption: useTypeScript ? 'yes' : 'no'}) diff --git a/packages/@sanity/cli/src/actions/init-project/readPackageJson.ts b/packages/@sanity/cli/src/actions/init-project/readPackageJson.ts new file mode 100644 index 00000000000..ac9e9283ccf --- /dev/null +++ b/packages/@sanity/cli/src/actions/init-project/readPackageJson.ts @@ -0,0 +1,18 @@ +import fs from 'node:fs' + +import {type PackageJson} from '@sanity/cli' + +/** + * Read the `package.json` file at the given path + * + * @param filePath - Path to package.json to read + * @returns The parsed package.json + */ +export function readPackageJson(filePath: string): PackageJson { + try { + // eslint-disable-next-line no-sync + return JSON.parse(fs.readFileSync(filePath, 'utf8')) + } catch (err) { + throw new Error(`Failed to read "${filePath}": ${err.message}`) + } +} From 5a5a7e42211ce346d466d130ac040f02b77b0cb7 Mon Sep 17 00:00:00 2001 From: Ash Date: Wed, 23 Oct 2024 16:57:25 +0100 Subject: [PATCH 2/6] fix(cli): `detectedFramework` CLI context type --- .../@sanity/cli/src/actions/init-project/initProject.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/@sanity/cli/src/actions/init-project/initProject.ts b/packages/@sanity/cli/src/actions/init-project/initProject.ts index 5b0d521c8ce..31bc2b92503 100644 --- a/packages/@sanity/cli/src/actions/init-project/initProject.ts +++ b/packages/@sanity/cli/src/actions/init-project/initProject.ts @@ -4,6 +4,7 @@ import path from 'node:path' import {type DatasetAclMode, type SanityProject} from '@sanity/client' import {type Framework} from '@vercel/frameworks' +import {type detectFrameworkRecord} from '@vercel/fs-detectors' import dotenv from 'dotenv' import execa, {type CommonOptions} from 'execa' import {deburr, noop} from 'lodash' @@ -112,7 +113,9 @@ export interface ProjectOrganization { // eslint-disable-next-line max-statements, complexity export default async function initSanity( args: CliCommandArguments, - context: CliCommandContext & {detectedFramework: Framework | null}, + context: CliCommandContext & { + detectedFramework: Awaited> + }, ): Promise { const { output, @@ -336,7 +339,6 @@ export default async function initSanity( const isUsingReact19 = semver.coerce(reactVersion)?.major === 19 if ( detectedFramework?.slug === 'nextjs' && - // @ts-expect-error - Detected version is not typed into Framework interface detectedFramework?.detectedVersion?.startsWith('15') && isUsingReact19 ) { From 3a472bfbdb414ef8c2cd1cd0b3820af6d55d9c84 Mon Sep 17 00:00:00 2001 From: pedrobonamin Date: Wed, 23 Oct 2024 17:58:58 +0200 Subject: [PATCH 3/6] fix(cli): use semver to detect nextjs version --- .../@sanity/cli/src/actions/init-project/initProject.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/@sanity/cli/src/actions/init-project/initProject.ts b/packages/@sanity/cli/src/actions/init-project/initProject.ts index 31bc2b92503..edb157388b9 100644 --- a/packages/@sanity/cli/src/actions/init-project/initProject.ts +++ b/packages/@sanity/cli/src/actions/init-project/initProject.ts @@ -337,11 +337,11 @@ export default async function initSanity( const packageJson = readPackageJson(`${outputPath}/package.json`) const reactVersion = packageJson.dependencies?.react const isUsingReact19 = semver.coerce(reactVersion)?.major === 19 - if ( + const isUsingNextJs15 = detectedFramework?.slug === 'nextjs' && - detectedFramework?.detectedVersion?.startsWith('15') && - isUsingReact19 - ) { + semver.coerce(detectedFramework?.detectedVersion)?.major === 15 + + if (isUsingNextJs15 && isUsingReact19) { warn('╭────────────────────────────────────────────────────────────╮') warn('│ │') warn('│ It looks like you are using Next.js 15 and React 19 │') From 9cb9e16669032f862b8cd3bdaf2cdf09e4428445 Mon Sep 17 00:00:00 2001 From: pedrobonamin Date: Wed, 23 Oct 2024 18:10:36 +0200 Subject: [PATCH 4/6] fix(cli): change import path for readPackageJson --- .../@sanity/cli/src/actions/init-project/readPackageJson.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@sanity/cli/src/actions/init-project/readPackageJson.ts b/packages/@sanity/cli/src/actions/init-project/readPackageJson.ts index ac9e9283ccf..4d6ad1a63bc 100644 --- a/packages/@sanity/cli/src/actions/init-project/readPackageJson.ts +++ b/packages/@sanity/cli/src/actions/init-project/readPackageJson.ts @@ -1,6 +1,6 @@ import fs from 'node:fs' -import {type PackageJson} from '@sanity/cli' +import {type PackageJson} from '../../types' /** * Read the `package.json` file at the given path From fb61699652a9f589fad14bb8884288b3feef805f Mon Sep 17 00:00:00 2001 From: pedrobonamin Date: Wed, 23 Oct 2024 18:23:50 +0200 Subject: [PATCH 5/6] fix(cli): do not throw error when reading package.json --- .../src/actions/init-project/initProject.ts | 37 +++++++++++-------- .../actions/init-project/readPackageJson.ts | 4 +- 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/packages/@sanity/cli/src/actions/init-project/initProject.ts b/packages/@sanity/cli/src/actions/init-project/initProject.ts index edb157388b9..40257fa8fde 100644 --- a/packages/@sanity/cli/src/actions/init-project/initProject.ts +++ b/packages/@sanity/cli/src/actions/init-project/initProject.ts @@ -305,7 +305,8 @@ export default async function initSanity( } let initNext = false - if (detectedFramework?.slug === 'nextjs') { + const isNextJs = detectedFramework?.slug === 'nextjs' + if (isNextJs) { initNext = await prompt.single({ type: 'confirm', message: @@ -334,21 +335,25 @@ export default async function initSanity( // Ensure we are using the output path provided by user outputPath = answers.outputPath - const packageJson = readPackageJson(`${outputPath}/package.json`) - const reactVersion = packageJson.dependencies?.react - const isUsingReact19 = semver.coerce(reactVersion)?.major === 19 - const isUsingNextJs15 = - detectedFramework?.slug === 'nextjs' && - semver.coerce(detectedFramework?.detectedVersion)?.major === 15 - - if (isUsingNextJs15 && isUsingReact19) { - warn('╭────────────────────────────────────────────────────────────╮') - warn('│ │') - warn('│ It looks like you are using Next.js 15 and React 19 │') - warn('│ Please read our compatibility guide. │') - warn('│ https://www.sanity.io/help/react-19 │') - warn('│ │') - warn('╰────────────────────────────────────────────────────────────╯') + if (isNextJs) { + const packageJson = readPackageJson(`${outputPath}/package.json`) + const reactVersion = packageJson?.dependencies?.react + + if (reactVersion) { + const isUsingReact19 = semver.coerce(reactVersion)?.major === 19 + const isUsingNextJs15 = + isNextJs && semver.coerce(detectedFramework?.detectedVersion)?.major === 15 + + if (isUsingNextJs15 && isUsingReact19) { + warn('╭────────────────────────────────────────────────────────────╮') + warn('│ │') + warn('│ It looks like you are using Next.js 15 and React 19 │') + warn('│ Please read our compatibility guide. │') + warn('│ https://www.sanity.io/help/react-19 │') + warn('│ │') + warn('╰────────────────────────────────────────────────────────────╯') + } + } } if (initNext) { diff --git a/packages/@sanity/cli/src/actions/init-project/readPackageJson.ts b/packages/@sanity/cli/src/actions/init-project/readPackageJson.ts index 4d6ad1a63bc..ed638458a67 100644 --- a/packages/@sanity/cli/src/actions/init-project/readPackageJson.ts +++ b/packages/@sanity/cli/src/actions/init-project/readPackageJson.ts @@ -8,11 +8,11 @@ import {type PackageJson} from '../../types' * @param filePath - Path to package.json to read * @returns The parsed package.json */ -export function readPackageJson(filePath: string): PackageJson { +export function readPackageJson(filePath: string): PackageJson | undefined { try { // eslint-disable-next-line no-sync return JSON.parse(fs.readFileSync(filePath, 'utf8')) } catch (err) { - throw new Error(`Failed to read "${filePath}": ${err.message}`) + return undefined } } From 686aba1073bb752d06f45c8fe80d2c43c535b5f6 Mon Sep 17 00:00:00 2001 From: Pedro Bonamin <46196328+pedrobonamin@users.noreply.github.com> Date: Wed, 23 Oct 2024 19:40:29 +0200 Subject: [PATCH 6/6] fix(cli): update isUsingNextJs15 check Co-authored-by: Espen Hovlandsdal --- packages/@sanity/cli/src/actions/init-project/initProject.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/@sanity/cli/src/actions/init-project/initProject.ts b/packages/@sanity/cli/src/actions/init-project/initProject.ts index 40257fa8fde..691a327039d 100644 --- a/packages/@sanity/cli/src/actions/init-project/initProject.ts +++ b/packages/@sanity/cli/src/actions/init-project/initProject.ts @@ -341,8 +341,7 @@ export default async function initSanity( if (reactVersion) { const isUsingReact19 = semver.coerce(reactVersion)?.major === 19 - const isUsingNextJs15 = - isNextJs && semver.coerce(detectedFramework?.detectedVersion)?.major === 15 + const isUsingNextJs15 = semver.coerce(detectedFramework?.detectedVersion)?.major === 15 if (isUsingNextJs15 && isUsingReact19) { warn('╭────────────────────────────────────────────────────────────╮')