Vue.js 开发

Nuxt 使用 Vue.js,并添加了诸如组件自动导入、基于文件的路由以及适用于 SSR 的 composables 等功能。

Nuxt 集成了 Vue 3,这是 Vue 的新一代重大版本,为 Nuxt 用户带来了新的使用模式。

尽管并不需要对 Vue 有深入的了解才能使用 Nuxt,但我们建议你阅读文档并查看 vuejs.org 上的一些示例。

Nuxt 一直以来都以 Vue 作为前端框架。

我们选择基于 Vue 构建 Nuxt,原因如下:

  • Vue 的响应式模型:数据的变化会自动触发界面的更新。
  • 基于组件的模板系统,在保留 HTML 作为通用网页语言的同时,提供直观的模式以保持界面一致且功能强大。
  • 无论是小型项目还是大型 Web 应用,Vue 都能在规模化时保持良好性能,确保你的应用持续为用户创造价值。

Vue 与 Nuxt

单文件组件

Vue 的单文件组件(SFC 或 *.vue 文件)封装了 Vue 组件的标记(<template>)、逻辑(<script>)和样式(<style>)。Nuxt 为 SFC 提供了零配置的体验,并通过 Hot Module Replacement 提供无缝的开发者体验。

自动导入

在 Nuxt 项目的 app/components/ 目录中创建的每个 Vue 组件都会在项目中可用,无需显式导入。如果某个组件在任何地方都未被使用,生产构建将不会包含它。

Docs > Guide > Concepts > Auto Imports 中查看详情

Vue Router

大多数应用需要多个页面以及在它们之间导航的方式。这称为 路由(routing)。Nuxt 使用 app/pages/ 目录和命名约定,利用官方的 Vue Router 库 直接根据你的文件创建路由映射。

Docs > Getting Started > Routing 中查看详情
Read and edit a live example in Docs > Examples > Features > Auto Imports.

Vapor Mode

Vapor Mode 支持是实验性的,并且需要 Vue 3.6 或更高版本。API 可能会发生变化。

Vapor Mode 是 Vue 3.6 中引入的一种替代编译策略,它无需 Virtual DOM 即可渲染组件,从而降低内存使用并提升运行时性能。

Nuxt 以 interop mode 支持 Vapor Mode:你的应用仍然使用 Virtual DOM 进行渲染,你可以将单个组件或页面编写为 Vapor 单文件组件,从而选择让它们使用 Vapor。这使你能够逐步采用 Vapor,而 Nuxt 的其余部分(路由、useAsyncData、布局以及大多数内置组件)仍可保持不变地工作。

启用 Vapor Mode

在 Nuxt 配置中启用 vue.vapor 选项:

nuxt.config.ts
export default defineNuxtConfig({
  vue: {
    vapor: true,
  },
})

这会安装 Vue 的 vaporInteropPlugin,使 Vapor 和 Virtual DOM 组件能够并行渲染。然后,你可以通过向 <script setup> 添加 vapor 属性,将任意组件或页面标记为 Vapor:

app/pages/index.vue
<script setup vapor lang="ts">
const count = ref(0)
</script>

<template>
  <button @click="count++">
    count is {{ count }}
  </button>
</template>

尝试使用

Vapor Mode 需要使用同时包含 Vapor 及其 interop 修复的 Vue 版本。在 Vue 3.6 处于预发布阶段期间,请安装包含这些修复的候选版本(或更高版本):

package.json
{
  "dependencies": {
    "vue": "^3.6.0-rc.2"
  }
}

如果你在较旧版本的 Vue 上启用 vue.vapor,Nuxt 会发出警告并将其禁用。

我们建议你在全新项目中尝试 Vapor Mode,而不是将其添加到现有项目中。你也可以在 Nuxt Vapor demo 中了解一个可正常运行的配置。

已知限制

由于 Nuxt 在 interop mode 下运行 Vapor,一些依赖 Virtual DOM 的模式在 Vapor 组件中的行为会有所不同:

  • 目前还不支持完整的 Vapor 应用。 应用根节点仍使用 Virtual DOM,你可以按组件选择启用 Vapor;未来我们可能会支持完整的 Vapor 应用。
  • Vapor 组件上的 模板 ref 不会暴露 $el
  • 一些内置组件会检查其插槽内容,因此无法读取 Vapor 插槽子节点。<ClientOnly> 会跳过其属性转发 fallthrough,而 <NuxtIsland>、服务器组件以及会读取文本子节点的 head 组件(例如 <Title><Style><Noscript>)在你传入 Vapor 插槽时会发出警告。请直接传入值(例如向 <Title> 传入字符串)。
  • Vapor 组件中不支持 Options API,因此无法通过 defineNuxtComponent 使用 asyncDatafetchKey。请改用带有 useAsyncData<script setup>
  • 带键的 onPrehydrate 会回退到不带键的形式(并在开发环境中发出警告),因为没有组件实例可用于附加键。
  • Vapor <script setup> 中在 await 之后调用的 Nuxt composables 可能会丢失 Nuxt 上下文。在可能的情况下,请在第一个 await 之前调用它们。

大多数其他 Nuxt composables 和内置组件都可以保持不变地工作,因为它们依赖注入,而不是依赖组件实例。

Differences with Nuxt 2 / Vue 2

Nuxt 3+ 基于 Vue 3。新的主要 Vue 版本带来了若干变化,Nuxt 对这些变化进行了利用:

  • 更好的性能
  • 组合式 API(Composition API)
  • TypeScript 支持

更快的渲染

Vue 的虚拟 DOM(VDOM)已从头重写,从而带来更好的渲染性能。除此之外,在使用已编译的单文件组件时,Vue 编译器可以在构建时进一步优化它们,将静态和动态标记分离。

这带来了更快的首次渲染(组件创建)和更新,以及更少的内存使用。在 Nuxt 3 中,这也使得服务器端渲染更快。

更小的包体积

在 Vue 3 和 Nuxt 3 中,重点放在了减小包体积上。Vue 3 中的大部分功能,包括模板指令和内置组件,都是可进行 tree-shaking 的。如果你不使用它们,生产包将不会包含它们。

因此,一个最小的 Vue 3 应用可以被缩减到 12 kb(gzip 压缩后)。

组合式 API

在 Vue 2 中,向组件提供数据和逻辑的唯一方式是通过 Options API,它允许你通过预定义属性如 datamethods 向模板返回数据和方法:

<script>
export default {
  data () {
    return {
      count: 0,
    }
  },
  methods: {
    increment () {
      this.count++
    },
  },
}
</script>

Vue 3 中引入的 组合式 API 并不是对 Options API 的替代,而是使得在整个应用中更好地复用逻辑成为可能,并且在复杂组件中按关注点组织代码更为自然。

<script> 定义中使用 setup 关键字时,下面是上述组件用组合式 API 和 Nuxt 3 自动导入的响应式 API 重写的示例:

components/Counter.vue
<script setup lang="ts">
const count = ref(0)
const increment = () => count.value++
</script>

Nuxt 的目标是围绕组合式 API 提供出色的开发者体验。

TypeScript 支持

Vue 3 和 Nuxt 3+ 都是用 TypeScript 编写的。完整的类型化代码库可以防止错误并记录 API 的使用方式。这并不意味着你必须用 TypeScript 编写应用才能利用它。在 Nuxt 3 中,你可以通过将文件从 .js 重命名为 .ts 来选择启用,或者在组件中添加 <script setup lang="ts">

阅读关于 Nuxt 中 TypeScript 的详细信息