一、背景

在今年年初我开始接触vue的时候,就发现在vue官方文档中“服务端渲染”的一节中提到了Nuxt.js框架,SSR这种方式对于首屏的加载时间优化显而易见,同时还可以方便的进行SEO。美团点评的点餐业务中,数据平台因为其数据量大的特点,首页加载时间很长,非常适合进行SSR改造;于是,我在非工作时间对nuxt.js框架进行了尝试,吃了一波螃蟹。本文对nuxt.js框架应用于生产环境进行了系统的论述,同时对所踩的坑也进行了一定的介绍。

官方对nuxt.js的介绍如下:

Properly configuring all the discussed aspects of a production-ready server-rendered app can be a daunting task. Luckily, there is an excellent community project that aims to make all of this easier: Nuxt.js. Nuxt.js is a higher-level framework built on top of the Vue ecosystem which provides an extremely streamlined development experience for writing universal Vue applications. Better yet, you can even use it as a static site generator (with pages authored as single-file Vue components)! We highly recommend giving it a try.

可以看出,vue官方对于nuxt.js的态度非常积极,还是值得大家尝试的,目前最新版本:1.0.0-rc2;1.0正式版即将发布,撒花!

因本文作者水平所限,如有错误,欢迎拍砖。

二、nuxt.js 简单介绍

1、nuxt.js的原理图:


具体的原理介绍官网有详细的解释,欢迎读者移步官网,这里不再复述。

2、nuxt.js的优势

1)就是我们无需为了路由划分而烦恼,你只需要按照对应的文件夹层级创建 .vue 文件就行
2)无需考虑数据传输问题,nuxt 会在模板输出之前异步请求数据(需要引入 axios 库),而且对 vuex 有进一步的封装
3)内置了 webpack,省去了配置 webpack 的步骤,nuxt 会根据配置打包对应的文件

三、技术栈选型

1、nuxt.js:0.10.6

2、axios:0.16.2 → 选择axios的原因很简单,它是vue官方推荐的包,并且axios可以运行于浏览器端和服务器端,减少了前端工程师的学习成本。

3、elementUI:1.3.7 → elementUI是基于vue的很全面的ui组件库,对于一个自己的验证项目很合适,可以快速开发,快速上线。

四、实施方案

工程的目录结构如下:


1、插件安装

你可以配置需要在“根vue.js应用”实例化之前需要运行的js插件,当然可以是你自己写的或第三方模块。

注意:在任何vue组件的生命周期内,只有beforeCreate和created这两个钩子会在浏览器端和服务端均被调用;其他的钩子都只会在浏览器端调用。

1)对于axios这种ajax请求插件,无疑会使用在页面的方方面面中,那么如果在每个页面中使用import方式进行引入,会导致在打包的时候打包多次。而实际上我们只需要打包一次,可以通过在nuxt.config.js里面的build.vendor来解决。


当然,如果你需要区分测试环境和线上环境的接口地址,就需要在plugins文件中对axios进行编写,如图:


2)使用vue插件 - elementUI

普通的npm包的引入方式如上面的axios所述,那么vue插件我们该怎么处理呢?

  1. 首先我们需要在plugins文件夹中添加插件文件,element-ui.js



  2. 在nuxt.config.js中配置plugins字段


  3. 由于elementUI是第三方库,我们需要把它打包到库文件里面以获得更好的缓存效果。在nuxt.config.js中配置element-ui即可。


3)同时nuxt还支持区分只在浏览器中运行和只在服务端运行的插件。

  1. 只在浏览器运行:配置nuxt.config.js中plugins字段,将引入的插件属性设置为ssr: false


  2. 只在服务端运行:直接在webpack打包server.bundle.js文件中,将process.SERVER_BUILD设置为true即可

2、layout布局

nuxt.js实现了一个新的概念,layout布局,我们可以通过layout布局方便的实现页面的多个布局之间方便的切换。本项目中实现了三种常用的布局,即:1)两栏布局,左栏固定,右栏动态宽度;2、错误页提示,页面中间一个提示框的布局方案;3、纯白页面布局。


以两栏布局举例:

  1. 首先,在layout → default.vue中编写默认布局


    layout与页面的具体内容的插口即:nuxt标签
  2. 具体开发的页面中,如果使用默认布局,则不需指定页面的布局,nuxt框架会自动对没有指定布局的页面和default布局进行关联。如果需要指定布局,则在layout字段中对布局进行指定。如图在login页面中对full布局进行了指定。


注:个人开发感受:layout布局对于页面类型多变的工程很有好处,我们可以减少冗余代码,并且方便开发人员在多个布局中简单切换。nuxt框架将页面分层划分为3层:1、布局;2、页面;3、组件


这么划分逻辑上更清楚,也更贴近组件化页面开发的思想。

PS:个人在非vue项目中也自行实现了一个简单的layout布局,使用slot插口即可实现。


layout文件提供slot插口


在开发页面中将layout文件以组件的方式引入即可。

3、server端api编写

nuxt的server端使用的是express,故server端api直接编写express router即可。server端目录组织如图:


server/index.js 文件是express的启动文件,plugins和middleware文件是axios的配置,api文件夹内即api接口。

server/index.js文件里面对api引用如下:


我们先看看axios的配置,通过对process.env的匹配来区分线上与测试环境,同时在middleware文件中对接口进行鉴权。



之后在api/index.js文件中对各接口进行引用和聚合


在所有接口文件中,以announcement.js举例:


可以看到为了实现简便和避免过度设计,api接口没有对数据进行重新封装,直接进行了透传处理。

4、页面路由

nuxt框架的页面路由使用了vue-router,但是我们不需要对页面的路由进行过多的操心,因为我们只要按照nuxt规范的页面文件目录结构进行设计,就可以自动生成vue-router文件。或者说我们存放页面的目录结构会直接影响最终生成的路由配置。

本项目的页面目录结构如图所示:


而生成的router文件为:


可以看出生成的路由与pages文件夹目录结构是一一对应的。

注意:其中带参数的动态路由,需要创建对应的下划线作为前缀的vue文件或目录。例如图中bidDetail/_id.vue文件,最终生成的路由即为:path: "/bidDetail/:id?"。

五、总结

从头搭建一个服务端渲染的框架其实是相当复杂的,不过有了nuxt.js后,我们可以很轻易的搭建出一个可扩展可定制的SSR框架,这大大的减少了我们搭建框架的时间成本。因为nuxt的官方文档写的足够详细,我没有对安装这类常规项进行描述,直接从插件安装、新概念 - layout布局、server端api、pages的组织入手,介绍了我在项目实战中使用nuxt框架的一些关键路径。目前项目上线在aws跑了半个多月,总体稳定,说明虽然nuxt不是1.0版本,但是也足够用于生产实践了。(考虑到github上说。nuxt的1.0版本即将到来,我们有理由期待vue的SSR前景)

由于本文作者水平与篇幅所限,不能对项目中的所有细节尽述,对nuxt感兴趣的读者可以邮件联系:wangxinghang@meituan.com,感谢~