Facing an issue when integrating next js draft mode visual editing using @sanity/overlay as well as on the latest sanity/visual-editing package both through the below error on both npm I have also tried the latest versions
on production and on locally both it loads the page and then scroll a certain amount of page it throughs the error (index.mjs:11 Uncaught Error: Encoded data has invalid length)
It's related to node_modules @sanity/visual-editing
I have attached the screenshot below for reference
This config is used to set up Sanity Studio that's mounted on the /pages/studio/[[...index]].tsx route
*/
import { visionTool } from '@sanity/vision'
import { defineConfig } from 'sanity'
import { deskTool } from 'sanity/desk'
import { defineUrlResolver, Iframe } from 'sanity-plugin-iframe-pane'
import { previewUrl } from 'sanity-plugin-iframe-pane/preview-url'
// see https://www.sanity.io/docs/api-versioning for how versioning works
import {
apiVersion,
dataset,
previewSecretId,
projectId,
} from '~/lib/sanity.api'
import { PageTypes } from '~/lib/sanity.links'
import { schemaTypes } from '~/schemas'
import { structureResolver } from '~/schemas/desk'
import { presentationTool } from 'sanity/presentation'
import { locate } from '~/lib/presentation/locate'
import { getClient } from './src/lib/sanity.client'
import { groq } from 'next-sanity'
// Define the actions that should be available for singleton documents
const singletonActions = new Set(['publish', 'discardChanges', 'restore'])
// Define the singleton document types
const token = process.env.SANITY_API_READ_TOKEN
if (!token) {
throw new Error(
'A secret is provided but there is no SANITY_API_READ_TOKEN environment variable setup.',
)
}
export default async function preview(req, res) {
if (!token) {
res.status(500).send('Misconfigured server')
return
}
const { query } = req
if (!secret) {
res.status(401)
res.send('Invalid secret')
return
}
if (draft) {
res.status(200)
res.send(
'Draft mode documents that are not published do not have a preview available.',
)
return
}
if (reference) {
res.status(200)
res.send(
'The section has been published but has not been referenced on any page.',
)
return
}
res.setDraftMode({ enable: true })
res.writeHead(307, {
Location: location,
})
res.end()
return
}
presentation draft is look like this // ./src/pages/api/draft.ts
import { validatePreviewUrl } from '@sanity/preview-url-secret'
import { createClient } from 'next-sanity'
Facing an issue when integrating next js draft mode visual editing using @sanity/overlay as well as on the latest sanity/visual-editing package both through the below error on both npm I have also tried the latest versions on production and on locally both it loads the page and then scroll a certain amount of page it throughs the error (index.mjs:11 Uncaught Error: Encoded data has invalid length) It's related to node_modules @sanity/visual-editing I have attached the screenshot below for reference
Its my packages json file
"@headlessui/react": "^1.7.18", "@phosphor-icons/react": "^2.0.14", "@portabletext/react": "3.0.4", "@sanity/client": "^6.10.0", "@sanity/demo": "^1.0.2", "@sanity/overlays": "^2.3.14", "@sanity/presentation": "1.2.0", "@sanity/react-loader": "^1.6.4", "@sanity/ui": "^2.0.1", "@sanity/vision": "^3.25.0", "@sanity/visual-editing": "^1.2.2", "@tailwindcss/typography": "0.5.9", "classnames": "^2.3.2", "framer-motion": "^10.16.4", "gsap": "^3.12.4", "js-search": "^2.0.1", "matter-js": "^0.19.0", "next": "13.4.8", "next-sanity": "^5.5.4", "poly-decomp": "^0.3.0", "react": "18.2.0", "react-dom": "18.2.0", "react-media-hook": "^0.5.0", "react-player": "^2.14.1", "react-share": "^5.0.3", "react-slick": "^0.29.0", "react-stars": "^2.2.5", "react-toastify": "^10.0.4", "reading-time": "^1.5.0", "sanity": "3.21.3", "sanity-plugin-iframe-pane": "2.5.5", "styled-components": "5.3.11", "swr": "^2.2.4", "usehooks-ts": "^2.9.1"
/pages/studio/[[...index]].tsx
route */ import { visionTool } from '@sanity/vision' import { defineConfig } from 'sanity' import { deskTool } from 'sanity/desk' import { defineUrlResolver, Iframe } from 'sanity-plugin-iframe-pane' import { previewUrl } from 'sanity-plugin-iframe-pane/preview-url'// see https://www.sanity.io/docs/api-versioning for how versioning works import { apiVersion, dataset, previewSecretId, projectId, } from '~/lib/sanity.api' import { PageTypes } from '~/lib/sanity.links' import { schemaTypes } from '~/schemas' import { structureResolver } from '~/schemas/desk' import { presentationTool } from 'sanity/presentation' import { locate } from '~/lib/presentation/locate' import { getClient } from './src/lib/sanity.client' import { groq } from 'next-sanity' // Define the actions that should be available for singleton documents const singletonActions = new Set(['publish', 'discardChanges', 'restore']) // Define the singleton document types
const requiresSlug = [PageTypes['Page'], PageTypes['Post']] const iframeOptions = { url: defineUrlResolver({ base: '/api/draft', requiresSlug, }), urlSecretId: previewSecretId, reload: { button: true }, }
export const previewView = (S) => S.view.component(Iframe).options(iframeOptions).title('Preview')
async function getPreviewUrl(doc) { const { slug: { current = '' } = {}, _id: docId, _type: docType, } = (await doc) || {} if (docId?.startsWith('drafts') && !current) { return
${window.location.origin}/api/draft?type=page&slug=/&secret=${process.env.SANITY_API_READ_TOKEN}&draft=true
} else if (current) { return${window.location.origin}/api/draft?type=${docType}&slug=${current}&secret=${process.env.SANITY_API_READ_TOKEN}
} else { const query = groq*[_type == "page" && references(*[_type == '${docType}' && _id == '${docId}']._id)][0] { _id, "slug": slug.current, _type }
const client = getClient() const childDoc = await client.fetch(query) if (childDoc) { const { _type: childDocType, slug: childDocSlug } = childDoc const url =${window.location.origin}/api/draft?type=${childDocType}&slug=${childDocSlug}&secret=${process.env.SANITY_API_READ_TOKEN}§ionId=${docId}
return url } else { const url =${window.location.origin}/api/draft?type=page&mode=draft&slug=/&secret=${process.env.SANITY_API_READ_TOKEN}&reference=not
return url } } }export const defaultDocumentNode = (S) => { return S.document().views([ S.view.form(), S.view .component(Iframe) .options({ url: (doc) => getPreviewUrl(doc), }) .title('Preview'), ]) }
export default defineConfig({ basePath: '/studio', name: 'wise-digital-partners', title: 'Wise Digital Partners', projectId, dataset, //edit schemas in './src/schemas' schema: { types: schemaTypes, // Filter out singleton types from the global “New document” menu options // templates: (templates) => // templates.filter(({ schemaType }) => !singletonTypes.has(schemaType)), }, plugins: [ deskTool({ structure: structureResolver, defaultDocumentNode, }), // Add the "Open preview" action previewUrl({ base: '/api/draft', requiresSlug, urlSecretId: previewSecretId, }), // Vision lets you query your content with GROQ in the studio // https://www.sanity.io/docs/the-vision-plugin visionTool({ defaultApiVersion: apiVersion }), presentationTool({ locate, previewUrl: { draftMode: { enable: '/api/presentation-draft', disable: '/api/disable-draft', }, }, }), ], })
_app.js is look like this
import '~/styles/global.scss'import { VisualEditing } from '@sanity/visual-editing/next-pages-router' import { useRouter } from 'next/router' import { lazy, Suspense, useEffect, useState } from 'react'
import { hideBodyScroll, showBodyScroll } from '~/utils/helpers'
import Layout from '../components/layout' import SEO from '../components/seo'
const PreviewProvider = lazy(() => import('~/components/PreviewProvider')) // const VisualEditing = lazy(() => import("~/components/VisualEditing"));
export default function App({ Component, pageProps }) { const { draftMode, token, transparentNav, seo } = pageProps const router = useRouter() const pageKey = router.asPath const [toggle, setToggle] = useState('')
const toggleFunc = (flag) => { setToggle(flag) } // useEffect(() => { // if (toggle) { // hideBodyScroll(); // } else { // showBodyScroll(); // } // }, [toggle]); const enableLayout = !pageKey?.split('/')?.includes('studio')
return enableLayout ? ( <Layout toggle={toggle} toggleFunc={toggleFunc} transparentNav={transparentNav}
`import { groq } from 'next-sanity' import { useLiveQuery } from 'next-sanity/preview'
import { fragment as modulesFragment } from '~/components/module-renderer' import ModuleRenderer from '~/components/module-renderer' import { readToken } from '~/lib/sanity.api' import { getClient } from '~/lib/sanity.client' export const getPageQuery = (slug) => groq
{ "page": *[_type == "page" && slug.current == '${slug}'] { _type, "title": title, "slug": slug.current, ..., transparentNav, modules[] { ..., ${modulesFragment} } } }
function Page(props) { const { draftMode, page: { id = '' } = {} } = props || {} const pageQuery = (slug) => groq
*[_type == "page" && slug.current == '${slug}'][0] { _type, "title": title, "slug": slug.current, ..., transparentNav, modules[] { ..., ${modulesFragment} } }
switch (props.page?._type) { case 'page': // eslint-disable-next-line react-hooks/exhaustive-deps const [page] = useLiveQuery(props.page, pageQuery(props.slug))
} }
export async function getStaticPaths() { const client = getClient() // const [ // slugs1, // slugs2, // slugs3, // slugs4, // slugs5, // slugs6, // slugs7, // slugs8, // slugs9, // ] = await client.fetch( // groq
[ // *[_type == "page"] { // "title": title, // "slug": slug.current // }, // *[_type == "press"] { // "title": title, // "slug": slug.current // }, // *[_type == "position"] { // "title": title, // "slug": slug.current // }, // *[_type == "teamProfile"] { // "title": name, // "slug": slug.current // }, // *[_type == "technologyPages"] { // "title": name, // "slug": slug.current // }, // *[_type == "services"] { // "title": name, // "slug": slug.current // }, // *[_type == "industryPages"] { // "title": title, // "slug": slug.current // }, // *[_type == "subServices"] { // "title": title, // "slug": slug.current // }, // *[_type == "subIndustryPages"] { // "title": title, // "slug": slug.current // } // ]
, // )// const allSlugs = [ // ...slugs1, // ...slugs2, // ...slugs3, // ...slugs4, // ...slugs5, // ...slugs6, // ...slugs7, // ...slugs8, // ...slugs9, // ]
return { paths: ['/'], // allSlugs?.map(({ slug }) => (slug !== '/' ?
/${slug}
:${slug}
)) || // [], fallback: false, } }export const getStaticProps = async ({ draftMode = false, params }) => { let slug = '/' if (Object.keys(params || {}).length) { const { slug: currentSlug } = params slug = currentSlug?.join('/') }
const client = getClient(draftMode ? readToken : undefined) if (!slug) throw new Error('No slug provided') const pageQuery = getPageQuery(slug)
const { page } = await client.fetch(pageQuery) const pageData = [...page] return { props: { draftMode, token: draftMode ? readToken : '', page: pageData[0], transparentNav: pageData[0]?.transparentNav || false, seo: { seoTitle: pageData[0]?.seoTitle, metaDescription: pageData[0]?.metaDescription, }, slug, }, revalidate: 10, } }
export default Page ` disable end point
`import { resolveHref } from '~/lib/sanity.links'
const token = process.env.SANITY_API_READ_TOKEN if (!token) { throw new Error( 'A secret is provided but there is no
SANITY_API_READ_TOKEN
environment variable setup.', ) }export default async function preview(req, res) { if (!token) { res.status(500).send('Misconfigured server') return } const { query } = req
const secret = typeof query.secret === 'string' ? query.secret : undefined const slug = typeof query.slug === 'string' ? query.slug : undefined const type = typeof query.type === 'string' ? query.type : undefined const draft = query.draft ? query.draft : undefined const reference = query.reference ? query.reference : undefined const sectionId = query.sectionId ? query.sectionId : undefined const location = type ? resolveHref(type, slug, sectionId) : '/'
if (!secret) { res.status(401) res.send('Invalid secret') return } if (draft) { res.status(200) res.send( 'Draft mode documents that are not published do not have a preview available.', ) return } if (reference) { res.status(200) res.send( 'The section has been published but has not been referenced on any page.', ) return } res.setDraftMode({ enable: true }) res.writeHead(307, { Location: location, }) res.end() return }
presentation draft is look like this
// ./src/pages/api/draft.tsimport { validatePreviewUrl } from '@sanity/preview-url-secret' import { createClient } from 'next-sanity'
const client = createClient({ projectId: process.env.NEXT_PUBLIC_SANITY_PROJECT_ID, dataset: process.env.NEXT_PUBLIC_SANITY_DATASET, apiVersion: process.env.NEXT_PUBLIC_SANITY_API_VERSION, useCdn: false, token: process.env.SANITY_API_READ_TOKEN, })
export default async function handle(req, res) { if (!req.url) { throw new Error('Missing url') }
const { isValid, redirectTo = '/' } = await validatePreviewUrl( client, req.url, ) if (!isValid) { return res.status(401).send('Invalid secret') } // Enable Draft Mode by setting the cookies res.setDraftMode({ enable: true }) res.writeHead(307, { Location: redirectTo }) res.end() } ` locate is look like this
any feedback regarding this is appreciated