编写universal
代码(也称为isomorphic
)意味着编写可在服务器和客户端上运行的代码。由于用例和平台 API 的差异,我们的代码在不同环境中运行时的行为不会完全相同。在这里,我们将介绍您需要注意的关键事项。
服务器上的数据响应性
在仅限客户端的应用程序中,每个用户都将在其浏览器中使用应用程序的新实例。对于服务器端渲染,我们希望相同:每个请求都应该有一个新的、隔离的应用程序实例,以避免跨请求状态污染。
由于实际的渲染过程需要是确定性的,因此我们还将在服务器上“预取”数据 - 这意味着当我们开始渲染时,我们的应用程序状态将已经解析。这意味着服务器上不需要数据响应性,因此默认情况下它被禁用。禁用数据响应性还可以避免将数据转换为响应式对象带来的性能成本。
组件生命周期钩子
由于没有动态更新,因此在所有 Vue 生命周期钩子中,只有beforeCreate
和created
将在 SSR 期间被调用。这意味着beforeMount
或mounted
等其他生命周期钩子中的任何代码都将仅在客户端执行。
需要注意的另一点是,您应该避免在beforeCreate
和created
中产生全局副作用的代码,例如使用setInterval
设置计时器。在仅限客户端的代码中,我们可能会设置一个计时器,然后在beforeUnmount
或destroyed
中将其拆除。但是,由于销毁钩子在 SSR 期间不会被调用,因此计时器将永远存在。为了避免这种情况,请将您的副作用代码移至beforeMount
或mounted
。
避免有状态的单例
在编写仅限客户端的代码时,我们习惯于我们的代码每次都会在新的上下文中进行评估。但是,Node.js 服务器是一个长期运行的进程。当我们的代码被需要到进程中时,它将被评估一次,然后保留在内存中。这意味着如果您创建了一个单例对象,它将在每个传入请求之间共享。
因此,Quasar CLI 为每个请求创建了一个新的根 Vue 实例,以及新的 Router 和 Vuex Store 实例。这类似于每个用户将在其自己的浏览器中使用应用程序的新实例的方式。如果我们在多个请求之间使用共享实例,则很容易导致跨请求状态污染。
您可以公开一个工厂函数,而不是直接创建 Router 和 Vuex Store 实例,该函数可以重复执行以创建每个请求的新应用程序实例
export default function (/* { store, ssrContext } */) {
const Router = new VueRouter({...})
return Router
}
export default function (/* { ssrContext } */) {
const Store = new Vuex.Store({...})
return Store
}
如果您使用的是Vuex 模块,请不要忘记将状态导出为函数,否则将创建单例
export default () => ({
...
})
访问平台特定 API
通用代码不能假设可以访问平台特定的 API,因此,如果您的代码直接使用仅限浏览器的全局变量(如window
或document
),则它们在 Node.js 中执行时会抛出错误,反之亦然。
对于服务器和客户端之间共享但使用不同平台 API 的任务,建议将平台特定的实现包装在通用 API 中,或使用为您执行此操作的库。例如,Axios 是一个 HTTP 客户端,它为服务器和客户端都公开了相同的 API。
对于仅限浏览器的 API,常见的方法是在仅限客户端的生命周期钩子中延迟访问它们。
启动文件
请注意,如果第三方库不是为通用使用而编写的,则将其集成到服务器渲染的应用程序中可能会很棘手。您可能能够通过模拟一些全局变量来使其工作,但这将是笨拙的,并且可能会干扰其他库的环境检测代码。
当您将第三方库添加到您的项目中(通过启动文件)时,请考虑它是否可以在服务器和客户端上运行。如果它只需要在服务器上运行或仅在客户端上运行,则在/quasar.config
文件中指定这一点
return {
// ...
boot: [
'some-boot-file', // runs on both server & client
{ path: 'some-other', server: false } // this boot file gets embedded only on client-side
{ path: 'third', client: false } // this boot file gets embedded only on server-side
]
}
数据预取和状态
在 SSR 期间,我们实际上是在渲染应用程序的“快照”,因此,如果应用程序依赖于某些异步数据,则需要在开始渲染过程之前预取和解析这些数据。
Quasar CLI 的预取功能旨在解决此问题。花点时间阅读一下。
此页面的一部分取自官方的Vue.js SSR 指南。