Nuxt3 框架实战开发介绍

521 阅读15分钟
Nuxt3 是一个基于 Vue3 的框架,它提供了一种直观且可扩展的方式来创建类型安全、高性能和生产级别的全栈 Web 应用和网站,使用的是 Vue.js。我们做了一切,让你从一开始就可以编写.vue 文件,同时在开发中享受到热模块替换的便利,并在生产中获得高性能的应用,其中默认启用了服务器端渲染。

自动化和约定

Nuxt 使用约定和一套规范的目录结构来自动化重复的任务,让开发者可以专注于推动功能的开发。配置文件仍然可以自定义和覆盖其默认行为。

  • 基于文件的路由: 根据 pages/目录的结构定义路由。这样可以更容易地组织应用程序,避免手动配置路由的需要。
  • 代码分割: Nuxt 自动将代码拆分成较小的块,这有助于减少应用程序的初始加载时间。
  • 内置服务器端渲染: Nuxt 具备内置的服务器端渲染能力,因此你不需要自己设置单独的服务器。
  • 自动导入: 在各自的目录中编写 Vue 组件和可组合函数,并在使用时无需手动导入,享受树摇和优化 JS 捆绑包的好处。
  • 数据获取工具: Nuxt 提供了可用于处理与服务器端渲染兼容的数据获取的可组合函数,以及不同的策略。
  • 零配置的 TypeScript 支持: 可以编写类型安全的代码,无需学习 TypeScript,因为我们提供了自动生成的类型和 tsconfig.json 配置文件。
  • 配置好的构建工具: 我们默认使用 Vite 来支持开发中的热模块替换(HMR),以及在生产中将代码打包成符合最佳实践的形式。

Nuxt 负责处理这些事情,并提供前端和后端功能,让你可以专注于创建你的 Web 应用

服务端渲染

Nuxt 默认具备内置的服务器端渲染(SSR)能力,无需自己配置服务器,这对于 Web 应用有许多好处:

  • 更快的初始页面加载时间: Nuxt 向浏览器发送完全渲染的 HTML 页面,可以立即显示。这可以提供更快的页面加载时间和更好的用户体验(UX),特别是在网络或设备较慢的情况下。

  • 改善 SEO: 搜索引擎可以更好地索引 SSR 页面,因为 HTML 内容立即可用,而不需要依赖 JavaScript 在客户端渲染内容。

  • 在低功率设备上的更好性能: 减少了需要在客户端下载和执行的 JavaScript 量,这对于处理重型 JavaScript 应用程序可能有困难的低功率设备非常有益。

  • 更好的可访问性: 内容在初始页面加载时立即可用,改善了依赖屏幕阅读器或其他辅助技术的用户的可访问性。

  • 更容易的缓存: 页面可以在服务器端缓存,这可以通过减少生成和发送内容所需的时间而进一步提高性能。 总体而言,服务器端渲染可以提供更快更高效的用户体验,同时改善搜索引擎优化和可访问性。

由于 Nuxt 是一个多功能的框架,它允许你将整个应用程序静态渲染为静态托管,使用 nuxt generate 进行部署, 通过 ssr: false 选项在全局禁用 SSR,或通过设置 routeRules 选项来实现混合渲染。

安装

先决条件

  1. Node.js - v18.0.0 或更新版本
  2. 文本编辑器 - 我们推荐使用 Visual Studio Code 以及 Volar 扩展
  3. 终端 - 用于运行 Nuxt 命令

创建项目

pnpm dlx nuxi@latest init <project-name>

按照依赖

pnpm install

启动项目

pnpm dev

配置

Nuxt 配置

/* eslint-disable no-undef */
import { resolve } from "path";
export default defineNuxtConfig({
  devtools: { enabled: true },
  runtimeConfig: {
    apiKey: process.env.NUXT_API_KEY,
    public: {
      baseURL: process.env.NUXT_PUBLIC_BASE_URL,
    },
  },
  app: {
    head: {
      title: "Nuxt3-Vite",

      meta: [
        {
          name: "这是一个nuxt3的服务端渲染项目",
          content: "width=device-width, initial-scale=1",
        },
        {
          charset: "utf-8",
        },
      ],
      link: [],
      style: [],
      script: [],
      noscript: [],
    },
  },
  modules: ["@nuxt/content", "@nuxtjs/i18n", "@pinia/nuxt"], // 启动项目的时候提前进行预加载某些模块,开发模式下优化编译效率
  i18n: {
    vueI18n: "./i18n.config.ts",
  },
  alias: {
    "@": resolve(__dirname, ""),
  },
  css: ["@/assets/main.scss"],
  ssr: true, //默认为true,表示服务端渲染,false表示客户端渲染
  postcss: {
    plugins: {
      tailwindcss: {},
      autoprefixer: {},
    },
  },
});

环境变量和私有令牌

runtimeConfig API 将像环境变量这样的值暴露给应用程序的其余部分。默认情况下,这些键只在服务器端可用。runtimeConfig.public 中的键也可以在客户端使用。 这些值应该在 nuxt.config 中定义,并可以使用环境变量进行覆盖。

image.png

image-1.png

应用程序配置

app.config.ts 文件位于源目录中(默认为项目的根目录),用于公开在构建时确定的公共变量。与 runtimeConfig 选项不同,这些变量不能使用环境变量进行覆盖。等等相关配置

image-3.png

vue 配置

使用 Vite

image-4.png

使用 Webpack

export default defineNuxtConfig({
  webpack: {
    loaders: {
      vue: {
        hotReload: true,
      },
    },
  },
});

视图

app.vue

默认情况下,Nuxt 将把这个文件视为入口点,并为应用程序的每个路由渲染其内容

<template>
  <div>
    <h1>欢迎来到首页</h1>
  </div>
</template>
 如果你熟悉 Vue,你可能会想知道 main.js 在哪里(通常用于创建 Vue应用的文件)。Nuxt 在幕后完成了这个操作。

组件

大多数组件是可重用的用户界面部件,如按钮和菜单。在 Nuxt 中,你可以在 components/ 目录中创建这些组件,它们将自动在整个应用程序中可用,无需显式地导入。

// app.vue
<template>
  <NuxtLayout>
    <NuxtPage />
  </NuxtLayout>
</template>

<script setup>
const config = useRuntimeConfig()
console.log(config.public.baseURL, '======config.public=====')
// const color = useColor()
// const a = 98754554
// const route = useUtils()
// console.log(route)
</script>

// components/AppAlert.vue
<template>
  <div class="active">这个是一个弹窗组件</div>
</template>

<script setup></script>
<style scoped lang="scss">
.active {
  animation: alert 1s ease-in-out;
}
</style>


布局

布局是页面的包装器,包含了多个页面的共同用户界面,如页眉和页脚。布局是使用 <slot /> 组件来显示页面内容的 Vue 文件。layouts/default.vue 文件将被默认使用。自定义布局可以作为页面元数据的一部分进行设置。

image-5.png

//app.vue
<template>
  <NuxtLayout>
    <NuxtPage />
  </NuxtLayout>
</template>

//layouts/default.vue
<template>
  <div>
    <p>default layout</p>
    <slot />
  </div>
</template>

// layouts/custom.vue
<template>
 <p>自定义布局</p>
  <slot />
</template>

pages

创建 pages 目录,里面的 view 页面会根据路径生成路由(根据路径,还有 id 其他的明命名),无需要要配置路由

image-6.png

image-7.png

资源

Nuxt 使用两个目录来处理样式表、字体或图片等资源。

  • public/ 目录中的内容会按原样作为服务器根目录下的公共资源提供。
  • assets/ 目录按约定包含了你希望构建工具(Vite 或 webpack)处理的所有资源。

公共目录

public/ 目录用作应用程序的公共服务器,用于存放在应用程序的指定 URL 下公开访问的静态资源。你可以通过应用程序的代码或浏览器的根 URL / 获取 public/ 目录中的文件。

<template>
  <img src="/img/nuxt.png" alt="Discover Nuxt 3" />
</template>

资源目录

Nuxt 使用 Vite(默认)或 webpack 来构建和打包你的应用程序。这些构建工具的主要功能是处理 JavaScript 文件,但它们可以通过 插件(对于 Vite)或 加载器(对于 webpack)来处理其他类型的资源,如样式表、字体或 SVG。此步骤主要是为了提高性能或缓存目的而对原始文件进行转换(例如样式表的缩小或浏览器缓存失效)

按照约定,Nuxt 使用 assets/ 目录来存储这些文件,但该目录没有自动扫描功能,你可以使用任何其他名称。 在应用程序的代码中,你可以通过使用 ~/assets/ 路径来引用位于 assets/ 目录中的文件。

<template>
  <img src="~/assets/img/nuxt.png" alt="Discover Nuxt 3" />
</template>

全局样式导入

要在你的 Nuxt 组件样式中全局插入语句,你可以在 nuxt.config 文件中使用 Vite 选项。

export default defineNuxtConfig({
  vite: {
    css: {
      preprocessorOptions: {
        sass: {
          additionalData: '@use "@/assets/colors.sass" as *',
        },
      },
    },
  },
});

样式化

在样式化方面,Nuxt 非常灵活。你可以编写自己的样式,或者引用本地和外部样式表。 你可以使用 CSS 预处理器、CSS 框架、UI 库和 Nuxt 模块来为你的应用程序添加样式。

本地样式表

如果你正在编写本地样式表,将它们放在 assets/ 目录 是最自然的位置。

在组件中引入

你可以在页面、布局和组件中直接引入样式表。 你可以使用 JavaScript 的 import,或者使用 css 的 @import 语句。

<script>
  // 使用静态导入以实现服务器端兼容性
  import "~/assets/css/first.css";

  // 注意:动态导入不兼容服务器端
  import("~/assets/css/first.css");
</script>

<style>
  @import url("~/assets/css/second.css");
</style>

全局引入

你还可以使用 Nuxt 配置中的 css 属性。 将你的样式表放在 assets/ 目录 是最自然的位置。然后你可以引用它的路径,Nuxt 将会将它包含在应用程序的所有页面中。

export default defineNuxtConfig({
  css: ["~/assets/css/main.css"],
});

外部样式表

你可以通过在 nuxt.config 文件的 head 部分添加一个 link 元素来在应用程序中包含外部样式表。你可以使用不同的方法来实现这个目标。注意,本地样式表也可以以这种方式包含。你可以通过 Nuxt 配置的 app.head 属性来修改 head:

export default defineNuxtConfig({
  app: {
    head: {
      link: [
        {
          rel: "stylesheet",
          href: "https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css",
        },
      ],
    },
  },
});

路由

Nuxt 文件系统路由为pages/目录中的每个文件创建一个路由,Nuxt 的核心功能之一是文件系统路由。pages/目录中的每个 Vue 文件都会创建一个相应的 URL(或路由),用于显示文件的内容。通过为每个页面使用动态导入,Nuxt 利用代码分割来仅加载所需路由的最小量 JavaScript。

页面

nuxt 内部自动生成路由

image-8.png

导航和路由参数

导航

image-9.png

路由参数

image-10.png

路由中间件

Nuxt 提供了一个可自定义的路由中间件框架,您可以在应用程序中使用,非常适合提取在导航到特定路由之前要运行的代码。类似路由守卫。

路由中间件在Nuxt应用程序的Vue部分中运行。尽管名称相似,但它们与在应用程序的Nitro服务器部分中运行的服务器中间件完全不同。

有三种类型的路由中间件:

  • 匿名(或内联)路由中间件,直接在使用它们的页面中定义。
    definePageMeta({
      middleware: [
        function (to, from) {
          // 自定义内联中间件
        },
      ],
    });
    
  • 命名路由中间件,放置在 middleware/目录中,当在页面中使用时,会通过异步导入自动加载。(注意:路由中间件名称会转换为短横线分隔命名,因此 someMiddleware 会变成 some-middleware。)

image-12.png

image-13.png

  • 全局路由中间件,放置在 middleware/目录中(使用.global 后缀),将在每次路由更改时自动运行。

image-11.png

中间件执行顺序:

  1. 全局中间件(默认情况下,全局中间件按照文件名的字母顺序执行,在这种情况下,我们建议在全局中间件的前面加上“字母”编号)
    middleware/
    01.setup.global.ts
    02.analytics.global.ts
    auth.ts

2. 页面定义的中间件顺序(如果使用数组语法声明了多个中间件)

路由验证

Nuxt 通过每个要验证的页面中的 definePageMeta()的 validate 属性提供路由验证,validate 属性接受 route 作为参数。您可以返回一个布尔值来确定是否将此路由视为有效路由以渲染此页面。如果返回 false,并且找不到其他匹配项,这将导致 404 错误。您还可以直接返回一个带有 statusCode/statusMessage 的对象以立即响应错误(其他匹配项将不会被检查)。

<script setup lang="ts">
definePageMeta({
  validate: async (route) => {
    // 检查id是否由数字组成
    return /^\d+$/.test(route.params.id)
  }
})
</script>


SEO 和 Meta

默认值

在你的 nuxt.config.ts 文件中提供 app.head 属性,可以自定义整个应用的头部。

image-14.png

useHead

你可以使用 useHead 函数来设置每个页面的标题、描述、关键字、图标、meta 标签等。

image-15.png

数据获取

useFetch、useAsyncData 和 $fetch

Nuxt 提供了两个组合函数和一个内置库,用于在浏览器或服务器环境中执行数据获取:useFetch、useAsyncData 和 $fetch。

useFetch 和 useAsyncData 共享一组常见的选项和模式,useFetch 和 useAsyncData 组合函数确保一旦在服务器上进行了 API 调用,数据将以有效的方式在负载中传递到客户端。避免网络请求重复,但是$fetch 会在客户端和服务端都进行请求,所以初始化的时候慎用!!!

useFetch(url) 几乎等同于 useAsyncData(url, () => $fetch(url)) - 它是为最常见的用例提供的开发者体验糖。

总结:尽量使用 useFetch,可对 useFetch 进行二次封装,作为统一的网络请求方法。

uselazyFetch、useLazyAsyncData

默认情况下,useFetch 在其异步处理程序解析之前会阻止导航。useLazyFetch 提供了一个包装器,将 useFetch 包装起来,通过将 lazy 选项设置为 true 来在处理程序解析之前触发导航.

//使用第一种方法,这样不会阻塞导航
// const { data, pending } = await useFetch('/api/hello', {
//   lazy: true
// })
//使用第二种方法,这样不会阻塞导航
const { data, pending } = await useLazyFetch("/api/hello");

状态管理

  1. 少部分状态管理,使用useState Nuxt 提供了强大的状态管理库和 useState 组合函数,用于创建响应式且适用于 SSR 的共享状态。

image-18.png

image-19.png

image-20.png

  1. 大多数状态管理,则可以考虑使用第三方库 Pinia

image-21.png

image-22.png

image-23.png

错误处理

Nuxt 3 是一个全栈框架,这意味着在不同的上下文中可能会发生几种无法预防的用户运行时错误:

  • Vue 渲染生命周期中的错误(SSR 和 CSR)
  • Nitro 服务器生命周期中的错误(server/ 目录)
  • 服务器和客户端启动错误(SSR + CSR)
  • 下载 JS chunk 时出错

Vue 渲染生命观周期错误

你可以使用 onErrorCaptured 来捕获 Vue 错误。此外,Nuxt 还提供了一个 vue:error 钩子,如果有任何错误传播到顶层,将会调用该钩子。如果你使用的是错误报告框架,你可以通过 vueApp.config.errorHandler 提供一个全局处理程序。它将接收所有的 Vue 错误,即使这些错误已经被处理。

export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.vueApp.config.errorHandler = (error, instance, info) => {
    // 处理错误,例如上报到一个服务
    console.log(error);
  };
  // 也可以这样
  //   nuxtApp.hook('vue:error', (error, instance, info) => {
  //     // 处理错误,例如上报到一个服务
  //   })
});

启动错误

如果启动 Nuxt 应用时出现任何错误,Nuxt 将会调用 app:error 钩子。

这包括:

  • 运行 Nuxt 插件
  • 处理 app:created 和 app:beforeMount 钩子
  • 将你的 Vue 应用渲染为 HTML(在 SSR 期间)
  • 挂载应用程序(在客户端),不过你应该使用 onErrorCaptured 或 vue:error 来处理这种情况
  • 处理 app:mounted 钩子

Nitro 服务器生命周期、JS chunk 错误、错误页面、错误工具、在组件中渲染错误就不一一列举了。

服务器

Nuxt 的服务器框架允许你构建全栈应用程序。例如,你可以从数据库或其他服务器获取数据,创建 API,甚至生成静态的服务器端内容,如站点地图或 RSS 订阅源 - 一切都可以从单一代码库中完成.

由 Nitro 驱动

Nuxt 的服务器使用的是 Nitro。Nitro 最初是为 Nuxt 创建的,但现在是 UnJS 的一部分,也被其他框架使用 - 甚至可以单独使用。 使用 Nitro 给予 Nuxt 超能力:

  1. 对应用程序的服务器端部分拥有完全控制权
  2. 在任何提供者上进行通用部署(许多无需配置)
  3. 渲染

对应用程序的服务器端部分拥有完全控制权

使用 Nitro,你可以轻松管理 Nuxt 应用程序的服务器部分,从 API 端点到中间件。Nitro 默认支持热模块替换和自动导入,就像 Nuxt 应用程序的其他部分一样。

  1. 定义 API
  2. 服务器路由
  3. 服务器中间件
  4. 服务器插件

image-24.png

渲染

Nuxt 支持不同的渲染模式,包括通用渲染,客户端渲染,还提供了混合渲染和在 CDN 边缘服务器上渲染应用程序的可能性。 浏览器和服务器都可以解释 JavaScript 代码,将 Vue.js 组件转换为 HTML 元素。这个过程被称为渲染。Nuxt 同时支持通用渲染和客户端渲染。默认情况下,Nuxt 使用通用渲染以提供更好的用户体验、性能优化和搜索引擎索引优化,但你可以在一行配置中切换渲染模式。

通用渲染

当浏览器请求启用了通用(服务器端+客户端)渲染的 URL 时,服务器将一个完整渲染的 HTML 页面返回给浏览器,这一步是传统服务端渲染 php 或者 jsp 等等的方式。但是客户端(浏览器)在下载完 HTML 文档后会在后台加载运行在服务器上的 JavaScript 代码。浏览器再次解释它。激活为 SPA,在浏览器中使静态页面具有交互性被称为“水合”,通用渲染使 Nuxt 应用程序能够快速加载页面,同时保留了客户端渲染的好处。此外,由于内容已经存在于 HTML 文档中,爬虫可以在没有额外开销的情况下对其进行索引.

image-25.png

image-26.png

image-27.png

比如:掘金 小米商城 华为云

9f70b13879cfd0944de4d9e4c0e5274.png

642f0fb70d26c5dcb43f6b2afca89f2.png

客户端渲染

传统的 Vue.js 应用程序默认在浏览器(或客户端)中进行渲染。然后,Vue.js 在浏览器下载和解析所有包含创建当前界面指令的 JavaScript 代码后,生成 HTML 元素。

image-28.png

image-29.png

image-30.png

部署

  1. 根据环境变量配置进行文件打包,生成 output 文件

image-31.png

  1. 全局安装 PM2 使用 PM2 启动 配置 ecosystem.config.js
npm install pm2 -g

module.exports = {
  apps: [
    {
      name: "nuxt3",
      script: "./.output/server/index.mjs",
      instances: "max",
      exec_mode: "cluster", //  Node.js 的 cluster集群模块来提高多进程性能
    },
  ],
};
  1. 启动脚本

image-32.png

  1. 启动

image.png 5.启动后访问 localhost:300

image.png

6.安装 docker,可在 docker 容器中配置 pm2,启动 nuxt 应用

总结(参考 nuxt.com.cn/ nuxt3 中文官方文档)