【第十二期】Vapper - 一个基于 Vue 的 SSR 框架

2,739 阅读6分钟

如果你正在使用 Vue 做同构的项目,那么 Nuxt 以及 Quasar Framework 都是一个不错的选择。但是今天我要介绍的是由水滴前端自主研发的一个基于 VueSSR 框架:Vapperjs

Vapperjs 是一个开源项目:github.com/vapperjs/va…

Vapper 的特性

我猜大部分同学在看到这篇文章之后的第一个疑问应该是:为什么不直接使用 Nuxt 或者 Quasar Framework 等框架,而是又造了一个轮子?接下来我们将尝试通过介绍 Vapper 的特性来解答这些问题,来看看 Vapper 有什么不同之处。

目标一:尽最大的努力让 SSR 应用的开发体验更接近 SPA

如何才能做到这一点呢?我们需要分几个方面来考虑:

  • 1、项目结构:

与其说项目结构,更准确的说法应该是文件的组织方式。我们知道 Nuxt 是基于文件系统的路由,这意味着它与传统 SPA 应用在文件的组织方式上就必然存在差距,你需要按照其规范(或规定的方式)去编写页面(或组件)。然而,我们在开发 SPA 应用时完全没有这些限制,因此我们希望有一个框架能够让我们不受任何限制的去组织文件,就像普通 SPA 应用一样。

要实现这一点其实并不难,因为 Vue SSR 的官方文档教给你的就是这种方式,因此 Vapper 就在此基础上的封装

  • 2、数据预取:

用过 Nuxt 的同学一定对其提供的 asyncData 组件选项很熟悉,你需要在 asyncData 函数内做数据预取,但是它有一些限制,例如该组件选项不能用于任何组件,只能在路由组件中使用(或 pages),并且在 asyncData 函数内是不能访问组件实例对象的。

数据预取,说白了就是请求数据,我们在开发 SPA 应用时从来没有因为请求数据而关心过是否只能在路由组件中请求数据,更没有关心过请求数据时不能访问组件实例的问题(这里我们假设是在 mountedcreated 钩子中进行数据预取)。因此我们希望有一个框架能够让你免除这些心智负担,并尽最大努力让同构应用的数据预取更加接近 SPA 应用。

Vapper 让这一切成为了可能,详情可以阅读官方文档,了解在 Vapper 中如何进行数据预取:Data prefetch

通过在如上两方面的努力,我们就几乎做到了让开发 SSR 应用的体验更加接近开发 SPA 应用。

目标二:只负责必要的 webpack 配置

很多人力富裕的公司或团队基本都会开发一个所谓的脚手架工具,但是绝大部分团队开发的脚手架工具都只是实现了 1% 功能的 Vue CLI3,实际上在 Vue CLI3 现有的架构下,理论上你完全可以实现任何业务特定场景的需求,而不需要自己再编写一个脚手架。

Vue CLI3 的架构借鉴了 PoiPoi 也是一个优秀的 webpack 管理工具,一个优秀的项目脚手架,因此我们希望有这样一个 SSR 框架,它本身只负责必要的 webpack 配置,即只负责 SSR 相关的 webpack 配置,其他的配置交给这些优秀的脚手架管理。这么做的好处就是双向的,即 Vapper 为这些脚手架提供了 SSR 能力,同时这些 webpack 管理工具的能力也成为了 Vapper 的能力,一举两得。

Vapper 中有一个 Configer 的概念,简单的说就是两个模块:

这让 Vapper 与这些优秀的 webpack 管理工具结合成为了可能,而且更重要的是就算你不适用 Vue CLI3 或者 Poi,你也可以编写自己的 Configer 从而集成到你自己的脚手架中,文档可以阅读这里:编写 Configer

目标三:路由级别的控制能力

什么是路由级别的控制能力呢?为了便于理解,我贴一张官网的图片:

一句话,我们希望访问不同的路由会根据需要采用不同的处理方式,例如我们希望当访问路由 /home 时应用服务端渲染(SSR);但是当访问路由 /foo 时直接返回 SPA 资源给用户;甚至当我们访问路由 /bar 时,我们可以把预渲染好的内容发送给客户端。

之所以要这么做,是因为有的时候,并非所有项目我们都需要进行 SSR,而且我们可以对部分页面进行预渲染,这些都是提升服务性能的有效途径。

Vapper 中你可以轻松做到这一点,你可以通过在路由 meta 中指定 ssr: true/false 来选择开启或关闭 SSR,例如:

new VueRouter({
  mode: 'history',
  routes: [
    {
      path: '/home',
      component: () => import('./components/Home.vue'),
      meta: {
        // 应用 SSR
        ssr: true
      }
    },
    {
      path: '/foo',
      component: () => import('./components/About.vue'),
      meta: {
        // 关闭 SSR,当用户访问 /foo 时将会得到 SPA 资源
        ssr: false
      }
    }
  ]
})

就是这么简单直率,不得不提的一点是,如果所有路由都没有应用 SSR,那么你的项目和 SPA 应用没有任何区别。换句话说,如果你想将现有 SPA 项目逐步迁移为 SSR 项目,那么 Vapper 非常适合你。

对于预渲染要稍微复杂一点,你需要安装 @vapper/plugin-prerender 插件,然后在 vapper.config.js 中进行如下配置:

// vapper.config.js
module.exports = {
  plugins: [
    [
      '@vapper/plugin-prerender',
      {
        // 写下要进行预渲染的路由
        routes: ['/foo']
      }
    ]
  ]
}

这样在构建阶段,vapper 会对 /foo 进行预渲染并生成 html 文件,当用户访问此路由时,会直接将该 html 文件发送给客户端。需要注意的是,只有开启了 SSR 的路由才支持预渲染,当然这是合理的。

目标四:错误处理方式

Vapper 让错误的处理方式更为灵活,当错误发生时我们有两种选择,除了展示自定义的错误页面之外,还可以选择回退的 SPA 模式。这么做的好处是显而易见的。因为有些错误可能只发生于服务端,或者有些错误是非致命的,对于这样的错误发生时,我们可以选择回退到 SPA 模式,这样用户就可以继续使用我们的应用,这对于一些注重转化率的场景是至关重要的。

更多内容可以阅读:Error Handling

更多特性

除了以上介绍的几个核心目标之外,Vapper 还拥有其他出色的特性,例如:

我们已经在自己的项目中使用了 Vapper,欢迎 StarPR: github.com/vapperjs/va…