Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: upgrade sanity init for Next.js to next-sanity v9 #6644

Merged
merged 2 commits into from
May 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 8 additions & 14 deletions packages/@sanity/cli/src/actions/init-project/initProject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ import {tryGitInit} from './git'
import {promptForDatasetName} from './promptForDatasetName'
import {promptForAclMode, promptForDefaultConfig, promptForTypeScript} from './prompts'
import {
promptForAppDir,
promptForAppendEnv,
promptForEmbeddedStudio,
promptForNextTemplate,
Expand All @@ -60,8 +59,7 @@ import {
sanityCliTemplate,
sanityConfigTemplate,
sanityFolder,
sanityStudioAppTemplate,
sanityStudioPagesTemplate,
sanityStudioTemplate,
} from './templates/nextjs'

// eslint-disable-next-line no-process-env
Expand Down Expand Up @@ -330,12 +328,8 @@ export default async function initSanity(
const embeddedStudio = unattended ? true : await promptForEmbeddedStudio(prompt)

if (embeddedStudio) {
// this one is trickier on unattended, as we should probably scan for which one
// they're using, but they can also use both
const useAppDir = unattended ? false : await promptForAppDir(prompt)

// find source path (app or pages dir)
const srcDir = useAppDir ? 'app' : 'pages'
// find source path (app or src/app)
const srcDir = 'app'
let srcPath = path.join(workDir, srcDir)

if (!existsSync(srcPath)) {
Expand All @@ -352,7 +346,7 @@ export default async function initSanity(
const embeddedStudioRouteFilePath = path.join(
srcPath,
`${studioPath}/`,
useAppDir ? `[[...index]]/page.${fileExtension}x` : `[[...index]].${fileExtension}x`,
`[[...tool]]/page.${fileExtension}x`,
)

// this selects the correct template string based on whether the user is using the app or pages directory and
Expand All @@ -361,7 +355,7 @@ export default async function initSanity(
// relative paths to reach the root level of the project
await writeOrOverwrite(
embeddedStudioRouteFilePath,
(useAppDir ? sanityStudioAppTemplate : sanityStudioPagesTemplate).replace(
sanityStudioTemplate.replace(
':configPath:',
new Array(countNestedFolders(embeddedStudioRouteFilePath.slice(workDir.length)))
.join('../')
Expand Down Expand Up @@ -451,11 +445,11 @@ export default async function initSanity(
}

if (chosen === 'npm') {
await execa('npm', ['install', 'next-sanity@7'], execOptions)
await execa('npm', ['install', 'next-sanity@9'], execOptions)
} else if (chosen === 'yarn') {
await execa('npx', ['install-peerdeps', '--yarn', 'next-sanity@7'], execOptions)
await execa('npx', ['install-peerdeps', '--yarn', 'next-sanity@9'], execOptions)
} else if (chosen === 'pnpm') {
await execa('pnpm', ['install', 'next-sanity@7'], execOptions)
await execa('pnpm', ['install', 'next-sanity@9'], execOptions)
}

print(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,6 @@ export function promptForEmbeddedStudio(prompt: CliPrompter): Promise<string> {
})
}

export function promptForAppDir(prompt: CliPrompter): Promise<string> {
return prompt.single({
type: 'confirm',
message: `Would you like to use the Next.js app directory for routes?`,
default: false,
})
}

export function promptForStudioPath(prompt: CliPrompter): Promise<string> {
return prompt.single({
type: 'input',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import {blogSchemaFolder, blogSchemaJS, blogSchemaTS} from './schemaTypes/blog'

export const sanityConfigTemplate = `/**
export const sanityConfigTemplate = `'use client'
/**
* This configuration is used to for the Sanity Studio that’s mounted on the \`:route:\` route
*/
Expand Down Expand Up @@ -39,27 +41,7 @@ const dataset = process.env.NEXT_PUBLIC_SANITY_DATASET
export default defineCliConfig({ api: { projectId, dataset } })
`

export const sanityStudioPagesTemplate = `import Head from 'next/head'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you are changing the name of one exported const and deleting two others. I'm assuming this is intended but just wanted to call this out to make sure.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, that's correct.
The name sanityStudioPagesTemplate allude to the format used to mount the studio in pages/studio/[[...tool]].tsx paths, which is handled by the Next.js Pages Router: https://nextjs.org/docs/pages/building-your-application/routing/pages-and-layouts

next-sanity v9 only supports App Router routes app/studio/[[...tool]]/page.tsx mount points: https://nextjs.org/docs/app/building-your-application/routing/defining-routes

Due to the two routes starting to diverge too much in how they handle meta data tags, and other APIs, we decided to stop supporting Pages Router and started to simplify the API surface and docs.
As a result sanityStudioPagesTemplate is no longer needed and produces invalid code.

For example this export no longer exists:

import { metadata } from 'next-sanity/studio/metadata'

And since there are no longer a need to maintain two templates it no longer makes sense to specify AppTemplate in the name :)

import { NextStudio } from 'next-sanity/studio'
import { metadata } from 'next-sanity/studio/metadata'
import config from ':configPath:'
export default function StudioPage() {
return (
<>
<Head>
{Object.entries(metadata).map(([key, value]) => (
<meta key={key} name={key} content={value} />
))}
</Head>
<NextStudio config={config} />
</>
)
}`

export const sanityStudioAppTemplate = `'use client'
/**
export const sanityStudioTemplate = `/**
* This route is responsible for the built-in authoring environment using Sanity Studio.
* All routes under your studio path is handled by this file using Next.js' catch-all routes:
* https://nextjs.org/docs/routing/dynamic-routes#catch-all-routes
Expand All @@ -71,12 +53,14 @@ export const sanityStudioAppTemplate = `'use client'
import { NextStudio } from 'next-sanity/studio'
import config from ':configPath:'
export const dynamic = 'force-static'
export { metadata, viewport } from 'next-sanity/studio'
export default function StudioPage() {
return <NextStudio config={config} />
}`

export const sanityStudioAppLayoutTemplate = `export {metadata} from 'next-sanity/studio'`

// Format today's date like YYYY-MM-DD
const envTS = `export const apiVersion =
process.env.NEXT_PUBLIC_SANITY_API_VERSION || '${new Date().toISOString().split('T')[0]}'
Expand Down Expand Up @@ -127,10 +111,11 @@ const client = `import { createClient } from 'next-sanity'
import { apiVersion, dataset, projectId, useCdn } from '../env'
export const client = createClient({
apiVersion,
dataset,
projectId,
dataset,
apiVersion,
useCdn,
perspective: 'published',
})
`

Expand Down
Loading