资源
vue ssr
nuxt.js 官网
Nuxt.js 官方文档-中文
nuxt 中文
本文大部分内容转载于:服务端预渲染之Nuxt(介绍篇)
概念
现在前端开发一般都是前后端分离,mvvm
和 mvc
的开发框架,如 Angular
、React
和 Vue
等,虽然写框架能够使我们快速的完成开发,但是由于前后台分离,给项目 SEO
带来很大的不便,搜索引擎在检索的时候是在网页中爬取数据,由于单页面应用读取到的页面是几乎空白的,无法爬取到任何数据信息。
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8>
<meta name=viewport content="width=device-width,initial-scale=1">
<title>authorization_web</title>
</head>
<body>
<div id=app></div>
</body>
</html>
如上代码,单页面应用查看源代码的时候如上所示,所以搜索引擎无法爬取到任何信息,搜索引擎会认为当前页面为一个空页面。为了解决 **SEO**
问题,推出了 **SSR**
服务端预渲染,以便提高对 **SEO**
优化。
什么是SSR
在认识 SSR
之前,首先对 CSR
与 SSR
之间做个对比。
传统的web开发:(mvc)
首先看一下传统的 web开发,传统的web开发是,客户端向服务端发送请求,服务端查询数据库,拼接 HTML
字符串(模板),通过一系列的数据处理之后,把整理好的HTML返回给客户端,浏览器相当于打开了一个页面。这种比如我们经常听说过的jsp
,PHP
,aspx
也就是传统的 **MVC**
的开发。
> 传统的web开发,网页内容在服务端渲染完成,一次性传输到浏览器
单页应用 Single Page App:(CSR)
SPA
应用,到了 Vue
、React
,单页面应用优秀的用户体验,逐渐成为了主流,页面整体式 javaScript
渲染出来的,称之为客户端渲染 **CSR**
。SPA
渲染过程。由客户端访问URL
发送请求到服务端,返回HTML
结构(但是SPA
返回的HTML
结构是非常小的,只有一个基本的结构,如第一段代码所示)。客户端接收到返回结果之后,在客户端开始渲染HTML
,渲染时执行对应javaScript
,最后渲染template
,渲染完成之后,再次向服务端发送数据请求,注意这里是数据请求,服务端返回json
格式数据。客户端接收数据,然后完成最终渲染。
> 单页应用优秀的用户体验,使其逐渐成为主流,页面内容由JS渲染出来,这种方式称为客户端渲染。
SPA虽然给服务器减轻了压力,但是也是有缺点的:
- 首屏渲染时间比较长:必须等待JavaScript加载完毕,并且执行完毕,才能渲染出首屏。
- SEO不友好:爬虫只能拿到一个div元素,认为页面是空的,不利于SEO。
为了解决如上两个问题,出现了SSR解决方案,后端渲染出首屏的DOM结构返回,前端拿到内容带上首屏,后续的页面操作,再用单页面路由和渲染,称之为服务端渲染(SSR)。
服务端渲染 Server Side Render
SSR渲染流程是这样的,客户端发送URL请求到服务端,服务端读取对应的url的模板信息,在服务端做出html和数据的渲染,渲染完成之后返回html结构,客户端这时拿到之后首屏页面的html结构。所以用户在浏览首屏的时候速度会很快,因为客户端不需要再次发送ajax请求。但是并不是做了SSR我们的页面就不属于SPA应用了,它仍然是一个独立的spa应用。
SSR是处于CSR与SPA应用之间的一个折中的方案,在渲染首屏的时候在服务端做出了渲染,注意仅仅是首屏,其他页面还是需要在客户端渲染的,在服务端接收到请求之后并且渲染出首屏页面,会携带着剩余的路由信息预留给客户端去渲染其他路由的页面。
> 后端渲染出完整的首屏的dom结构返回,前端拿到的内容包括首屏及完整spa结构,应用激活后依然按照spa方式运行,这种页面渲染方式被称为服务端渲染(server side render)
nuxt 介绍
在Nuxt
官方网站有一句这样的话:Nuxt.js
预设了使您开发Vue.js
应用程序所需的所有配置。Nuxt
是一个基于Vue.js
的通用应用框架。通过对客户端/服务端基础框架的抽象组织,Nuxt
主要关注的是应用的ui
渲染。
通过上面的这些介绍可以简单的得出:
Nuxt
不仅仅用于服务端渲染也可以用于SPA
应用的开发- 利用
Nuxt
提供的基础项目结构、路由生成、异步数据加载,中间件、插件、布局等特性可大幅提升开发效率 Nuxt
可用于网站静态化,可以使用命令将整个网页打包成静态页面,使SEO
更加友好
nuxt.js特性
- 基于
Vue
- 自动代码分层
- 服务端渲染
- 强大的路由功能,支持异步数据
- 静态文件服务
ECMAScript6
和ECMAScript7
的语法支持- 打包和压缩
JavaScript
和Css
HTML
头部标签管理- 本地开发支持热加载
- 集成
ESLint
- 支持各种样式预编译器
SASS
、LESS
等等 - 支持
HTTP/2
推送
nuxt渲染流程
一个完整的服务器请求到渲染的流程
通过上面的流程图可以看出,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默认安装了):
npx create-nuxt-app <项目名>
或
yarn create nuxt-app <project-name>
安装向导:
Project name // 项目名称
Programming language // 编程语言:JavaScript / TypeScript
Packge manager // 包管理工具: Yarn / NPM
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
Nuxt.js modules // 选择nuxt.js模板:
◉ Axios - Promise based HTTP client
◯ Progressive Web App (PWA)
◉ Content - Git-based headless CMS
Linting tools // 选择代码规范化工具:
◉ ESLint
◉ Prettier
◉ Lint staged files
◉ StyleLint
◉ Commitlint
建议全选,团队协作时利于整体代码管理
Testing framework // 选择测试框架:None / Jest / AVA / WebdriverIO / Nightwatch
Rendering mode // 渲染模式:Universal (SSR / SSG) 渲染所有连接页面 / Single Page App 只渲染当前页面
Deployment target // 开发目标:Server (Node.js hosting) / Static (Static/Jamstack hosting)
Development tools // 开发工具
◉ jsconfig.json (Recommended for VS Code if you're not using typescript)
◉ Semantic Pull Requests
◯ Dependabot (For auto-updating dependencies, GitHub only)
Continuous integration // 持续集成:None / GitHub Actions (GitHub only) / Travis CI / CircleCI
What is your GitHub username? wei0925
Version control system: // 版本控制系统:Git / None
等待安装,安装完毕出现下方提示命令
To get started: 项目运行
cd nuxt-project
npm run dev
To build & start for production: 项目打包
cd nuxt-project
npm run build
npm run start
To test: 项目测试
cd nuxt-project
npm run test
目录结构介绍
- .nuxt
- Nuxt自动生成,临时的用于编辑的文件,
build
- Nuxt自动生成,临时的用于编辑的文件,
- 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
const pkg = require('./package')
module.exports = {
mode: 'universal', // 当前渲染使用模式
head: { // 页面head配置信息
title: pkg.name, // title
meta: [ // meat
{ charset: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
{ hid: 'description', name: 'description', content: pkg.description }
],
link: [ // favicon,若引用css不会进行打包处理
{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }
]
},
loading: { color: '#fff' }, // 页面进度条
css: [ // 全局css(会进行webpack打包处理)
'element-ui/lib/theme-chalk/index.css'
],
plugins: [ // 插件
'@/plugins/element-ui'
],
modules: [ // 模块
'@nuxtjs/axios',
],
axios: {},
build: { // 打包
transpile: [/^element-ui/],
extend(config, ctx) { // webpack自定义配置
}
}
}
packge.json
{
"scripts": {
"dev": "nuxt", // 开发环境
"build": "nuxt build", // 打包/构建项目
"start": "nuxt start", // 线上部署命令
"generate": "nuxt generate", // 生成静态页面
"lint:js": "eslint --ext \".js,.vue\" --ignore-path .gitignore .",
"lint:style": "stylelint \"**/*.{vue,css}\" --ignore-path .gitignore",
"lint": "npm run lint:js && npm run lint:style",
"test": "jest" // 自动化测试
},
}