资源

vue ssr
nuxt.js 官网
Nuxt.js 官方文档-中文
nuxt 中文
本文大部分内容转载于:服务端预渲染之Nuxt(介绍篇)

概念

现在前端开发一般都是前后端分离,mvvm 和 mvc 的开发框架,如 Angular 、React 和 Vue 等,虽然写框架能够使我们快速的完成开发,但是由于前后台分离,给项目 SEO 带来很大的不便,搜索引擎在检索的时候是在网页中爬取数据,由于单页面应用读取到的页面是几乎空白的,无法爬取到任何数据信息。

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset=utf-8>
  5. <meta name=viewport content="width=device-width,initial-scale=1">
  6. <title>authorization_web</title>
  7. </head>
  8. <body>
  9. <div id=app></div>
  10. </body>
  11. </html>

如上代码,单页面应用查看源代码的时候如上所示,所以搜索引擎无法爬取到任何信息,搜索引擎会认为当前页面为一个空页面。为了解决 **SEO** 问题,推出了 **SSR** 服务端预渲染,以便提高对 **SEO** 优化。

什么是SSR

在认识 SSR 之前,首先对 CSR 与 SSR 之间做个对比。

传统的web开发:(mvc)

首先看一下传统的 web开发,传统的web开发是,客户端向服务端发送请求,服务端查询数据库,拼接 HTML字符串(模板),通过一系列的数据处理之后,把整理好的HTML返回给客户端,浏览器相当于打开了一个页面。这种比如我们经常听说过的jsp,PHP,aspx 也就是传统的 **MVC** 的开发。 Nuxt 介绍 - 图1> 传统的web开发,网页内容在服务端渲染完成,一次性传输到浏览器

单页应用 Single Page App:(CSR)

SPA 应用,到了 Vue、React,单页面应用优秀的用户体验,逐渐成为了主流,页面整体式 javaScript 渲染出来的,称之为客户端渲染 **CSR**。SPA渲染过程。由客户端访问URL发送请求到服务端,返回HTML结构(但是SPA返回的HTML结构是非常小的,只有一个基本的结构,如第一段代码所示)。客户端接收到返回结果之后,在客户端开始渲染HTML,渲染时执行对应javaScript,最后渲染template,渲染完成之后,再次向服务端发送数据请求,注意这里是数据请求,服务端返回json格式数据。客户端接收数据,然后完成最终渲染。 Nuxt 介绍 - 图2> 单页应用优秀的用户体验,使其逐渐成为主流,页面内容由JS渲染出来,这种方式称为客户端渲染。

SPA虽然给服务器减轻了压力,但是也是有缺点的:

  1. 首屏渲染时间比较长:必须等待JavaScript加载完毕,并且执行完毕,才能渲染出首屏。
  2. SEO不友好:爬虫只能拿到一个div元素,认为页面是空的,不利于SEO。

为了解决如上两个问题,出现了SSR解决方案,后端渲染出首屏的DOM结构返回,前端拿到内容带上首屏,后续的页面操作,再用单页面路由和渲染,称之为服务端渲染(SSR)。

服务端渲染 Server Side Render

SSR渲染流程是这样的,客户端发送URL请求到服务端,服务端读取对应的url的模板信息,在服务端做出html和数据的渲染,渲染完成之后返回html结构,客户端这时拿到之后首屏页面的html结构。所以用户在浏览首屏的时候速度会很快,因为客户端不需要再次发送ajax请求。但是并不是做了SSR我们的页面就不属于SPA应用了,它仍然是一个独立的spa应用。
SSR是处于CSR与SPA应用之间的一个折中的方案,在渲染首屏的时候在服务端做出了渲染,注意仅仅是首屏,其他页面还是需要在客户端渲染的,在服务端接收到请求之后并且渲染出首屏页面,会携带着剩余的路由信息预留给客户端去渲染其他路由的页面。 Nuxt 介绍 - 图3> 后端渲染出完整的首屏的dom结构返回,前端拿到的内容包括首屏及完整spa结构,应用激活后依然按照spa方式运行,这种页面渲染方式被称为服务端渲染(server side render)

nuxt 介绍

在Nuxt官方网站有一句这样的话:Nuxt.js预设了使您开发Vue.js应用程序所需的所有配置。Nuxt是一个基于Vue.js的通用应用框架。通过对客户端/服务端基础框架的抽象组织,Nuxt主要关注的是应用的ui渲染。

通过上面的这些介绍可以简单的得出:

  1. Nuxt不仅仅用于服务端渲染也可以用于SPA应用的开发
  2. 利用Nuxt提供的基础项目结构、路由生成、异步数据加载,中间件、插件、布局等特性可大幅提升开发效率
  3. Nuxt可用于网站静态化,可以使用命令将整个网页打包成静态页面,使SEO更加友好

nuxt.js特性

  1. 基于 Vue
  2. 自动代码分层
  3. 服务端渲染
  4. 强大的路由功能,支持异步数据
  5. 静态文件服务
  6. ECMAScript6 和 ECMAScript7 的语法支持
  7. 打包和压缩 JavaScript 和 Css
  8. HTML 头部标签管理
  9. 本地开发支持热加载
  10. 集成 ESLint
  11. 支持各种样式预编译器 SASS、LESS 等等
  12. 支持 HTTP/2 推送

nuxt渲染流程

一个完整的服务器请求到渲染的流程
image.png
通过上面的流程图可以看出,Nuxt.js 通过一系列构建于 Vue.js 之上的方法进行服务端渲染,具体流程如下:

第一步:当一个客户端请求进入的时候,服务端通过调用 nuxtServerInit 方法。预先将服务器的数据保存,如已登录的用户信息等。这个方法也可以执行异步操作 Store action,并等待数据解析后返回。让我们可以将从服务端拿到的信息存储到 Store 中。

第二步:之后使用了 Middleware 中间件机制,中间件其实就是一个函数,会在每个路由执行之前去执行,在这里可以做很多事情,或者说可以理解为是路由器的拦截器的作用。读取 nuxt.config.js 中全局 middleware 字段的配置,并调用相应的中间件方法 匹配并加载与请求相对应的 layout 调用 layout 和 page 的中间件方法。

第三步:然后再调用 validate 方法,对客户端携带的请求参数进行校验,或是对第一步中服务器下发的数据进行校验,如果校验失败,将抛出 404 页面。

第四步:调用 asyncData 与 fetch 方法。这两个方法都会在组件加载之前被调用(进入正式的渲染周期),它们的职责各有不同,asyncData 用来异步的进行组件数据的初始化工作,把请求到的数据合并到 Vue 中的 data 中。而 fetch 方法偏重于异步获取数据后修改 Vuex 中的状态。

nuxt安装

安装命令:

确保安装了npx(npx在NPM版本5.2.0默认安装了):

  1. npx create-nuxt-app <项目名>
  2. 或
  3. yarn create nuxt-app <project-name>

安装向导:

  1. Project name // 项目名称
  2. Programming language // 编程语言:JavaScript / TypeScript
  3. Packge manager // 包管理工具: Yarn / NPM
  4. UI framework // ui框架: None / Ant Design Vue / BalmUI / Bootstrap Vue / Buefy / Chakra UI / Element / Framevuerk / Oruga / Tachyons / Tailwind CSS / Windi CSS / Vant / View UI / Vuesax / Vuetify.js
  5. Nuxt.js modules // 选择nuxt.js模板:
  6. ◉ Axios - Promise based HTTP client
  7. ◯ Progressive Web App (PWA)
  8. ◉ Content - Git-based headless CMS
  9. Linting tools // 选择代码规范化工具:
  10. ◉ ESLint
  11. ◉ Prettier
  12. ◉ Lint staged files
  13. ◉ StyleLint
  14. ◉ Commitlint
  15. 建议全选,团队协作时利于整体代码管理
  16. Testing framework // 选择测试框架:None / Jest / AVA / WebdriverIO / Nightwatch
  17. Rendering mode // 渲染模式:Universal (SSR / SSG) 渲染所有连接页面 / Single Page App 只渲染当前页面
  18. Deployment target // 开发目标:Server (Node.js hosting) / Static (Static/Jamstack hosting)
  19. Development tools // 开发工具
  20. ◉ jsconfig.json (Recommended for VS Code if you're not using typescript)
  21. ◉ Semantic Pull Requests
  22. ◯ Dependabot (For auto-updating dependencies, GitHub only)
  23. Continuous integration // 持续集成:None / GitHub Actions (GitHub only) / Travis CI / CircleCI
  24. What is your GitHub username? wei0925
  25. Version control system: // 版本控制系统:Git / None

等待安装,安装完毕出现下方提示命令

  1. To get started: 项目运行
  2. cd nuxt-project
  3. npm run dev
  4. To build & start for production: 项目打包
  5. cd nuxt-project
  6. npm run build
  7. npm run start
  8. To test: 项目测试
  9. cd nuxt-project
  10. npm run test

目录结构介绍

  • .nuxt
    • Nuxt自动生成,临时的用于编辑的文件,build
  • assets
    • 存放未编译的静态资源文件
    • 放置需要经过 webpack 打包处理的资源文件,如 less、sass、JavaScript
  • components
    • 存放 Vue.js 可以复用的组件。
    • Nuxt.js 不会扩展增强该目录下 Vue.js 组件,即这些组件不会像⻚面组件那样有 asyncData 方法的特性。
  • content
  • layouts
    • 存放布局组件
    • 该目录名为 Nuxt.js 保留的,不可更改。
    • 页面都需要有一个布局,默认为 default.vue。它规定了一个页面如何布局页面。 可以在这个目录下创建全局页面的统一布局,或是错误页布局。
    • 如果需要在布局中渲染 pages 目录中的路由页面,需要在布局文件中加上 <nuxt /> 标签。
    • 如果需要在普通页面中使用下级路由,则需要在页面中添加 <nuxt-child />。
  • middleware
    • 存放中间件
    • 在加载组件之前调用。可以在页面中调用: middleware: 'middlewareName' 。
  • node_modules
    • 存放依赖包
  • pages
    • 存放页面
    • 一个 vue 文件即为一个页面。index.vue 为根页面
    • 我们主要的工作区域。用于nuxt自动组织应用的路由及视图。Nuxt.js 框架读取该目录下所有的 .vue 文件并自动生成对应的路由配置。
    • 若需要二级页面,则添加文件夹即可
    • 如果页面的名称类似于 id.vue (以 开头),则为动态路由页面
      • _ 后为匹配的变量(params)。
      • 若变量是必须的,则在文件夹下建立空文件 index.vue。
  • plugins
    • 存放插件。
    • 用于组织需要在 vue.js 实例化之前运行的 Javascript 插件。
    • 需要注意的是,在任何 Vue 组件的生命周期内, 只有 beforeCreate 和 created 这两个钩子方法会在 客户端和服务端均被调用。其他钩子方法仅在客户端被调用。 可以在这个目录中放置自定义插件,在根 Vue 对象实例化之前运行。例如,可以将项目中的埋点逻辑封装成一个插件,放置在这个目录中,并在 nuxt.config.js 中加载。
  • static
    • 存放静态资源文件
    • 此类文件不会被 Nuxt.js 调用 Webpack 进行构建编译处理。放置不需要经过 webpack 打包的静态资源。如一些 js, css 库,图片,ico,logo,导航图标。
    • 服务器启动的时候,该目录下的文件会映射至应用的根路径 / 下。
  • store
    • vuex 状态管理。官网
    • Nuxt.js 框架集成了 Vuex 的相关功能配置,在 store 目录下创建一个 index.js 文件可激活这些配置。
  • test
    • 存放测试代码
  • .babelrc
  • .editorconfig
    • 开发工具格式配置
  • .eslintrc.js
    • eslint 的配置文件,用于检查代码格式
  • .gitignore
    • 配置 git 不上传的文件
  • .prettierrc
  • commitlint.config.js
  • jest.config.js
    • 自动化测试配置
  • jsconfig.json
  • nuxt.config.js
    • Nuxt.js 应用个性化配置,以便覆盖默认配置。官网
  • package-lock.json
    • npm 自动生成,用于帮助 package 的统一性设置的,yarn也有相同的操作
  • package.json
    • npm 包管理配置文件
  • stylelint.config.js

nuxt.config.js

  1. const pkg = require('./package')
  2. module.exports = {
  3. mode: 'universal', // 当前渲染使用模式
  4. head: { // 页面head配置信息
  5. title: pkg.name, // title
  6. meta: [ // meat
  7. { charset: 'utf-8' },
  8. { name: 'viewport', content: 'width=device-width, initial-scale=1' },
  9. { hid: 'description', name: 'description', content: pkg.description }
  10. ],
  11. link: [ // favicon,若引用css不会进行打包处理
  12. { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }
  13. ]
  14. },
  15. loading: { color: '#fff' }, // 页面进度条
  16. css: [ // 全局css(会进行webpack打包处理)
  17. 'element-ui/lib/theme-chalk/index.css'
  18. ],
  19. plugins: [ // 插件
  20. '@/plugins/element-ui'
  21. ],
  22. modules: [ // 模块
  23. '@nuxtjs/axios',
  24. ],
  25. axios: {},
  26. build: { // 打包
  27. transpile: [/^element-ui/],
  28. extend(config, ctx) { // webpack自定义配置
  29. }
  30. }
  31. }

packge.json

  1. {
  2. "scripts": {
  3. "dev": "nuxt", // 开发环境
  4. "build": "nuxt build", // 打包/构建项目
  5. "start": "nuxt start", // 线上部署命令
  6. "generate": "nuxt generate", // 生成静态页面
  7. "lint:js": "eslint --ext \".js,.vue\" --ignore-path .gitignore .",
  8. "lint:style": "stylelint \"**/*.{vue,css}\" --ignore-path .gitignore",
  9. "lint": "npm run lint:js && npm run lint:style",
  10. "test": "jest" // 自动化测试
  11. },
  12. }