介绍
作为 vue 开发人员, 你可能听说过服务器端渲染(SSR). 即使你没有使用像 Nuxt.JS 或 SSR-plugin 这样的框架, 你也要知道如何编写在服务器端和客户端都支持的通用组件. 如果你想找到基于 SSR 的方法或与人共享你的组件, 这些知识肯定会让你更轻松! 如果作为一个库 / 插件作者, 我认为这些知识是必须掌握的. 猜猜看, 它甚至都不难!
常见的陷阱
在编写通用组件时, 开发人员应该考虑三个非常常见的警告.
1.Windows, document, and friends - platform-specific APIs
在服务器端处理组件时, 不会发生动态更新. 这就是为什么在服务器上只执行两个生命周期钩子: beforeCreate 和 created. 这也意味着, 这两个钩子将被调用两次, 一次在服务器上, 一次在客户端. 但是在服务器端, 没有 Windows,document, 也没有其他特定于浏览器的 API, 如 fetch. 如果你试图在这两个钩子中调用它们, 服务器上会抛出一个错误, 组件就不能在服务器端渲染了! 这只是服务器端环境下 "普通" 组件或第三方库的最常见问题.
经验法则: 不要在 created 或 beforeCreate 中调用特定于浏览器的 API. 如果必须这样做, 那么至少要执行可用性检查:
- export default {
- created() {
- if(typeof Windows !== 'undefined'){
- Windows.scroll(/*...*/)
- }
- }
- }
但在大多数情况下, 在 beforeMount 或 mount 中调用它们是完全没问题的. 如果必须在服务器和客户端上使用 API, 比如要发送 Ajax 请求, 请确保双方都可以使用(例如使用 isomorphic-fetch 或 axios). 此外, 你有时需要在组件中用到 this.$el($el 是组件本身的 DOM 元素). 在绑定事件侦听器或进行查询选择时, 这可以派上用场.
2.Lifecycle hooks and side effects
说到生命周期钩子! 你应该考虑另一件事: 副作用. 函数或表达式在修改本地环境之外的某些状态时具有副作用. 比如 API 调用, I/O 操作, 设置计时器, 添加侦听器等.
为了避免内存泄漏, 你不希望在创建和 beforeCreate 挂钩中产生副作用, 因为当这些钩子也从服务器端调用时, 你无法关闭那里的连接. 相反, 这些对象将永远存在并加起来, 导致内存泄漏!
经验法则: 不要在 created 或 beforeCreate 中使用带副作用的代码.
3.No data reactivity(数据隔离性)
这通常不是什么大问题, 但你需要知道. 服务器端和客户端的值之间数据互不影响. 如果你在服务器端操作 data, 则根本不会在客户端看到这些变更.
指令(Directives)
自定义 Vue 指令经常用于操纵 DOM(例如, 在滚动时显示元素或使元素固定到特定位置). 我们知道这在服务器端不起作用. 那有什么解决办法呢?
嗯, 最简单的方法是: 不要使用 Directives, 使用 component. 我使用 VueNextLevelScroll 或 vue-if-bot 等组件做到了这一点, 因为它更容易使它们普遍可用, 并且它们也可以进行代码分割! 使用 components 抽离, 你不会失去任何东西.
如果你确实想使用指令, 则可以在服务器端添加相同效果的一个指令. 在 Nuxt 中, 可以通过在 nuxt.config.JS 中的 this.options.render.bundleRenderer 对象中设置指令对象来实现. 一个好的 (但很复杂的) 例子是官方的 v-model ssr 指令.
注意: 请注意以 kebab-case(如: make-red 而不是 makeRed)传递你的指令. 否则, 他们将无法被识别! 这是 vue-server-renderer 中的错误(有关详细信息, 请看官方文档).
总结
使用特定平台的 API 时要特别小心, 尤其是 Windows 和 document. 请记住, created 和 beforeCreate 是在服务器端和客户端都会执行的. 确保写的时候没有副作用, 没有 Windows, 服务器端数据变更不会表现在客服端. 使用指令并不总是最好的抽离方法. 但是如果你确实使用它们, 请提供服务器端指令 如果你想进一步阅读
来源: https://juejin.im/entry/5bd84425e51d452b2c680807