Sapper中动态路由页面为什么在客户端首次加载时显示空白?
折腾了一下午也没解决,我在Sapper的动态路由里写了一个博客详情页,服务器端渲染正常,但直接访问客户端时页面内容全白。
代码是这样的:
<!-- routes/_posts/[slug].svelte -->
<script context="module">
export async function load({ params }) {
const post = await fetch(<code>api/posts/${params.slug}</code>).then(res => res.json())
return { props: { post } }
}
</script>
<script>
export let post;
</script>
<h1>{post.title}</h1>
<p>{post.content}</p>
检查了网络请求发现客户端没有触发API调用,控制台也没报错。预渲染时页面能正确显示,但直接访问客户端URL就空白。尝试过加key属性和强制更新都没用,求大神指点!
load函数,除非你在页面组件里显式调用它。标准写法是:在页面组件里用export let page接收路由参数,然后手动调用preload(或者让 Sapper 帮你自动调用,但前提是你的组件结构得对)。你现在的
load写在context="module"里是对的,但 Sapper 要求页面组件本身得是默认导出的 Svelte 组件,而且不能漏掉export let page,哪怕你没用到它——这是触发客户端load的关键开关。改法很简单,把你的代码改成这样就行:
注意
export let page这一行不能省,哪怕你不操作它。这是 Sapper 客户端进入页面时判断是否需要执行load的依据之一,文档里叫“implicit preload trigger”。另外顺带一提,你 API 路径里的反引号没闭合,
api/posts/${params.slug}应该写成api/posts/${params.slug},不过这在问题描述里是被代码标签包裹的,估计是复制时的格式问题,不是你真正漏写的。如果加了
export let page还是空白,再检查下fetch返回的post是不是 null 或 undefined——Sapper 客户端不会自动 fallback,props 里要是没值,模板里直接访问post.title就会静默失败(不报错,但页面白屏)。可以加个兜底:这问题我当年也踩过,以为是 SSR/CSR 差异,其实就差那一个
export let page。几点说明:第一,要用
preload而不是load,这是Sapper的生命周期钩子,专门处理页面加载前的数据获取。第二,记得加条件渲染,防止数据未加载完成时报错。第三,用this.fetch替代原生fetch,它能保证服务端和客户端请求的一致性。最后提醒一句,检查下你的
api/posts/[slug]接口是不是同时支持GET请求,有时候只写了POST就会出问题。我之前就踩过这坑,调试了一晚上。