NextJS部署Vercel后Storyblok预览功能异常求助
NextJS + Storyblok 部署Vercel后预览失效问题排查
问题现象
- 本地开发时功能正常,部署到Vercel后Storyblok预览功能失效:仅在发布Storyblok内容触发Vercel全量重新部署后,修改才生效
- 在Storyblok中移动区块后点击保存,内容会自动恢复原状
- 浏览器使用Storyblok时出现Storefront错误,推测与Shopify API相关;环境变量配置无误,本地调试无异常,Vercel日志未发现问题
相关代码
Storefront函数代码
//Assigning Storefront access token and the shop URL const storefrontAccessToken: any = process.env.NEXT_PUBLIC_SHOPIFY_STOREFRONT_ACCESS_TOKEN; const storeURL: any = process.env.NEXT_PUBLIC_SHOPIFY_STORE_DOMAIN; export async function storefront(query: any, variables = {}) { try { const response = await fetch(storeURL, { method: "POST", headers: { "Content-Type": "application/json", "X-Shopify-Storefront-Access-Token": storefrontAccessToken, }, body: JSON.stringify({ query, variables }), }); const JSONResponse = await response.json(); return JSONResponse; } catch (error: any) { console.error("Storefront Error:", error); } }
index.tsx代码
export default function Home({ story, products }: any) { //Enable the Visual Editor story = useStoryblokState(story); return ( <> <ProductsProvider value={products}> <StoryblokComponent blok={story.content} /> </ProductsProvider> </> ) } export async function getStaticProps() { const storyblokApi = getStoryblokApi(); //home is the default slug for the homepage in Storyblok let slug = 'home'; //Load draft version let sbParams: any = { version: "draft" //Or 'published }; // Recieve storyblok data let { data }: any = await storyblokApi.get(`cdn/stories/${slug}`, sbParams); // Recieve shopify data const shopifyData: any = await storefront(productsQuery); return { props: { //Storyblok story: data ? data.story : false, key: data ? data.story.id : false, //Shopify products: shopifyData.data, }, revalidate: 3600, } }
问题原因分析
静态生成缓存限制
你使用了getStaticProps+revalidate的增量静态再生(ISR),但Storyblok预览需要实时获取draft版本内容。ISR默认会缓存页面,getStaticProps仅在构建或重新验证时执行,Storyblok编辑器的实时修改无法触发页面重新验证,导致预览看不到最新内容。Shopify API的客户端暴露问题
你给Shopify的环境变量加了NEXT_PUBLIC_前缀,这会把密钥暴露给客户端。生产环境中,客户端直接请求Shopify API会触发跨域限制(本地开发有CORS代理,生产环境没有),同时暴露密钥存在安全风险。这个API请求错误会导致Storyblok编辑器的内容同步逻辑中断,出现区块保存后恢复的问题。Storyblok编辑器的错误依赖
Storyblok编辑器依赖前端无错误的运行状态来同步内容修改。一旦前端出现API请求错误(比如Shopify请求失败),编辑器会无法确认内容已在前端渲染,从而回滚到修改前的状态。
修复方案
1. 适配Storyblok预览的动态内容获取
修改getStaticProps,根据预览模式切换内容版本并调整缓存策略:
export async function getStaticProps(context) { const storyblokApi = getStoryblokApi(); let slug = 'home'; // 判断是否处于Storyblok预览模式 const isPreview = context.preview || false; let sbParams: any = { version: isPreview ? "draft" : "published" }; let { data }: any = await storyblokApi.get(`cdn/stories/${slug}`, sbParams); const shopifyData: any = await storefront(productsQuery); return { props: { story: data ? data.story : false, key: data ? data.story.id : false, products: shopifyData.data, isPreview, }, revalidate: isPreview ? 0 : 3600, // 预览模式禁用缓存 } }
同时在Storyblok后台配置预览URL为Vercel的预览分支地址,确保预览模式能正确拉取draft内容。
2. 修复Shopify API的权限与跨域问题
- 移除Shopify环境变量的
NEXT_PUBLIC_前缀,改为服务端仅能访问的变量:const storefrontAccessToken: string = process.env.SHOPIFY_STOREFRONT_ACCESS_TOKEN!; const storeURL: string = process.env.SHOPIFY_STORE_DOMAIN!; - 确保所有Shopify API请求都在服务端执行(如
getStaticProps/getServerSideProps),不要在客户端组件中直接调用storefront函数。若客户端需要Shopify数据,通过组件Props传递,或创建Next.js API路由作为中间层,客户端通过API路由请求数据。
3. 添加错误边界避免编辑器同步失败
给Storyblok组件添加错误边界,防止单个API错误导致整个编辑器逻辑中断:
// 示例错误边界组件 class ErrorBoundary extends React.Component { constructor(props) { super(props); this.state = { hasError: false }; } static getDerivedStateFromError(error) { return { hasError: true }; } componentDidCatch(error, errorInfo) { console.error("Storyblok Component Error:", error, errorInfo); } render() { if (this.state.hasError) { return <div>内容加载出现问题,请重试</div>; } return this.props.children; } } // 在页面中使用 export default function Home({ story, products }: any) { story = useStoryblokState(story); return ( <> <ProductsProvider value={products}> <ErrorBoundary> <StoryblokComponent blok={story.content} /> </ErrorBoundary> </ProductsProvider> </> ) }
内容的提问来源于stack exchange,提问作者Dosya
相关产品推荐
相关产品推荐

