Skip to content

Vue3 SSR、Nuxt3

[TOC]

Vue3 SSR

单页应用程序(SPA)

单页应用程序 (SPA) 全称是:Single-page application,SPA应用是在客户端呈现的(术语称:CRS)。

  • SPA应用默认只返回一个空HTML页面,如:body只有<div id="app"></div>
  • 而整个应用程序的内容都是通过 Javascript 动态加载,包括应用程序的逻辑、UI 以及与服务器通信相关的所有数据。
  • 构建 SPA 应用常见的库和框架有: React、AngularJS、Vue.js 等。

客户端渲染原理

image-20240911154139238

SPA优缺点

SPA的优点

  • 只需加载一次
    • SPA应用程序只需要在第一次请求时加载页面,页面切换不需重新加载,而传统的Web应用程序必须在每次请求时都得加载页面,需要花费更多时间。因此,SPA页面加载速度要比传统 Web 应用程序更快。
  • 更好的用户体验
    • SPA 提供类似于桌面或移动应用程序的体验。用户切换页面不必重新加载新页面
    • 切换页面只是内容发生了变化,页面并没有重新加载,从而使体验变得更加流畅
  • 可轻松的构建功能丰富的Web应用程序

SPA的缺点

  • SPA应用默认只返回一个空HTML页面,不利于SEO (search engine optimization)
  • 首屏加载的资源过大时,一样会影响首屏的渲染
  • 也不利于构建复杂的项目,复杂 Web 应用程序的大文件可能变得难以维护

爬虫-工作流程

Google 爬虫的工作流程分为 3 个阶段,并非每个网页都会经历这 3 个阶段:

  • 抓取:
    • 爬虫(也称蜘蛛),从互联网上发现各类网页, 网页中的外部连接也会被发现。
    • 抓取数以十亿被发现网页的内容,如:文本、图片和视频
  • 索引编制:
    • 爬虫程序会分析网页上的文本、图片和视频文件
    • 并将信息存储在大型数据库(索引区)中。
    • 例如 <title> 元素和 Alt 属性、图片、视频等
    • 爬虫会对内容类似的网页归类分组
    • 不符合规则内容和网站会被清理
      • 如:禁止访问 或 需要权限网站等等
  • 呈现搜索结果:
    • 当用户在 Google 中搜索时,搜索引擎会根据内容的类型,选择一组网页中最具代表性的网页进行呈现

image-20240911154151286

搜索引擎的优化(SEO)

语义性HTML标记

  • 标题用<h1>,一个页面只有一个; 副标题用<h2><h6>
  • 不要过度使用h标签,多次使用不会增加 SEO(search engine optimization)。
  • 段落用<p>,列表用<ul>,并且li只放在 ul 中 等等。

每个页面需包含:标题 + 内部链接

  • 每个页面对应的title,同一网站所有页面都有内链可以指向首页

确保链接可供抓取,如右图所示:

meta标签优化:设置 description keywords 等

文本标记和img:

  • 比如<b><strong>加粗文本的标签,爬虫也会关注到该内容
  • img标签添加 alt 属,图片加载失败,爬虫会取alt内容。

robots.txt 文件:规定爬虫可访问您网站上的哪些网址。

sitemap.xml站点地图:在站点地图列出所有网页,确保爬虫不会漏掉某些网页

更多查看:https://developers.google.com/search/docs/crawling-indexing/valid-page-metadata

image-20240911154210001

静态站点生成(SSG)

静态站点生成(SSG) 全称是:Static Site Generate,是预先生成好的静态网站。

  • SSG 应用一般在构建阶段就确定了网站的内容。
  • 如果网站的内容需要更新了,那必须得重新再次构建和部署。
  • 构建 SSG 应用常见的库和框架有: Vue Nuxt、 React Next.js 等。

SSG的优点:

  • 访问速度非常快,因为每个页面都是在构建阶段就已经提前生成好了。
  • 直接给浏览器返回静态的HTML,也有利于SEO
  • SSG应用依然保留了SPA应用的特性,比如:前端路由、响应式数据、虚拟DOM等

SSG的缺点:

  • 页面都是静态,不利于展示实时性的内容,实时性的更适合SSR。
  • 如果站点内容更新了,那必须得重新再次构建和部署。

服务器端渲染(SSR)

服务器端渲染全称是:Server Side Render,在服务器端渲染页面,并将渲染好HTML返回给浏览器呈现。

  • SSR应用的页面是在服务端渲染的,用户每请求一个SSR页面都会先在服务端进行渲染,然后将渲染好的页面,返回给浏览器 呈现。
  • 构建 SSR 应用常见的库和框架有: Vue Nuxt、 React Next.js 等(SSR应用也称同构应用) 。

服务器端渲染原理

image-20240911154224018

SSR优缺点

SSR的优点

  • 更快的首屏渲染速度
    • 浏览器显示静态页面的内容要比 JavaScript 动态生成的内容快得多。
    • 当用户访问首页时可立即返回静态页面内容,而不需要等待浏览器先加载完整个应用程序。
  • 更好的SEO
    • 爬虫是最擅长爬取静态的HTML页面,服务器端直接返回一个静态的HTML给浏览器。
    • 这样有利于爬虫快速抓取网页内容,并编入索引,有利于SEO。
  • SSR应用程序在 Hydration 之后依然可以保留 Web 应用程序的交互性。比如:前端路由、响应式数据、虚拟DOM等。

SSR的缺点

  • SSR 通常需要对服务器进行更多 API 调用,以及在服务器端渲染需要消耗更多的服务器资源,成本高。
  • 增加了一定的开发成本,用户需要关心哪些代码是运行在服务器端,哪些代码是运行在浏览器端。
  • SSR 配置站点的缓存通常会比SPA站点要复杂一点。

SSR 解决方案

SSR的解决方案:

  • 方案一:php、jsp ...
  • 方案二:从零搭建 SSR 项目( Node+webpack+Vue/React )
  • 方案三:直接使用流行的框架(推荐)
    • React : Next.js
    • Vue3 : Nuxt3 | | Vue2 : Nuxt.js
    • Angular : Anglular Universal

SSR应用场景非常广阔,比如:

  • SaaS产品,如:电子邮件网站、在线游戏、客户关系管理系统(CRM)、采购系统等
  • 门户网站、电子商务、零售网站
  • 单个页面、静态网站、文档类网站
  • 等等

image-20240911154253222

image-20240911154259643

邂逅Vue3 + SSR

Vue除了支持开发SPA应用之外,其实也是支持开发SSR应用的。

在Vue中创建SSR应用,需要调用createSSRApp函数,而不是createApp

  • createApp:创建应用,直接挂载到页面上
  • createSSRApp:创建应用,是在激活的模式下挂载应用

服务端用 @vue/server-renderer 包中的 renderToString 来进行渲染。

image-20240911154312608

image-20240911154317705

Node Server 搭建

需安装的依赖项:

  • npm i express
  • npm i –D nodemon
  • npm i -D webpack webpack-cli webpack-node-externals

nodemon:

  • 启动Node程序时并监听文件的变化,变化即刷新

webpack-node-externals:

  • 排除掉 node_modules 中所以的模块

image-20240911154324530

Vue3 + SSR 搭建

需安装的依赖项:

  • npm i express
  • npm i –D nodemon
  • npm i vue
  • npm i -D vue-loader
  • npm i -D babel-loader @babel/preset-env
  • npm i -D webpack webpack-cli
  • npm i -D webpack-merge webpack-node-externals

vue-loader:加载.vue文件

webpack-merge: 用来合并webpack配置

babel-loader、@babel/preset-env

  • 加载JS文件,转换新语法

image-20240911154332979

跨请求状态污染

在SPA中,整个生命周期中只有一个App对象实例 或 一个Router对象实例 或 一个Store对象实例都是可以的,因为每个用户在 使用浏览器访问SPA应用时,应用模块都会重新初始化,这也是一种单例模式。

然而,在 SSR 环境下,App应用模块通常只在服务器启动时初始化一次。同一个应用模块会在多个服务器请求之间被复用,而 我们的单例状态对象也一样,也会在多个请求之间被复用,比如:

  • 当某个用户对共享的单例状态进行修改,那么这个状态可能会意外地泄露给另一个在请求的用户。
  • 我们把这种情况称为:跨请求状态污染。

为了避免这种跨请求状态污染,SSR的解决方案是:

  • 可以在每个请求中为整个应用创建一个全新的实例,包括后面的 router 和全局 store等实例。
  • 所以我们在创建App 或 路由 或 Store对象时都是使用一个函数来创建,保证每个请求都会创建一个全新的实例。
  • 这样也会有缺点:需要消耗更多的服务器的资源。

Vue3 SSR + Hydration

服务器端渲染页面 + 客户端激活页面,是页面有交互效果(这个过程称为:Hydration 水合)

Hydration的具体步骤如下:

  • 1.开发一个App应用,比如App.vue
  • 2.将App.vue打包为一个客户端的client_bundle.js文件
    • 用来激活应用,使页面有交互效果
  • 3.将App.vue打包为一个服务器端的server_bundle.js文件
    • 用来在服务器端动态生成页面的HTML
    1. server_bundle.js 渲染的页面 + client_bundle.js 文件进行Hydration

image-20240911154352824

image-20240911154402094

Vue3 SSR + Vue Router

需再安装的依赖项:

  • npm i vue-router

注意事项:

  • 为了避免 跨请求状态污染
  • 需在每个请求中都创建一个全新router

image-20240911154413775

Vue3 SSR + Pinia

需再安装的依赖项:

  • npm i pinia

注意事项:

  • 为了避免 跨请求状态污染
  • 需在每个请求中都创建一个全新pinia

image-20240911154427603

Nuxt

什么是Nuxt?

在了解 Nuxt 之前,我们先来了解一下创建一个现代应用程序,所需的技术:

  • 支持数据双向绑定 和 组件化( Nuxt 选择了Vue.js )。
  • 处理客户端的导航( Nuxt 选择了vue-router )。
  • 支持开发中热模块替换和生产环境代码打包( Nuxt支持webpack 5和Vite )。
  • 兼容旧版浏览器,支持最新的 JavaScript 语法转译( Nuxt使用esbuild )。
  • 应用程序支持开发环境服务器,也支持服务器端渲染 或 API接口开发。
  • Nuxt 使用 h3来实现部署可移植性(h3是一个极小的高性能的http框架)
    • 如:支持在 Serverless、Workers 和 Node.js 环境中运行。

Nuxt 是一个 直观的 Web 框架

  • 自 2016 年 10 月以来,Nuxt专门负责集成上述所描述的事情 ,并提供前端和后端的功能。
  • Nuxt 框架可以用来快速构建下一个 Vue.js 应用程序,如支持 CSR 、SSR、SSG 渲染模式的应用等。

image-20240911151818836

Nuxt 发展史

Nuxt.js

  • 诞生于 2016 年 10 月 25号,由 Sebastien Chopin 创建,主要是基于Vue2 、Webpack2 、Node 和 Express。
  • 在2018 年 1 月 9 日, Sebastien Chopin 正式宣布,发布 Nuxt.js 1.0 版本。
    • 重要的变化是放弃了对 node < 8 的支持
  • 2018 年 9 月 21 日, , Sebastien Chopin 正式宣布,发布 Nuxt.js 2.0 版本。
    • 开始使用 Webpack 4 及其技术栈, 其它的并没有做出重大更改。
  • 2021年8月12日至今,Nuxt.js 最新的版本为:Nuxt.js 2.15.8

Nuxt3版本:

  • 经过 16 个月的工作,Nuxt 3 beta 于 2021 年 10 月 12 日发布,引入了基于 Vue 3、Vite 和 Nitro( 服务引擎 ) 。
  • 六个月后, 2022 年 4 月 20 日,Pooya Parsa 宣布 Nuxt 3 的第一个候选版本,代号为“Mount Hope”
  • 在2022年11月16号, Pooya Parsa 再次宣布 Nuxt3 发布为第一个正式稳定版本。

官网地址: https://nuxt.com/

Nuxt3 特点

Vue技术栈

  • Nuxt3 是基于 Vue3 + Vue Router + Vite 等技术栈,全程 Vue3+Vite 开发体验(Fast)。

自动导包

  • Nuxt 会自动导入辅助函数、组合 API和 Vue API ,无需手动导入。
  • 基于规范的目录结构,Nuxt 还可以对自己的组件、 插件使用自动导入。

约定式路由(目录结构即路由)

  • Nuxt 路由基于vue-router,在 pages/ 目录中创建的每个页面,都会根据目录结构和文件名来自动生成路由

渲染模式:Nuxt 支持多种渲染模式(SSR、CSR、SSG等)

利于搜索引擎优化:服务器端渲染模式,不但可以提高首屏渲染速度,还利于SEO

服务器引擎

  • 在开发环境中,它使用 Rollup 和 Node.js 。
  • 在生产环境中,使用 Nitro 将您的应用程序和服务器构建到一个通用.output目录中。
    • Nitro服务引擎提供了跨平台部署的支持,包括 Node、Deno、Serverless、Workers等平台上部署。

image-20240911151850083

Nuxt.js VS Nuxt3

image-20240911151901743

Nuxt3 环境搭建

在开始之前,请确保您已安装推荐的设置:

  • Node.js (最新 LTS 版本,或 16.11以上)
  • VS Code
    • Volar、ESLint、Prettier

命令行工具,新建项目(hello-nuxt)

  • 方式一:npx nuxi init hello-nuxt
  • 方式二:pnpm dlx nuxi init hello-nuxt
  • 方式三:npm install –g nuxi && nuxi init hello-nuxt

运行项目: cd hello-nuxt

  • yarn install
  • pnpm install --shamefully-hoist(创建一个扁平的 node_modules 目录结构,类似npm 和 yarn)
  • yarn dev

image-20240911151920796

image-20240911151933741

创建项目报错

执行 npx nuxi init 01-hello-nuxt 报如下错误,主要是网络不通导致:

解决方案:

  • 第一步:ping raw.githubusercontent.com 检查是否通
  • 第二步:如果访问不通,代表是网络不通
  • 第三步:配置 host,本地解析域名
    • Mac电脑 host 配置路径: /etc/hosts
    • Win 电脑 host 配置路由:c:/Windows/System32/drivers/etc/hosts
  • 第四步:在host文件中新增一行 ,编写如下配置:
    • 185.199.108.133 raw.githubusercontent.com
  • 第五步:重新ping域名,如果通了就可以用了
  • 第六部:重新开一个终端创建项目即可

image-20240911151952824

image-20240911151958008

image-20240911152006878

Nuxt3 目录结构

image-20240911152025639

应用入口(App.vue)

默认情况下,Nuxt 会将此文件视为入口点,并为应用程序的每个路由呈现其内容,常用于:

  • 定义页面布局Layout 或 自定义布局,如:NuxtLayout
  • 定义路由的占位,如:NuxtPage
  • 编写全局样式
  • 全局监听路由 等等

image-20240911152103373

Nuxt 配置(nuxt.config)

nuxt.config.ts 配置文件位于项目的根目录,可对Nuxt进行自定义配置。比如,可以进行如下配置:

  • runtimeConfig:运行时配置,即定义环境变量
    • 可通过.env文件中的环境变量来覆盖,优先级(.env > runtimeConfig) ➢ .env的变量会打入到process.env中,符合规则的会覆盖runtimeConfig的变量 ➢ .env一般用于某些终端启动应用时动态指定配置,同时支持dev和pro
  • appConfig: 应用配置,定义在构建时确定的公共变量,如:theme
    • 配置会和 app.config.ts 的配置合并(优先级 app.config.ts > appConfig)
  • app:app配置
    • head:给每个页面上设置head信息,也支持 useHead 配置和内置组件。
  • ssr:指定应用渲染模式
  • router:配置路由相关的信息,比如在客户端渲染可以配置hash路由
  • alias:路径的别名,默认已配好
  • modules:配置Nuxt扩展的模块,比如:@pinia/nuxt @nuxt/image
  • routeRules:定义路由规则,可更改路由的渲染模式或分配基于路由缓存策略(公测阶段)

builder:可指定用 vite 还是 webpack来构建应用,默认是vite。如切换为 webpack 还需要安装额外的依赖。

image-20240911152122061

image-20240911152127865

image-20240911152140048

应用配置(app.config)

Nuxt 3 提供了一个 app.config.ts 应用配置文件,用来定义在构建时确定的公共变量,例如:

  • 网站的标题、主题色 以及任何不敏感的项目配置

app.config.ts 配置文件中的选项不能使用env环境变量来覆盖,与 runtimeConfig 不同

不要将秘密或敏感信息放在 app.config.ts 文件中,该文件是客户端公开

image-20240911152203241

image-20240911152210475

runtimeConifg vs app.config

runtimeConfig 和 app.config都用于向应用程序公开变量。要确定是否应该使用其中一种,以下是一些指导原则:

  • runtimeConfig:定义环境变量,比如:运行时需要指定的私有或公共token。
  • app.config:定义公共变量,比如:在构建时确定的公共token、网站配置。

image-20240911152223144

Nuxt3 内置组件

Nuxt3 框架也提供一些内置的组件,常用的如下:

  • SEO组件: Html、Body、Head、Title、Meta、Style、Link、NoScript、Base
  • NuxtWelcome:欢迎页面组件,该组件是 @nuxt/ui的一部分
  • NuxtLayout:是 Nuxt 自带的页面布局组件
  • NuxtPage:是 Nuxt 自带的页面占位组件
    • 需要显示位于目录中的顶级或嵌套页面 pages/
    • 是对 router-view 的封装
  • ClientOnly:该组件中的默认插槽的内容只在客户端渲染
    • 而fallback插槽的内容只在服务器端渲染
  • NuxtLink:是 Nuxt 自带的页面导航组件
    • 是 Vue Router<RouterLink>组件 和 HTML<a>标签的封装。
  • 等等

image-20240911152238668

image-20240911152244584

全局样式

编写全局样式步骤

  • 1.在assets中编写全局样式,比如:globel.scss
  • 2.接着在nuxt.config中的css选项中配置
  • 3.接着执行npm i –D sass 即可

image-20240911152256548

定义全局变量步骤

  • 1.在assets中编写全局样式变量,比如:_colors.scss
  • 2.接着在nuxt.config中的vite选项中配置
  • 3.然后就可以在任意组件中或scss文件中直接使用全局变量

image-20240911152307778

image-20240911152315707

资源的导入

public目录

  • 用作静态资产的公共服务器,可在应用程序上直接通过 URL 直接访问
  • 比如:引用public/img/ 目录中的图像文件
    • 在静态 URL 中可用 /img/nuxt.png,如右图
    • 静态的URL也支持在背景中使用

image-20240911152332273

assets目录

  • assets经常用于存放如样式表、字体或 SVG的资产
  • 可以使用 ~/assets/ 路径引用位于assets目录中的资产文件
  • ~/assets/ 路径也支持在背景中使用

image-20240911152339337

字体图标

字体图标使用步骤

  • 1、将字体图标存放在assets目录下
  • 2、字体文件可以使用 ~/assets/ 路径引用。
  • 3、在nuxt.config配置文件中导入全局样式
  • 4、在页面中就可以使用字体图标了

image-20240911152352624

新建页面

Nuxt项目中的页面是在 pages目录 下创建的

在pages目录创建的页面,Nuxt会根据该页面的目录结构和其文件名来自动生成对应的路由。

页面路由也称为文件系统路由器(file system router),路由是Nuxt的核心功能之一

新建页面步骤

  • 1.创建页面文件,比如: pages/index.vue
  • 2.将<NuxtPage />内置组件添加到 app.vue
  • 3.页面如果使用scss那么需要安装:npm i sass -D

image-20240911152411388

命令快速创建页面

  • npx nuxi add page home # 创建home页面
  • npx nuxi add page detail/[id] # 创建detail页面
  • npx nuxi add page user-[role]/[id] # 创建user页面

image-20240911152419264

<NuxtLink>是Nuxt内置组件,是对 RouterLink 的封装,用来实现页面的导航。

  • 该组件底层是一个<a>标签,因此使用 a + href 属性也支持路由导航
  • 但是用a标签导航会有触发浏览器默认刷新事件,而 NuxtLink 不会,NuxtLink还扩展了其它的属性和功能

应用Hydration后(已激活,可交互),页面导航会通过前端路由来实现。这可以防止整页刷新

当然,手动输入URL后,点击刷新浏览器也可导航,这会导致整个页面刷新

NuxtLink 组件属性:

  • to:支持路由路径、路由对象、URL
  • href:to的别名
  • activeClass:激活链接的类名
  • target:和a标签的target一样,指定何种方式显示新页面
  • 等等

image-20240911152433425

编程导航 (一)

Nuxt3除了可以通过<NuxtLink>内置组件来实现导航,同时也支持编程导航:navigateTo 。

通过编程导航,在应用程序中就可以轻松实现动态导航了,但是编程导航不利于SEO。

navigateTo 函数在服务器端和客户端都可用,也可以在插件、中间件中使用,也可以直接调用以执行页面导航,例如:

  • 当用户触发该goToProfile()方法时,我们通过navigateTo函数来实现动态导航。
  • 建议: goToProfile方法总是返回 navigateTo 函数(该函数不需要导入)或 返回异步函数

navigateTo( to , options) 函数:

  • to: 可以是纯字符串 或 外部URL 或 路由对象,如右图所示:
  • options: 导航配置,可选
    • replace:默认为false,为true时会替换当前路由页面
    • external:默认为false,不允许导航到外部连接,true则允许
    • 等等

image-20240911152444836

编程导航(二)

Nuxt3z中的编程导航除了可以通过 navigateTo 来实现导航,同时也支持 useRouter ( 或 Options API 的 this.$router )

useRouter常用的API

  • back:页面返回,和 一样 router.go(-1)
  • forward:页面前进,同 router.go(1)
  • go:页面返回或前进,如 router.go(-1) or router.go(1)
  • push:以编程方式导航到新页面。建议改用 navigateTo 。支持性更好
  • replace:以编程方式导航到新页面,但会替换当前路由。建议改用 navigateTo 。支持性更好
  • beforeEach:路由守卫钩子,每次导航前执行(用于全局监听)
  • afterEach:路由守卫钩子,每次导航后执行(用于全局监听)
  • .....

image-20240911152500451

动态路由

Nuxt3 和 Vue一样,也是支持动态路由的,只不过在Nuxt3中,动态路由也是根据目录结构和文件的名称自动生成。

动态路由语法:

  • 页面组件目录 或 页面组件文件都 支持 [ ] 方括号语法
  • 方括号里编写动态路由的参数。

例如,动态路由 支持如下写法:

  • pages/detail/[id].vue -> /detail/:id
  • pages/detail/user-[id].vue -> /detail/user-:id
  • pages/detail/[role]/[id].vue -> /detail/:role/:id
  • pages/detail-[role]/[id].vue -> /detail-:role/:id

注意事项:

  • 动态路由 和 index.vue 不能同时存在, Next.js则可以

image-20240911152514589

image-20240911152523455

路由参数

动态路由参数

  • 1.通过 [] 方括号语法定义动态路由,比如:/detail/[id].vue
  • 2.页面跳转时,在URL路径中传递动态路由参数,比如:/detail/10010
  • 3.目标页面通过 route.params 获取动态路由参数

查询字符串参数

  • 1.页面跳转时,通过查询字符串方式传递参数,比如:/detail/10010?name=liujun
  • 2.目标页面通过 route.query 获取查询字符串参数

image-20240911152536137

404 Page

捕获所有不配路由(即 404 not found 页面)

  • 通过在方括号内添加三个点 ,如:[...slug].vue 语法,其中slug可以是其它字符串。
  • 除了支持在 pages根目录下创建,也支持在其子目录中创建。
  • Nuxt3正式版不支持404.vue页面了,以前的候选版是支持的404.vue,但是Next.js是支持。

image-20240911152549514

路由匹配规则

路由匹配需注意的事项

  • 预定义路由优先于动态路由,动态路由优先于捕获所有路由。请看以下示例:
    • 1.预定义路由:pages/detail/create.vue ➢ 将匹配 /detail/create
    • 2.动态路由:pages/detail/[id].vue ➢ 将匹配/detail/1, /detail/abc 等。 ➢ 但不匹配 /detail/create 、/detail/1/1、/detail/ 等
    • 3.捕获所有路由:pages/detail/[...slug].vue ➢ 将匹配 /detail/1/2, /detail/a/b/c 等。 ➢ 但不匹配 /detail 等

嵌套路由

Nuxt 和 Vue一样,也是支持嵌套路由的,只不过在Nuxt中,嵌套路由也是根据目录结构和文件的名称自动生成。

编写嵌套路由步骤:

  • 1.创建一个一级路由,如:parent.vue
  • 2.创建一个与一级路由同名同级的文件夹,如: parent
  • 3.在parent文件夹下,创建一个嵌套的二级路由
    • 如:parent/child.vue, 则为一个二级路由页面
    • 如: parent/index.vue 则为二级路由默认的页面
  • 4.需要在parent.vue中添加 NuxtPage 路由占位

image-20240911152609332

image-20240911152614587

路由中间件(middleware)

Nuxt 提供了一个可定制的 路由中间件,用来监听路由的导航,包括:局部和全局监听(支持再服务器和客户端执行)

路由中间件分为三种:

  • 匿名(或内联)路由中间件
    • 在页面中使用 definePageMeta 函数定义,可监听局部路由。当注册多个中间件时,会按照注册顺序来执行。
  • 命名路由中间件
    • 在 middleware 目录下定义,并会自动加载中间件。命名规范 kebab-case)
  • 全局路由中间件(优先级比前面的高,支持两端)
    • 在middleware 目录中,需带.global后缀的文件,每次路由更改都会自动运行。

image-20240911152633942

image-20240911152645202

路由验证( validate )

Nuxt支持对每个页面路由进行验证,我们可以通过definePageMeta中的validate属性来对路由进行验证。

  • validate属性接受一个回调函数,回调函数中以 route 作为参数
  • 回调函数的返回值支持:
    • 返回 bool 值来确定是否放行路由 ➢ true 放行路由 ➢ false 默认重定向到内置的 404 页面
    • 返回对象 ➢ { statusCode:401 } // 返回自定义的 401 页面,验证失败

路由验证失败,可以自定义错误页面:

  • 在项目根目录(不是pages目录)新建 error.vue

image-20240911152705706

image-20240911152656539

布局(Layout)

Layout布局是页面的包装器,可以将多个页面共性东西抽取到 Layout布局 中。

  • 例如:每个页面的页眉和页脚组件,这些具有共性的组件我们是可以写到一个Layout布局中。

Layout布局是使用<slot>组件来显示页面中的内容

Layout布局有两种使用方式:

  • 方式一:默认布局
    • 在layouts目录下新建默认的布局组件,比如:layouts/default.vue
    • 然后在app.vue中通过<NuxtLayout>内置组件来使用
  • 方式二:自定义布局(Custom Layout)
    • 继续在layouts文件夹下新建 Layout 布局组件,比如: layouts/custom-layout.vue
    • 然后在app.vue中给<NuxtLayout>内置组件 指定name属性 的值为:custom-layout ➢ 也支持在页面中使用 definePageMeta 宏函数来指定 layout 布局

image-20240911152717550

渲染模式

浏览器 和 服务器都可以解释 JavaScript 代码,都可以将 Vue.js 组件呈现为 HTML 元素。此过程称为渲染。

  • 在客户端将 Vue.js 组件呈现为 HTML 元素,称为:客户端渲染模式
  • 在服务器将 Vue.js 组件呈现为 HTML 元素,称为:服务器渲染模式

而Nuxt3是支持多种渲染模式,比如:

  • 客户端渲染模式(CSR): 只需将 ssr 设置为 false
  • 服务器端渲染模式(SSR):只需将 ssr 设置为 true
  • 混合渲染模式(SSR | CSR | SSG | SWR):需在 routeRules 根据每个路由动态配置渲染模式(beta版本)

image-20240911152730827

image-20240911152738420

Nuxt插件(Plugins)

Nuxt3支持自定义插件进行扩展,创建插件有两种方式:

  • 方式一:直接使用 useNuxtApp() 中的 provide(name, vlaue) 方法直接创建,比如:可在App.vue中创建
    • useNuxtApp 提供了访问 Nuxt 共享运行时上下文的方法和属性(两端可用):provide、hooks、callhook、vueApp等
  • 方式二:在 plugins 目录中创建插件(推荐)
    • 顶级和子目录index文件写的插件会在创建Vue应用程序时会自动加载和注册
    • .server 或 .client 后缀名插件,可区分服务器端或客户端,用时需区分环境

在 plugins 目录中创建插件

  • 1.在 plugins 目录下创建 plugins/price.ts 插件
  • 2.接着 defineNuxtPlugin 函数创建插件,参数是一个回调函数
  • 3.然后在组件中使用 useNuxtApp() 来拿到插件中的方法

注意事项:

  • 插件注册顺序可以通过在文件名前加上一个数字来控制插件注册的顺序
    • 比如:plugins/1.price.ts 、plugins/2.string.ts、plugins/3.date.ts

image-20240911152752332

image-20240911152802298

App Lifecycle Hooks

监听App的生命周期的Hooks:

  • App Hooks 主要可由 Nuxt 插件 使用 hooks 来监听 生命周期,也可用于 Vue 组合 API 。
  • 但是,如在组件中编写hooks来监听,那 create和setup hooks就监听不了,因为这些hooks已经触发完了监听。

语法:nuxtApp.hook(app:created, func)

image-20240911152822455

组件生命周期

客户端渲染

image-20240911152833536

服务器端渲染

  • beforeCreate -> setup
  • created

image-20240911152844344

获取数据

在Nuxt中数据的获取主要是通过下面4个函数来实现(支持Server和Client ):

  • 1.useAsyncData(key, func):专门解决异步获取数据的函数,会阻止页面导航。
    • 发起异步请求需用到 $fetch 全局函数(类似Fetch API) ➢ $fetch(url, opts)是一个类原生fetch的跨平台请求库
  • 2.useFetch(url, opts):用于获取任意的URL地址的数据,会阻止页面导航
    • 本质是 useAsyncData(key, () => $fetch(url, opts)) 的语法糖。
  • 3.useLazyFetch(url, opts):用于获取任意URL数据,不会阻止页面导航
    • 本质和 useFetch 的 lazy 属性设置为 true 一样
  • 4.useLazyAsyncData(key, func):专门解决异步获取数据的函数。 不会阻止页面导航
    • 本质和useAsyncData的lazy属性设置为true一样

注意事项:

  • 这些函数只能用在 setup or Lifecycle Hooks 中。

image-20240911152857560

image-20240911152903030

image-20240911152908081

useFetch vs axios

获取数据Nuxt推荐使用 useFetch 函数,为什么不是 axios ?

  • useFetch 底层调用的是$fetch函数,该函数是基于unjs/ohmyfetch请求库,并与原生的Fetch API有者相同API
  • unjs/ohmyfetch 是一个跨端请求库: A better fetch API. Works on node, browser and workers
    • 如果运行在服务器上,它可以智能的处理对 API接口的直接调用。
    • 如果运行在客户端行,它可以对后台提供的 API接口 正常的调用(类似 axios),当然也支持第三方接口的调用
    • 会自动解析响应和对数据进行字符串化
  • useFetch 支持智能的类型提示和智能的推断 API 响应类型。
  • 在setup中用useFetch获取数据,会减去客户端重复发起的请求。

useFetch(url, options)语法

  • 参数
    • url: 请求的路径
    • options:请求配置选项 ➢ method、query ( 别名 params )、body、headers、baseURL ➢ onRequest、 onResponse、lazy....
  • 返回值: data, pending, error, refresh

image-20240911152920968

useFetch的封装

封装useFetch步骤

  • 1.定义HYRequest类,并导出
  • 2.在类中定义request、get、post方法
  • 3.在request中使用useFetch发起网络请求
  • 4.添加TypeScript类型声明

image-20240911152934257

Server API

Nuxt3 提供了编写后端服务接口的功能,编写服务接口可以在server/api目录下编写

比如:编写一个 /api/homeinfo 接口

  • 1.在server/api目录下新建 homeinfo.ts
  • 2.接在在该文件中使用 defineEventHandler 函数来定义接口(支持 async)
  • 3.然后就可以用useFetch函数轻松调用: /api/homeinfo 接口了

image-20240911152948244

image-20240911152957461

全局状态共享

Nuxt跨页面、跨组件全局状态共享可使用 useState(支持Server和Client ):

  • useState<T>(init?: () => T | Ref<T>): Ref<T>
  • useState<T>(key: string, init?: () => T | Ref<T>): Ref<T>
  • 参数:
    • init:为状态提供初始值的函数,该函数也支持返回一个Ref类型
    • key: 唯一key,确保在跨请求获取该数据时,保证数据的唯一性。为空时会根据文件和行号自动生成唯一key
  • 返回值:Ref 响应式对象

useState 具体使用步骤如下:

  • 1.在 composables 目录下创建一个模块,如: composables/states.ts
  • 2.在states.ts中使用 useState 定义需全局共享状态,并导出
  • 3.在组件中导入 states.ts 导出的全局状态

useState 注意事项:

  • useState 只能用在 setup 函数 和 Lifecycle Hooks 中
  • useState 不支持classes, functions or symbols类型,因为这些类型不支持序列化

image-20240911153014463

Nuxt3 集成 Pinia

安装依赖

  • npm install @pinia/nuxt –-save
    • @pinia/nuxt 会处理state同步问题,比如不需要关心序列化或XSS 攻击等问题
  • npm install pinia –-save
    • 如有遇到pinia安装失败,可以添加 --legacy-peer-deps 告诉 NPM 忽略对等依赖并继续安装。或使用yarn

Nuxt 应用接入 Pinia

  • 在nuxt.config文件中添加: modules: [‘@pinia/nuxt‘] ,如下图所示:

image-20240911153027343

Pinia 使用步骤

Pinia 使用步骤:

  • 1.在store文件夹中定义一个模块,比如:store/counter.ts
  • 2.在 store/counter.ts 中使用defineStore函数来定义 store 对象
  • 3.在组件中使用定义好的 store对象

image-20240911153041827

image-20240911153047859

useState vs Pinia

Nuxt跨页面、跨组件全局状态共享,既可以使用 useState,也可以使用Pinia,那么他们有什么异同呢?

它们的共同点:

  • 都支持全局状态共享,共享的数据都是响应式数据
  • 都支持服务器端和客户端共享

但是 Pinia 比 useState 有更多的优势,比如:

  • 开发工具支持(Devtools)
    • 跟踪动作,更容易调试
    • store可以出现在使用它的组件中
    • ....
  • 模块热更换
    • 无需重新加载页面即可修改store数据
    • 在开发时保持任何现有状态
  • 插件:可以使用插件扩展 Pinia 功能
  • 提供适当的 TypeScript 支持或自动完成

项目介绍

OPPO手机商城

image-20240911153127538

项目需安装的依赖

样式

  • npm install normalize.css –save
  • npm install sass –-save-dev

Pinia

  • npm install @pinia/nuxt --save
  • npm install pinia –save --legacy-peer-deps

Element Plus

  • npm install element-plus –save
  • npm install unplugin-element-plus --save-dev

安装 Element Plus 2

Element Plus 官网:https://element-plus.org/zh-CN/guide/quickstart.html

安装 Element Plus 的具体步骤:

  • 第一步:
    • npm install element-plus --save
    • npm install unplugin-element-plus --save-dev
  • 第二步:
    • 配置Babel对EP的转译
    • 配置自动导入样式
  • 第三步:
    • 在组件中导入组件,并使用

注意事项:目前Nuxt3暂时还不支持EP组件自动导包,等后续EP的module

image-20240911153143796

image-20240911153150066

购买-阿里云服务器

阿里云服务器购买地址:https://aliyun.com/

  • 1.打开控制台
  • 2.菜单找到:云服务器 ECS
  • 3.创建我们ECS
  • 4.服务器的配置
    • CentOS 7.9 / 64
    • 2cpu 4G
  • 5.配置安全组
  • 6.系统配置,自定义密码
  • 7.确认订单,创建实例

image-20240911153202733

连接-阿里云服务器

VS Code 安装:Remote SSH 插件

image-20240911153214818

Remote SSH 连接远程服务器

image-20240911153223136

image-20240911153228309

image-20240911153233416

安装Node和PM2

安装 Node

  • yum install nodejs ( 16.17.0 )
  • yum install npm ( 8.15.0 )

认识PM2(Process Manager)

  • PM2是一个守护进程管理器, 它将帮助管理和保持你的在线应用程序
  • 更简单的理解:负责管理Node、Python等程序,并能让程序一直保持在后台运行

安装PM2

  • npm install –g pm2 ( 5.2.2 )

管理Node版本(可选)

  • npm install –g n
  • n --version # 查看版本

image-20240911153246157

image-20240911153252154

PM2 常用命令

PM2 常用命令和配置文件

image-20240911153303371

image-20240911153314104

项目打包和部署

项目打包

  • 执行 npm run build , 生成的.output文件夹就是部署产物(目前不支持中文路径)
  • 执行 npm run preview 本地预览效果

使用Node部署

  • 运行:node .output/server/index.mjs
  • 指定端口:PORT=8888 node .output/server/index.mjs
    • PORT:是动态添加的环境变量

使用PM2部署(推荐)

  • pm2 init simple # 自动生成ecosystem配置文件
  • pm2 start ecosystem.config.js # 启动应用
    • instances:指定启动实例(进程)的个数
    • exec_mode:运行的模式:cluster模式和fork模式(默认)

image-20240911153346412