使用Nuxt.js开发SSR服务端渲染应用程序

298 阅读4分钟

本篇文章分享来自小伙伴「dapeng」的一次学习总结分享,希望跟社区的同学一起探讨。

1.Nuxt.js介绍

1.1 什么是SEO

  • 搜索引擎优化(Search Engine Optimization), 通过各种技术(手段)来确保,我们的Web内容被搜索引擎最大化收录,最大化提高权重,最终带来更多流量。
  • 显然,使用前端路由的SPA程序不利于SEO
  • SEO解决方案:提前将页面和数据进行整合,如采用SSR

1.2 什么是SSR

  • 服务端渲染(Server Side Render),即:网页是通过服务端渲染生成后输出给客户端。
    • 在SSR中,前端分成2部分:前端客户端、前端服务端
    • 前端服务端,用于发送ajax,获得数据
    • 前端客户端,用于将ajax数据和页面进行渲染,渲染成html页面,并响应给调用程序(浏览器、爬虫)
    • 如果爬虫获得html页面,就可以启动处理程序,处理页面内容,最终完成SEO操作。

1.3 SPA和SSR对比

SPA单页应用程序SSR服务器端渲染
优势1.页面内容在客户端渲染
2. 只关注View层,与后台耦合度低,前后端分离
3.减轻后台渲染画面的压力
1.更好的SEO,搜索引擎工具可以直接查看完全渲染的画面
2.更快的内容到达时间 (time-to-content),用户能更快的看到完整渲染的画面
劣势1.首屏加载缓慢
2.SEO(搜索引擎优化)不友好
1.更多的服务器端负载
2.涉及构建设置和部署的更多要求,需要用Node.js渲染
3.开发条件有限制,一些生命周期将失效
4.一些常用的浏览器API无法使用

1.4 什么是Nuxt.js

  • Nuxt.js 是一个基于 Vue.js 的通用应用框架。
  • 通过对客户端/服务端基础架构的抽象组织,Nuxt.js 主要关注的是应用的 UI 渲染
  • Nuxt.js 预设了利用 Vue.js 开发服务端渲染的应用所需要的各种配置。

2.入门

2.1 create-nuxt-app

  • Nuxt.js 提供了脚手架工具 create-nuxt-app
  • create-nuxt-app 需要使用 npx
  • npx 命令为 NPM版本5.2.0默认安装组件

2.2 安装

npx create-nuxt-app <project-name>

例如

npx create-nuxt-app demo1

image.png

2.3 启动

npm run dev

2.4 访问

http://localhost:3000

2.5 目录结构

image.png

3. Nuxt 框架分析

3.1 context / 上下文

  • 通俗一点的理解:nuxt因需要同时考虑服务端与客户端,原本前端的嵌入到js原型实例的方法已经不适用,服务端需要考虑与客户端考虑数据传输的问题。而nuxt提供的context对象,快速帮助服务端获取对应的数据,如app,store,router, env等,达到两个客户端数据相通的目的。
  • 具体提供的所有对象,可参考上述链接。包括app, store, route, params, query, env, isDev, isHMR等。
  • store, route, params, query等,跟vue实例差异不大,只是nuxt提前帮我们注入到服务端实例中,我们这里解释一下app:
  • 包含所有插件的根 Vue 实例选项。例如,在使用的时候i18n,你可以访问$i18n通过context.app.i18n。
  • 同等于客户端的this。在spa页面的获取Vue实例,只需要通过this对象即可获取。而在服务端,需要借助nuxt提供的app才可以获取到对应的实例。
  • 这里的app,并不等同于页面的this。在特定的生命周期声明,才可以获取得到。如果需要提前注入, 那还要借助plugins机制提前注入。

3.2 layout / 布局

  • layout可能对于一个刚接触nuxt的有点懵逼,毕竟vue-cli没有。
  • 其实非常好理解。vue-cli支持子父路由嵌套,而nuxt的layout,就可以简单理解是vue-cli最外层的嵌套。由于nuxt的路由,是自动生成的。
  • 配置子父路由相对复杂,所以nuxt引入了layout,只需要在对应的页面配置layout:layoutName,就能完成快速的嵌套。非常方便。

3.3 router / 路由

  • vue-cli与nuxt的路由,无论是原理还是实践,差异还挺大的。毕竟一个是服务端路由,一个是纯前端路由。
  • router区别
    • 名称不同这里只是名称叫法不一致,用法都雷同,不再描述
<router-link /> 切换成 <nuxt-link />
<router-view /> 切换成 <nuxt />
  • 自动生成:nuxt的路由是可以自动生成的,这点跟传统的vue-cli有些不一致。
  • 路由钩子nuxt的路由,相比vue-cli复杂一些。nuxt需要借助plugin或者middleware才能完成对路由的全局守卫。
  • 原理性质不同,一个为"前端路由",另外一个为"后端路由",两者的原理是不同的。可以搜索"前端路由"与"后端路由"的差异。

3.4 axios / 网络请求

  • 此时的网络请求,需要考虑两个客户端,故原来的axios在服务端是需要处理做兼容的。
  • 好在官方提供了@nuxtjs/axios,我们只需在modules配置上就可以使用。
modules: [ "@nuxtjs/axios"]
  • 此时,axios可能还面临一个问题,它需要从实例发起请求,但此时你并没有实例。这时候你需要借助plugins:
export default function(context, inject) {
        context.$axios.onRequest((config) => {
            ...
        });
    }

3.5 plugins / 插件机制

  • 在传统的spa页面,执行顺序,是优先生成了实例,再执行对应的js。此时所有的js,想获取到对应的实例,是十分简单的,直接js,或者import vue form 'vue'引入接口。
  • 但是在ssr中,服务端跟客户端是无法同时使用同一个实例的。毕竟server与client还是存在差异。
  • 如果我们自己写ssr框架的话,这将是一大痛点。而nuxt帮我们处理了这个事情,引入了plugins。让在server的生明周期,也可以获取到对应的实例。
  • 给plugins一个简单的理解的话,就是: 需要在根vue.js应用实例化之前需要运行的JavaScript插件
  • 值得注意的是,在配置 plugins 的时候,如果 ssr:false ,将会在asyncData。
  • 或者mode: 'client' || 'server'控制终端。

3.6 fetch的使用

  • 如果页面组件设置了fetch方法,它会在组件每次加载前被调用(在服务端或切换至目标路由之前),此方法需要跟服务端的人员配合
<script>
  export default { 
    async fetch ({ app, store, params }) {
      let { data } = app.$axios.get('/token');
      store.commit('setToken', data.token);
    }
  }
</script> 

3.7 nuxtServerInit

import Vuex from 'vuex'
let store = () => new Vuex.Store({
  state: {
  	token: ''   
  },
  mutations: {     
  	setToken (state, token) {
      state.token = token    
    }
  },
  actions: {
  	nuxtServerInit({ commit }, { req }) {
      let cookie = req.headers.cookie; // 将cookie转成json对象(自己实现该方法)       
      let token = cookieparse(cookie).token;
      commit('setToken', token);
  	},
  }
})
export default store 

3.8 pm2部署

  • 它允许您永久保持应用程序活跃,无需停机即可重新加载它们,并不需要传统部署的.nuxt文件夹,该部署方法也跟生产环境一样含热更新
npm install pm2 -g 

npm run build pm2 start ./node_modules/nuxt/bin/nuxt-start