sanity-io / next-sanity

Sanity.io toolkit for Next.js

Home Page:https://www.sanity.io/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Unable to use embedded studio with static deployment `output: export`

espezaliate opened this issue · comments

Describe the bug

When trying to set up sanity with static next deployment you get the following error:

Error: Page "/(studio)/admin/[[...index]]/page" is missing exported function "generateStaticParams()", which is required with "output: export" config.

To Reproduce

Set the output to export in next config and try to access the studio

Expected behavior

Should be able to use sanity with static deployment

Which versions of Sanity are you using?

latest

Also I have followed all the instructions in readme and set the "use client" in Studio.tsx and export const dynamic = "force-static" in page.tsx

This problem occurs after upgrading from Next version above 13.4.19

i have the same problem. For my other dynamic page routings, I have to implement the generateStaticParams() function for those pages e.g. /products/1 where 1 is the id of the product in my inventory. However, when implementing this generateStaticParams function, you can no longer do "use client" at the top, which was set for app/studio/[[...index]]/page.tsx since it renders on the server side.

Ok I was able to resolve this issue. Looks like you cannot use output: export. A couple of things: 1) generateStaticParams is a server-side function, that's why you should not use "use client". It's called at build time to pre-render all your resource pages. This is called static site generation (SSG); 2) output: export is good if you only want SSG for your web app and don't expect it to update after the build; 3) if you want to have it update the pages from a backend server database, you should not use output: export. Just remove this line because by default next js is rendered at server side if not explicitly speicfied client side. In order to do that, we need to build the app as Server-side rendering. As for sanity studio, you should probably want to deploy the studio to the santiy cloud and decouple it from your project, or have studio run as a standalone app locally separate from the project.

With that said, I don't think this is a bug. But sanity can probably update the documentation to let developer know that caveat when embedding studio into the project. Happy building!

We haven't had time to properly end-to-end test the solution, but you should be able to get around the generateStaticParams and catchall limit by changing the underlying router.

You'll need the history package:

npm install --save-exact history@^5.3

So instead of hosting the studio on app/studio/[[...index]]/page.tsx you could use app/studio/page.tsx using these props (remember to put use client at the top of your sanity.config.ts file for this snippet to work):

import {
  createHashHistory,
  createMemoryHistory,
  type History,
  type Listener,
  type MemoryHistory,
} from 'history'
import { NextStudio } from 'next-sanity/studio'

import config from '../../sanity.config'

export const dynamic = 'error'

export { metadata, viewport } from 'next-sanity/studio'

// if 'hash' creates issues with newer Studio features such as `sanity/presentation`
// then change `type` to 'memory'
const type = 'hash'
const historyImplementation =
  type === 'hash'
    ? createHashHistory()
    : createMemoryHistory({
        initialEntries: ['/'],
      })
const history = {
  get action() {
    return historyImplementation.action
  },
  get index() {
    return type === 'hash' ? 0 : (historyImplementation as MemoryHistory).index
  },
  get location() {
    return historyImplementation.location
  },
  get createHref() {
    return historyImplementation.createHref
  },
  get push() {
    return type === 'hash' ? historyImplementation.replace : historyImplementation.push
  },
  get replace() {
    return historyImplementation.replace
  },
  get go() {
    return historyImplementation.go
  },
  get back() {
    return historyImplementation.back
  },
  get forward() {
    return historyImplementation.forward
  },
  get block() {
    return historyImplementation.block
  },
  // Overriding listen to workaround a problem where native history provides history.listen(location => void), but the npm package is history.listen(({action, location}) => void)
  listen(listener: Listener) {
    return historyImplementation.listen(({ action, location }) => {
      // console.debug('history.listen', action, location)
      // @ts-expect-error -- working around a bug? in studio
      listener(location)
    })
  },
}

export default function StudioPage() {
  return <NextStudio config={config} unstable_history={history} />
}

Thanks for taking the time to respond Cody. This will def help others who might come across the same problem. Cheers!

I'm new to NextJS and Sanity, just tasked with getting the infra up to deploy this - running into the same problem here that we get this error generating a static build to deploy. I'm going to try the solution @stipsan posted here, but just wanted to check that this is a different suggestion than made here: #471?

@rosshettel where did you deploy this? Are you using any server-side rendering or you just need to generate all your static content during build time? output: 'export' is not going to work if you need server-side rendering.

You might want to consider deploy sanity studio to sanity cloud and remove the studio from your project. I found sanity studio cloud works fairly well.

If not, (will be tedious), another way i tried was ignore studio stuff from the project and never push the content to git. But when I need studio stuff then i manually move the studio folder to my project and run it locally.

@AlfredChenPiano @rosshettel just published https://github.com/sanity-io/next-sanity/releases/tag/v8.5.0 which lets you use a route like /(studio)/admin/page by setting history="hash" on NextStudio 🙌