next-sanity
next-sanity copied to clipboard
Documentation proposal: Remove unecessary context.preview from getStaticProps code example
In the README.md it says:
export async function getStaticProps({params, preview = false}) {}
The README.md mentions that NextJS preview-mode can be used. But I would argue that it's confusing to include this context.preview
variable in the example because it will never be true unless the user sets up the necessary API endpoint.
It really seems like Sanity does not need NextJS's preview mode because it checks to see if the user is logged into Sanity, and relies on that login session to fetch preview data.
So, I propose:
- Removing unused example code related to NextJS's preview mode.
- Expand the documentation to emphasise the difference between this way of previewing vs. NextJS's preview mode.
- Optionally create a separate NextJS preview mode example, and explain when one should consider using it. If there's no need to use it the docs should be explicit about that.
Finally, I'd like to say thanks for building a great product. That's why I took the time to write this up because I think this issue might be a step towards making Sanity previews easier to implement.
Great suggestion, I was quite confused by this as well, and people have already started to copy my confusing code 😅
Maybe also remove the entire getClient/previewClient part as well as it's adding to the confusion and not really necessary for the usePreviewSubscription approach..?
@nilsnh can we write a better documentation example as a proposal? I'm so confused by the example that is given.
Is there any update on this one? I'm a bit confused about the example given and how it links with the preview mode in nextjs.
Hey, just wanted to shed some light here, as much for others as for myself, as I've just grasped this concept.
Actually the two different approaches stem from the different ways in which the next-sanity
client and the @sanity/client
handle authenticating the user:
TL;DR:
With next-sanity
export async function getStaticProps({params, preview = false}) {}
is only indeed needed if you want to _toggle the preview mode on and off.
But for @sanity/client
, besides preview
you actually need to use setPreviewData
inside the preview API route, to send the Sanity Token, then grab it like this: getStaticProps(params, preview = false, previewData})
Detailed explanations below:
At first I didn't understand the purpose behind the whole next-sanity
package, it seemed simple enough just to use @sanity/client
directly in Next.js. But look at the two approaches below and the advantages become clear:
using @sanity/client
aka "the hard way"
- all requests made via
sanityClient(options).fetch...etc
are NOT authenticated by default. They can only read public data, and can't access draft documents for previews - to get access to drafts, you need to provide a token inside of the
options
object, which is a read token that you need to manually create in the Sanity admin back-end and add as an environment variable inside of next. - the env variable needs to be private, not public otherwise you will expose your token. so something like
SANITY_API_TOKEN
rather thanNEXT_PUBLIC_SANITY_API_TOKEN
- but private environment vars are not accessible to client-side, where you make your preview queries (that's the whole point) so you can only access
SANITY_API_TOKEN
server-side, which is to say, inside of API routes you create in the/pages/api
folder, since they run code on the server, not the client. - but this means that, for previews, you actually need to pass the
SANITY_API_TOKEN
via the API route code you write - most likely like this:
// /pages/api/preview.js
...
res.setPreviewData(
{ token: process.env.SANITY_API_TOKEN },
{
maxAge: 20, // this is optional, to control the amount of time you set the preview mode active for, per request made to `/api/preview`, or whatever you named your preview API route
}
);
...
- then, inside of a page (overly simplified example, would need refactoring for actual use:
// /lib/sanity.js - or wherever you choose to put this
import createSanityClient from '@sanity/client'
const options = {
<project ID, dataset, API version, etc>
}
export const sanityClient = createSanityClient(options)
export function createPreviewClient(token) {
return createSanityClient({
...options,
useCdn: false,
token,
})
}
export function getSanityClient(preview) {
if (preview?.active) {
return createPreviewClient(preview.token)
} else {
return sanityClient
}
}
// /pages/index.js
import {getSanityClient} from "lib/sanity"
getStaticProps(params, preview = false, previewData}) {
const previewInfo = {
active: preview,
token: previewData?.token
}
const pageData = getSanityClient(previewInfo).fetch(<your query here>)
...etc
}
using next-sanity
, aka "the easy way"
- the authentication check is done automatically behind the scenes with getCurrentUser()
-
next-sanity
's client checks to see if the user is logged into the sanity instance - if they are logged in, then **ALL REQUESTS made via a client created with the
createClient()
method of thenext-sanity
package will be authenticated, same as having a token priovided via the method above. - You don't need to bother with passing the SANITY_API_TOKEN env. variable, at all. It's not needed.
- simply:
import { createClient } from "next-sanity";
import sanityClientConfig from "lib/sanity-config.js"
getStaticProps(params, preview = false}) { // no more "previewData" needed
// one line does it all, we just need to turn off the CDN for preview
const pageData = getSanityClient(...sanityClientConfig, useCdn: !preview).fetch(<your query here>)
...etc
}
This way, logged in users always get the preview data, if your (query is set up to prioritize fetching drafts, that is). You could improve this to allow logged in users to ignore preview data and see only the published data, if that's needed, somehow.
Hi all,
Just pinging this thread to let you know we're working on updating tooling and new documentation regarding preview mode. You can keep an eye on it here.
And just to clear a few things up:
- At first the preview mode in Next.js were only used by us to switch statically generated pages into an "SSR"-like mode where fresh draft data and drafts are fetched.
- It fixed the wonky behavior where you would see old content while the page is loading, then a lot of jank as the drafts loads in once JS is done booting up.
- Now it's evolved to be more important as browsers like Safari no longer work with this mode as it relies on cookies that use a different origin than the page you're on and the
res.setPreviewData({token})
is now vital for Preview Mode to work outside of Chrome. This PR implements a flow like that to enable Safari to run Preview Mode..
Forgot to mention we've updated the cms-sanity
example over at Vercel with more information and an easier setup for Preview Mode that can hopefully help make it easier to grasp while we work on the new docs 😄
We've just released v2.0.0
which has updated docs that outline how to do things the "easy way" ™ as well as how to provide a viewer token in a secure way. Checkout @sanity/preview-kit
for more docs on how to build realtime previews outside of Nextjs' Preview Mode.