我的网站大体上是一个静态网站,但我仍然想要身份验证和会话功能。我想有一种方法可以静态生成网站,但随后会覆盖诸如您未登录消息以在水合时以“用户”身份登录的信息,对吗?更重要的是它可以与预取一起使用吗?
1 回答
文档的这一部分令人困惑:
换句话说,任何涉及用户会话或身份验证的应用程序都不是 sapper 导出的候选者。
真正重要的规则是这个:
基本规则是:对于一个可导出的应用程序,任何两个访问您应用程序的同一页面的用户都必须从服务器获取相同的内容。
这并不妨碍您拥有一些代码,对所有用户都相同,但是根据客户端会话(例如 localStorage ...)或您通常可以在客户端执行的任何操作,其行为会有所不同。
例如,您可以在应用程序的任何地方都有这样的代码:
<script>
const isServer = typeof window === 'undefined'
const getUserInfo = async page => {
if (isServer) {
// on server, returns a promise that never resolves, to always
// render as "loading" (adjust to your needs)
return new Promise()
}
// on client, resolve from localStorage, HTTP request, or whatever
return loadUser(page)
}
</script>
{#await getUserInfo()}
<div>Loading...</div>
{:then userInfo}
{#if userInfo && userInfo.userId != null}
<div>Logged in as {userInfo.username}</div>
{:else}
<a href="/login">Log in</a>
{/if}
{:catch err}
<div>Oops: {err}</div>
{/await}
显然,这不会被预取(Sapper 不会分析您的代码的作用)。
但是,您也可以通过以下方式解析用户信息preload
:
<script context="module">
import { loadUser } from './api'
const isServer = typeof window === 'undefined'
export const preload = async page => {
// if preload returns nothing on the server, then it will be called
// again in the client (otherwise the client will be passed the preloaded
// object and preload could be skipped in the client -- see bellow)
if (isServer) return null
const { data } = await loadUser(page)
return { user: data }
}
</script>
<script>
// our user from preload
export let user
</script>
{#if user && !user.anonymous}
<div>Hello, {user.name}</div>
{:else}
<a href="/login">Log in</a>
{/if}
这将具有以下效果:(1)延迟页面的呈现,直到返回的承诺preload
被解决,以及(2)在页面被预取时开始解析所述用户信息。
如果您打算使用preload
它来解析动态内容,那么在服务器中不要从它返回任何内容(undefined
或),这一点很重要。null
否则,如果页面是通过 URL 直接访问的(例如,如果您重新加载相同的页面),那么服务器数据将被传递给客户端,并且preload
不会被称为客户端。非常微妙的错误。躲开它。
因此,总而言之,preload
服务器中返回的任何内容都将包含在您的静态站点中(因此,可以公开访问)。但是您仍然可以在客户端中管理会话并加载动态内容。如果您从preload
函数中执行此操作,则此加载将照常预取。