一、为什么要用Nuxt?
1)背景
- 随着各大领域与行业互联网的普及,各大行业都在争取自家的品牌或产品的曝光率多一些,SEO(Search Engine Optimization,搜索引擎优化)已成为前端领域必须考虑的一个问题,SEO 的目的是让网站在搜索引擎中获得更多的流量和曝光度,从而提高品牌知名度和商业价值。
- 然后随着SPA(Single Page Application,单页应用)架构的普及,SPA的弊端也逐步凸显出来。都知道SPA的弊端,不利于搜索引擎优化(SEO不友好),还有首屏加载慢等问题。
- 此时我们就需要SSR(Server-Side Rendering,服务器端渲染)前端开发技术
2)SSR
1、什么是SSR?
- SSR 就是 服务器渲染,什么是 服务器渲染?
- 由 服务器 组装好 DOM 元素,生成 HTML 字符串给到浏览器,也就是在浏览器里面是可以看到整个页面的 DOM 源码的。
2、SSR优点
- 它的主要目的是在服务器端生成 HTML 内容,并将其发送到客户端,从而提高页面的加载速度和搜索引擎优化(SEO)效果。
- 相比于传统的客户端渲染(CSR,Client-Side Rendering)方式,SSR 具有以下优点:
- 更好的首屏加载速度:在客户端渲染中,页面的 HTML、CSS 和 JavaScript 文件需要先被下载到客户端,然后才能进行渲染。而在 SSR 中,服务器端可以直接生成完整的 HTML 内容,并将其发送到客户端,从而提高页面的加载速度和用户体验。
- 更好的搜索引擎优化:由于搜索引擎爬虫无法执行 JavaScript,因此在客户端渲染中,页面的 HTML 内容往往是空的或者不完整的。而在 SSR 中,服务器端可以直接生成完整的 HTML 内容,并将其发送到客户端,从而提高页面的搜索引擎优化效果。
- 更好的可访问性:在客户端渲染中,由于需要等待 JavaScript 文件的加载和执行,因此页面的可访问性往往受到限制。而在 SSR 中,服务器端可以直接生成完整的 HTML 内容,并将其发送到客户端,从而提高页面的可访问性。
- 更好的性能和安全性:在客户端渲染中,由于需要执行大量的 JavaScript 代码,因此页面的性能和安全性往往受到限制。而在 SSR 中,服务器端可以直接生成完整的 HTML 内容,并将其发送到客户端,从而提高页面的性能和安全性。
3、SSR弊端
-
代码兼容:对于开发人员来讲,需要去兼容代码在不同环境的运行
Vue SSR
所需要的服务端环境是Node
,有一些客户端的对象,比如dom
、windows
之类的则无法使用。 -
服务器负载:相对于前后端分离模式下服务器只需要提供静态资源来说,
SSR
需要的服务器负载更大,所以在项目中使用SSR
模式要慎重,比如一整套图表页面,相对于服务端渲染,可能用户不会在乎初始加载的前几秒,可以交由客户端使用类似于骨架屏,或者懒加载之类的提升用户体验。
3)为什么选择Nuxt.js作为vue的SSR解决方案
Nuxt.js 是一个基于 Vue.js 的 SSR 框架,它可以帮助开发者快速搭建 SSR 应用程序,提供了丰富的功能和工具,具有以下优点:
- 简单易用:Nuxt.js 可以快速搭建 SSR 应用程序,无需进行繁琐的配置和编写大量的代码,具有较低的学习成本和上手难度。
- 丰富的功能和工具:Nuxt.js 提供了丰富的功能和工具,例如自动生成路由、自动生成静态站点、自动生成和管理 HTML 头部标签、集成 Vuex 状态管理、集成 axios HTTP 请求等,可以大大提高开发效率和质量。
- 高度可定制:Nuxt.js 提供了多种可定制的配置选项和插件,可以根据项目的需求和特点进行灵活的配置和扩展,从而满足不同的开发需求。
- 优秀的性能和可维护性:Nuxt.js 采用了优秀的代码结构和组织方式,可以提高应用程序的性能和可维护性,并且可以通过优化和缓存等方式进一步提高性能。
- 社区活跃度高:Nuxt.js 有一个活跃的社区,提供了大量的文档、示例和插件,可以帮助开发者快速解决问题和学习新知识。
综上所述,Nuxt.js 是一个优秀的基于 Vue.js 的 SSR 框架,具有简单易用、丰富的功能和工具、高度可定制、优秀的性能和可维护性、活跃的社区等优点,因此在开发基于 Vue.js 的 SSR 应用程序时,选择 Nuxt.js 是一个不错的选择。
二、Nuxt入门
1)安装
// 使用npx创建nuxt项目 npx create-nuxt-app <项目名>
Project name // 项目名称
Programming language // 程序语言 js or ts
Package manager // 包管理 npm or yarn
UI framework // UI框架(ElementUI等)
Template engine // 选择模板引擎 HTML or Pug
Nuxt.js modules // 选择安装其中或者全部nuxt模块(Axios、PWA和CMS)
Linting tools // lint工具(ESLint、Prettier、Lint staged files、StyleLint和CommitLint)
Testing framework // 测试框架(Jest等)
Rendering mode // 渲染模式(SSR/SSG or SPA)
Deployment target // 部署目标 (Server or Static)
Deployment tools // 部署工具(jsconfig.json等)
Continuous integration // 持续集成(Github Actions等)
Version control system // 版本管理(git)
2)目录结构
目录或文件 | 介绍 |
---|---|
assets/ | 资源目录 |
components/ | 组件目录。Nuxt.js不会扩展增强该目录下Vue.js组件,即这些组件不会像页面组件那样有asyncData方法的特性 |
layouts/ | 布局目录 |
middleware/ | 存放应用的中间件 |
pages/ | 页面目录。框架会读取该目录下所有的.vue文件并自动生成对应的路由配置 |
plugins/ | 插件目录。组织那些需要在根vue.js应用实例化之前需要运行的JavaScript插件 |
server/ | 服务器端目录 |
static/ | 静态文件目录。服务器启动时,该目录下的文件会映射至应用的根目录/下 |
store/ | 用于组织应用的Vuex状态树文件,在该目录下创建一个index.js文件即可激活这些配置 |
.eslintrc.js | Eslint配置文件 |
nuxt.config.js | Nuxt.js应用的个性化配置,覆盖默认配置 |
3) 页面特殊配置项
Nuxt.js为页面提供的特殊配置项
属性名 | 描述 |
---|---|
asyncData | 可以在设置组件(限于页面组件)的数据之前能异步获取或处理数据。 |
fetch | 与asyncData方法类似,用于在渲染页面之前获取数据填充应用的状态树(store)。不同的是fetch方法不会设置组件的数据 |
head | 配置当前页面的Meta标签 |
layout | 指定当前页面使用的布局(layouts根目录下的布局文件) |
loading | 如果设置为false,则阻止页面自动调用this.loading.finish()和start(),您可以手动控制它,仅适用于在nuxt.config.js中设置loading的情况下 |
transition | 页面切换的过渡动效 |
scrollToTop | 布尔值,默认: false。 用于判定渲染页面前是否需要将当前页面滚动至顶部。 |
validate | 校验方法用于校验动态路由的参数 |
middleware | 指定页面的中间件,中间件会在页面渲染之前被调用 |
1、asynData/服务端请求
created无法达到异步任务SEO效果。那么如果,需要SEO渲染,如何处理呢?这就是asyncData存在的意义。
来看官网的介绍:asyncData 方法
Nuxt.js 扩展了 Vue.js,增加了一个叫 asyncData 的方法,使得我们可以在设置组件的数据之前能异步获取或处理数据。
由此可以理解,asyncData是Nuxt服务端渲染的关键生命周期。该生命周期属于服务端,即在进入客户端之前,请求好数据展示前拼接好html返回客户端。
因为属于服务端渲染,我们也需特别注意,无法获取到属于客户端的东西,如window,document。其他类似store, this对象等,也需要借助上文说的context完成交互。
注: 由于asyncData方法是在组件 初始化 前被调用的,所以在方法内是没有办法通过 this 来引用组件的实例对象
2、fetch 方法
fetch 方法用于在渲染页面前填充应用的状态树(store)数据, 与 asyncData 方法类似,不同的是它不会设置组件的数据。
asyncData和fetch的参数
//asyncData()(context) {
fetch()(context) {
const { app, //包含所有插件的 Vue 根实例。例如:在使用 axios 的时候,你想获取 $axios 可以直接通过 context.app.$axios 来获取
store, // Vuex.Store 实例。只有vuex 数据流存在相关配置时可用
route, // Vue Router 路由实例
params, // route.params 的别名
query, // route.query 的别名
from, // 路由的导航路线
env, // nuxt.config.js 中配置的环境变量
isDev, //是否是开发 dev 模式,在生产环境的数据缓存中用到
isHMR, //是否是通过模块热替换 webpack hot module replacement (仅在客户端以 dev 模式)
req, // Node.js API 的 Request 对象。如果 Nuxt 以中间件形式使用的话,这个对象就根据你所使用的框架而定。nuxt generate 不可用
res, // 与req同理
redirect,// 用这个方法重定向用户请求到另一个路由。状态码在服务端被使用,默认 302 redirect([status,] path [, query])
error, // 用这个方法展示错误页:error(params) 。params 参数应该包含 statusCode 和 message 字段
$config // 访问运行配置
} = context
}
3)layout布局
可通过添加 layouts/default.vue 文件来扩展应用的默认布局
默认布局的源码如下:
<template>
<!-- 等同于vue的<router-view></router-view> -->
<nuxt />
</template>
1、自定义布局
layouts 目录中的每个文件都将创建一个可通过页面组件中的 layout 属性访问的自定义布局
假如要创建一个title标题让页面公用,保存在layout/title.vue
<template>
<div>
这里标题
<nuxt />
</div>
</template>
<script>
export default {
name: "title",
data () {
return {
}
}
}
</script>
在页面中引入
<template>
<div class="container">
<div class="item-title">这是标题页面</div>
</div>
</template>
<script>
export default {
layout:'title'
}
</script>
<style scoped lang="scss">
</style>
2、定制错误布局
1)第一种:在layout中添加error.vue
<template>
<div class="container">
<h1 v-if="error.statusCode === 404">页面不存在</h1>
<h1 v-else>应用发生错误异常</h1>
</div>
</template>
<script>
export default {
props: ['error'],
}
</script>
<style scoped lang="scss">
.container{
color: #FFFF;
}
</style>
2)第二种:在nuxt.config.js配置中添加router扩展
router: {
// middleware: 'middleware',
extendRoutes (routes, resolve) {
routes.push({
name: 'custom',
path: '*',
component: resolve(__dirname, 'pages/error/404.vue')
})
},
prefetchLinks: false
},
pages/error/404.vue就是指定的路由错误页面
第二种权重最大
4)中间件
中间件允许您定义一个自定义函数运行在一个页面或一组页面渲染之前。
每一个中间件应放置在 middleware/ 目录。文件名的名称将成为中间件名称 (middleware/terminal.js将成为 terminal中间件)。
举例:通过中间件判断终端,根据终端跳转对应路由(PC和移动端一套代码)
在middleware/terminal.js中
export default function ({ req, redirect, route }) {
let isMobile = (ua) => {
return !!ua.match(/AppleWebKit.*Mobile.*/)
}
let userAgent = req ? req.headers['user-agent'] : process.client && navigator.userAgent || ''
//重定向到PC
if ((route.fullPath.indexOf('/m') > -1 || route.fullPath.indexOf('/m/') > -1) && !isMobile(userAgent)) {
let url = route.fullPath.substring(2)
redirect(url)
}
//重定向到PC
if ((route.fullPath.indexOf('/m') < 0 || route.fullPath.indexOf('/m/') < 0) && isMobile(userAgent)) {
redirect('/m' + route.fullPath)
}
}
然后在你的 nuxt.config.js 、 layouts 或者 pages 中使用中间件(权重依次从高到低)
nuxt.config.js
module.exports = {
router: {
middleware: 'terminal'
}
}
现在,terminal中间件将在每个路由改变时被调用。
您也可以将 middleware 添加到指定的布局或者页面:
export default {
middleware: 'terminal'
}
5)页面
页面目录 pages 用于组织应用的路由及视图。Nuxt.js 框架读取该目录下所有的 .vue 文件并自动生成对应的路由配置
6)插件
插件目录 plugins 用于组织那些需要在 根vue.js应用 实例化之前需要运行的 Javascript 插件。
例如我想使用element-ui,在plugins里创建element-ui.js文件
element-ui.js
import Vue from 'vue'
import Element from 'element-ui'
import locale from 'element-ui/lib/locale/lang/en'
Vue.use(Element, { locale })
然后在nuxt.config.js中引入
plugins: ['@/plugins/element-ui'],
就可以在项目中使用element-ui
7)命令
package.json中执行的script命令
"scripts": {
"dev": "nuxt",// 启动一个热加载的 Web 服务器(开发模式) localhost:3000。
"build": "nuxt build",// 利用 webpack 编译应用,压缩 JS 和 CSS 资源(发布用)。
"start": "nuxt start",// 以生产模式启动一个 Web 服务器 (需要先执行nuxt build)。
"generate": "nuxt generate"// 编译应用,并依据路由配置生成对应的 HTML 文件 (用于静态站点的部署)。 },
8)打包部署
1、执行npm run build进行打包
1| .nuxt
2| static
3| nuxt.config.js
4| package.json
2、将这些文件放在服务器文件夹中
3、然后用pm2去部署
在项目根目录创建pm2配置文件ecosystem.config.js
module.exports = {
apps: [
{
name: 'nuxtDemo',//自定义的pm2中name唯一值
exec_mode: 'cluster',
script: './node_modules/nuxt/bin/nuxt.js',
args: 'start',
env: {
"PORT": 30001
}
}
]
}
具体配置可参考ecosystem.config.js 字段详细介绍
npm install
pm2 start
当状态为online的时候就说明部署成功,可以访问了