在 Nuxt 中使用 AI 编程

Mar 25, 2026 · 6594 字

Nuxt 是一个基于 Vue.js 的全栈框架,可以帮助我们快速构建现代化的 Web 应用。它通过 Modules 提供了丰富的功能扩展,让我们能够非常方便地集成开箱即用的数据库、认证、API 等功能。这实际上有点类似 Java 企业级开发中常见的 Spring Boot,都是通过模块化的方式来扩展能力。但使用 Nuxt 显然是一个更轻量、更现代的方案。

相比 Next.js 等其他框架,Nuxt 对 TypeScript 的强力支持和开箱即用的体验是一个非常大的优势。Nuxt 通过 Nitro 提供的 InternalApi 类型,可以自动生成后端 API 的类型定义,然后在前端通过 $fetchuseFetch 直接获取对应类型。这样一来,后端的任何修改都能立刻反馈到前端的类型检查和报错中。

Nuxt Modules

我写项目通常会使用以下几个模块:

NuxtHub

这是其中最重要的模块之一。NuxtHub 提供了开箱即用的数据库、KV、Storage、Cache 集成方案。只需要简单地在 nuxt.config.ts 中配置

export default defineNuxtConfig({
  hub: {
    db: "postgresql",
    blob: true,
    // ...
  },
});

就可以非常快地连接到数据库、对象存储等服务。对于数据库来说,NuxtHub 内置了对 PostgreSQL、MySQL、SQLite 等数据库的支持,并且提供了统一的 API 来进行数据操作,非常方便。此外,这些配置都通过环境变量管理。

以 PostgreSQL 为例,你只需要设置 DATABASE_URL 环境变量,NuxtHub 就会自动连接到数据库,并提供一个 db 对象来进行数据操作。此外,NuxtHub 默认集成的是 Drizzle ORM,这是一个完全基于 TypeScript 的 ORM,提供了极强的类型安全和开发体验。通过 Drizzle ORM,你可以非常方便地定义数据模型、进行数据库迁移以及执行查询操作,并且所有操作都会有完整的类型提示,极大地提升开发效率和代码质量。NuxtHub 已经默认帮你配置好了 Drizzle ORM,你只需要直接在 server/db/schema.ts 中定义数据模型:

import { pgTable, serial, text } from "drizzle-orm/pg-core";

export const user = pgTable("user", {
  id: serial("id").primaryKey(),
  name: text("name").notNull(),
});

然后运行 npx nuxt db generate 就可以自动生成数据库迁移文件了,非常方便。

为什么说 NuxtHub + Drizzle ORM 非常适合 AI 编程?在前文 Harness Engineering 里我们提到,对于现在的大模型来说,模型能力已经很强,真正稀缺的是一个能让 AI 发挥能力的工程环境。使用 Drizzle ORM 时,类型会严格按照“数据库 → 后端 → 前端”的顺序流动。换句话说,我们真正实现了全链路的类型安全:从数据库 schema 定义开始,类型信息会自动流向后端 API 和前端调用,从而最大程度利用 TypeScript 的类型系统来提升开发效率和代码质量。这样一来,AI 在编写代码时,也能直接利用这些类型信息进行补全、推断和错误检查。

另外还想提一嘴,NuxtHub 在 build 阶段会尝试自动迁移数据库,所以通常不需要额外的迁移步骤。代码推送后,它会自动帮我们执行迁移。

还有就是,Drizzle ORM 的 Query API 非常好用,在 schema 中定义好关系后可以直接通过链式调用来进行复杂的查询操作。

nuxt-auth-utils

这是一个简单的认证模块,提供了开箱即用的认证方案。它支持多种认证方式,包括基于 JWT 的认证、基于 Session 的认证等,并且提供了统一的 API 来进行认证操作,非常方便。通过这个模块,我们可以快速实现用户注册、登录、权限管理等功能。

亮点是你可以编写一个 shared/types/auth.d.ts 文件:

declare module "#auth-utils" {
  interface User {
    // Add your own fields
  }

  interface UserSession {
    // Add your own fields
  }

  interface SecureSessionData {
    // Add your own fields
  }
}

export {};

这样当你在前端读取用户数据 const { user } = useUserSession() 时,你可以直接获得对应存储在 JWT 中的具体数据类型。

@nuxtjs/i18n

这是一个 i18n 国际化框架,提供了开箱即用的国际化方案。它支持多种语言翻译,并且提供了统一的 API 来进行国际化操作。读者可能会问,我们做的大部分项目可能都是单语言的,用这个模块有什么用呢?

这里其实有一个非常有意思的用法。前面提到 NuxtHub + Drizzle ORM 的时候,我们不是说要让类型定义只存在一处,然后流动起来吗?对于一些预定义的键值,特别是数据库 enum,这个思路非常有用。以下面的数据库 schema 为例:

import { pgEnum, pgTable, serial } from "drizzle-orm/pg-core";

export const userRole = pgEnum("user_role", ["admin", "editor", "viewer"]);

然后我们可以先创建一个 shared/types/db.ts 导出数据库类型给前端:

import { userRole } from "@nuxthub/db/schema";
// 注意这里一定要从 "@nuxthub/db/schema" 里导入,直接导入 "@nuxthub/db" 会导致前端把整个 Drizzle ORM 都打包进来

export const userRoleEnum = userRole.enumValues;

export type UserRole = (typeof userRoleEnum)[number];

之后创建 i18n/locales/en.json 来定义前端的显示文本:

{
  "userRole": {
    "admin": "Administrator",
    "editor": "Editor",
    "viewer": "Viewer"
  }
}

这样我们就可以在前端的选择器和展示位置直接使用这个 UserRole 类型:

<script setup lang="ts">
const items = userRoleEnum.map((value) => ({
  value,
  label: t(`userRole.${value}`),
}));
</script>

<template>
  <Select :items="items" />
</template>

通过这种方式,我们就实现了数据库 enum 类型只定义一次,再通过类型流动和国际化文本在前端复用。

@nuxt/ui

Nuxt 官方的 UI 组件库,提供了开箱即用的 UI 组件。它基于 Tailwind CSS 构建,包含丰富的组件和工具类,可以帮助我们快速构建美观的用户界面。

笔者本人其实不太喜欢 shadcn/ui 那种完全无样式的组件库。它虽然提供了极大的灵活性,但也需要自己编写大量样式代码才能实现完整界面。而 @nuxt/ui 提供了一个很好的平衡点:既有开箱即用的美观组件,也允许我们通过 Tailwind CSS 进行高度定制,非常适合在 AI 编程场景里快速构建界面。

其他

除此以外,还有一些在 Vue 生态里本来就很流行的模块,不过我暂时没有探索出特别有意思的用法,这里就不展开了,比如:

  • @vueuse/nuxt:提供了大量的实用工具函数和组合式 API,可以帮助我们更方便地进行状态管理、事件监听、动画等操作。
  • @nuxt/image:提供了开箱即用的图片优化方案,支持多种图片格式和优化策略,可以帮助我们快速实现高性能的图片加载。
  • nuxt-maplibre:MapLibre 本身是一个非常不错的开源地图解决方案,nuxt-maplibre 则是它在 Nuxt 中的集成模块,提供了开箱即用的地图组件和工具。
  • NuxtContent:主要是用来做博客的,提供了基于 Markdown 的内容管理方案。也可以写自己的数据源来从文本或代码中直接生成奇妙的页面(还在探索中)。
  • @nuxtjs/mdc:渲染 Markdown 内容的模块。mdc 的 c 是 Component 的意思,可以直接在 Markdown 中调用 Vue 组件,类似 mdx 的用法,非常适合我们在写一些文档或者博客的时候直接使用 Vue 组件来展示一些动态的内容。

Nitro

Nitro 本身也有一些比较有意思的功能。比如需要计划任务时,可以直接使用 Scheduled Tasks 来实现,不需要额外引入第三方任务调度库。

此外还有一个我以前研究的 基于内存的消息广播 功能。不过这个方案其实挺鸡肋,因为它只能在单实例中使用;如果要在分布式环境中使用,还是需要引入第三方消息队列或者 pub/sub 方案。NuxtHub 目前的 KV 只能存储,不能监听变化,也没有 Queue 功能,这点还是挺可惜的。

AGENTS.md

虽说这篇博客的名字是《在 Nuxt 中使用 AI 编程》,但其实我并没有在这篇博客里介绍太多关于 AI 编程的内容。因为我觉得 AI 编程的核心其实是一个工程环境,而不是 AI 模型本身。我们需要一个能够让 AI 发挥能力的工程环境,这个环境需要具备良好的开发体验、强大的功能扩展能力和高效的类型安全机制。而 Nuxt + NuxtHub + Drizzle ORM 就是这样一个非常适合 AI 编程的工程环境。最后,我们需要一个 AGENTS.md 来告诉 AI 如何在这个环境里编程,如何使用这些工具和模块来实现各种功能。以下是一些我觉得比较重要的点:

This project is built with nuxt4 + nuxthub + @nuxt/ui + @nuxtjs/i18n + nuxt-auth-utils, please refer to Context7 for their documentation.

- Most of the files from `vue`, `shared`, `utils`, `types` and nuxt modules are auto-imported by nuxt, you can directly use them in your code. DO NOT import them by yourself.

## Frontend

- Prioritize using components from Nuxt UI, and avoid writing too much tailwindcss yourself if not necessary.
- For error messages in Toast, add `e.data?.message || e.message` in the description to display the specific error information.

## Backend

- Authentication should use `await getUserSession(event)` and `await requireUserSession(event)` from nuxt-auth-utils.
- The backend API should be as simple as possible. Do not arbitrarily customize the Type. If there is no need, do not perform too much validation. Please use Zod to validate the request body. Don't define the zod schema, directly use `z.object({ ... }).parse(body)` to validate the request body.
- Database operations use the Drizzle ORM provided by NuxtHub. The database schema is defined in `server/db/schema.ts`. Use `import { db, schema } from "@nuxthub/db"` to access it.
- The backend directly returns the result returned by the database. For example, `return db.select().from(users).where(eq(users.id, userId))`.
- When there are multiple sub-paths under a certain path, directories should be created first, and then the `index.xxx.ts` should be used.

粤ICP备2025414119号 粤公网安备44030002006951号

© 2026 Saurlax · Powered by Astro