Zademy

我的新宠技术栈 Nuxt 4 Nuxt UI MongoDB 和 Quarkus

Development
Nuxt; MongoDB; Quarkus
words 字

我最近把主力技术栈换成了 Nuxt 4 + Nuxt UI + MongoDB + Quarkus,用了一段时间之后觉得值得写一篇完整的分享。

选这个组合的原因不复杂:原型快,生产性能扛得住,每个组件的文档都过关,社区活跃,而且从简单 API 到复杂系统都能覆盖。下面逐个说。

Nuxt 4:Vue 生态的又一次进化

2025 年 7 月 15 日发布的 Nuxt 4,重心放在稳定性和 DX 上。不是那种大张旗鼓的破坏性升级,而是把过去一年在小版本里验证过的东西变成默认值。

项目组织

新的目录结构把应用代码统一放在 app/ 下,和 node_modules/、.git/ 分离。效果是文件监视器更快了(Windows 和 Linux 上尤其明显),IDE 的上下文判断也更准。

my-app/
 ├─ app/
 │  ├─ assets/
 │  ├─ components/
 │  ├─ pages/
 │  └─ app.vue
 ├─ shared/
 ├─ server/
 └─ nuxt.config.ts

能感知到的性能提升

Turbo 模式构建速度快达 10 倍。服务器冷启动从 Nuxt 3 的 ~2.3s 降到 ~1.1s,砍掉了 52%。CLI 和 Vite 开发服务器之间走 socket 通信,网络端口开销没了。原生 edge server 让你在离用户最近的地方跑应用,延迟压到最低。

数据获取

useAsyncData 和 useFetch 现在自动在使用相同 key 的组件之间共享数据,卸载时自动清理,缓存控制也更灵活了。

// 优化的数据获取示例
const { data: products } = await useAsyncData(
  'products',
  () => $fetch('/api/products'),
  {
    server: true,
    default: () => [],
    transform: (data) => data.map(p => ({...p, formattedPrice: formatCurrency(p.price)}))
  }
)

Nuxt UI v4:免费的专业设计

2025 年 9 月发布的 Nuxt UI v4 把之前的 Nuxt UI 和 Nuxt UI Pro 合成了一个 MIT 许可的开源库。以前要花钱才能用的 Pro 组件,现在全免费。

110 多个生产就绪组件,覆盖了表单(输入框、选择框、复选框、单选框)、导航(菜单、面包屑、分页)、布局(卡片、模态框、侧边栏、手风琴)、数据展示(表格、列表、网格)和反馈(提示框、警报、进度条、骨架屏)。日常项目需要的组件基本不缺了。

底层选得也好。Tailwind CSS v4 构建快 5 倍。Reka UI 保证 WAI-ARIA 合规,无障碍性不用自己操心。Tailwind Variants 提供完整的 TypeScript 类型和主题系统。

实际示例

<template>
  <UContainer class="py-8">
    <UCard>
      <template #header>
        <h1 class="text-2xl font-bold">用户管理</h1>
      </template>
      
      <UTable :rows="users" :columns="columns">
        <template #actions-data="{ row }">
          <UButton
            icon="i-heroicons-pencil"
            size="sm"
            color="primary"
            variant="ghost"
            @click="edit(row)"
          />
        </template>
      </UTable>
      
      <template #footer>
        <div class="flex justify-between items-center">
          <span class="text-sm text-gray-500">
            {{ users.length }} users found
          </span>
          <UPagination
            v-model="page"
            :total="total"
            :page-count="10"
          />
        </div>
      </template>
    </UCard>
  </UContainer>
</template>

<script setup lang="ts">
const users = ref([])
const page = ref(1)
const total = ref(100)

const columns = [
  { key: 'name', label: 'Name' },
  { key: 'email', label: 'Email' },
  { key: 'role', label: 'Role' },
  { key: 'actions', label: 'Actions' }
]

async function loadUsers() {
  const { data } = await useFetch('/api/users', {
    query: { page: page.value }
  })
  users.value = data.value
}
</script>

MongoDB:灵活的数据层

MongoDB 的 JSON 文档模型和 JavaScript/TypeScript 天然契合,这是它对我最大的吸引力。不需要在语言之间做思维转换。

schema 可以随需求演进,不用写复杂的 migration。对需求频繁变化的快速原型、半结构化数据、迭代频繁的敏捷开发来说,这一点省了很多痛苦。

和技术栈的集成

在 Nuxt 里用 Mongoose 连 MongoDB 很直接:

// Nuxt 中的 Mongoose 连接
import mongoose from 'mongoose'

export default defineNitroPlugin(async (nitroApp) => {
  if (!mongoose.connection.readyState) {
    await mongoose.connect(process.env.MONGODB_URI)
  }
})

// 示例架构
const userSchema = new mongoose.Schema({
  name: String,
  email: { type: String, unique: true },
  role: { type: String, enum: ['admin', 'user', 'editor'] },
  preferences: {
    theme: String,
    notifications: Boolean
  },
  createdAt: { type: Date, default: Date.now }
})

// 优化索引
userSchema.index({ email: 1 })
userSchema.index({ createdAt: -1 })

复合索引、聚合管道、全文搜索、change stream 实时更新、sharding 水平扩展,这些功能组合起来,从中小规模到高并发的场景都能覆盖。

Quarkus:Java 给云原生的回答

Quarkus 的卖点是启动快、内存省。对微服务和 serverless 来说,这两点直接决定成本。

2025 年的基准数据:原生模式冷启动 ~50ms,RSS 内存 ~12MB,P99 延迟 ~95ms,已用堆 ~3.2MB。这个量级的资源消耗,放 Kubernetes 里跑容器非常合适。

JVM 模式下热重载快,适合日常开发。原生模式编译成原生可执行文件,适合生产部署。两个模式切换很自然。

// Quarkus 中的 REST API 示例
@Path("/api/products")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class ProductResource {
    
    @Inject
    ProductService service;
    
    @GET
    @Operation(summary = "列出产品", description = "返回所有产品")
    public Response list(
            @QueryParam("page") @DefaultValue("0") int page,
            @QueryParam("size") @DefaultValue("20") int size) {
        List<Product> products = service.list(page, size);
        return Response.ok(products).build();
    }
    
    @POST
    @Operation(summary = "创建产品")
    public Response create(ProductDTO dto) {
        Product product = service.create(dto);
        return Response.status(Status.CREATED)
                      .entity(product)
                      .build();
    }
}

MongoDB 集成

Quarkus 提供 MongoDB Panache 来简化数据访问,写法和 JPA 类似:

// 使用 Panache 的实体
@Entity
public class Product extends PanacheMongoEntity {
    public String name;
    public String description;
    public BigDecimal price;
    public Integer stock;
    public String category;
    public LocalDateTime createdAt;
    
    // 静态查询
    public static List<Product> findByCategory(String category) {
        return list("category", category);
    }
    
    public static List<Product> findActive() {
        return list("stock > 0");
    }
    
    public static long countByCategory(String category) {
        return count("category", category);
    }
}

// 仓库
@ApplicationScoped
public class ProductRepository implements PanacheMongoRepository<Product> {
    
    public List<Product> searchWithStock(int page, int size) {
        return find("stock > 0")
               .page(page, size)
               .list();
    }
    
    public Optional<Product> searchByCode(String code) {
        return find("code", code).firstResultOptional();
    }
}

整体架构

四个组件一起跑起来的时候,这个栈的优势才真正体现出来:

┌─────────────────────────────────────────────────────────┐
│                    Nuxt 4 (前端)                        │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────────┐  │
│  │ Nuxt UI v4  │  │  Pages/Views│  │   API Client    │  │
│  └─────────────┘  └─────────────┘  └─────────────────┘  │
└─────────────────────────────────────────────────────────┘
                              │
                              ▼ HTTP/REST/gRPC
┌─────────────────────────────────────────────────────────┐
│                   Quarkus (后端)                        │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────────┐  │
│  │  REST API   │  │  Services   │  │ MongoDB Panache │  │
│  └─────────────┘  └─────────────┘  └─────────────────┘  │
└─────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────┐
│                      MongoDB                            │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────────┐  │
│  │  Products   │  │    Users    │  │     Orders      │  │
│  └─────────────┘  └─────────────┘  └─────────────────┘  │
└─────────────────────────────────────────────────────────┘

Nuxt 配置:

// nuxt.config.ts
export default defineNuxtConfig({
  modules: [
    '@nuxt/ui',
    '@nuxtjs/mdc',
    '@pinia/nuxt'
  ],
  
  runtimeConfig: {
    public: {
      apiBase: process.env.NUXT_PUBLIC_API_BASE || '/api'
    }
  },
  
  ui: {
    global: true,
    icons: ['heroicons', 'simple-icons']
  },
  
  devtools: { enabled: true }
})

集中式 API 客户端:

// composables/useApi.ts
export const useApi = () => {
  const config = useRuntimeConfig()
  
  const client = $fetch.create({
    baseURL: config.public.apiBase,
    headers: {
      'Content-Type': 'application/json'
    },
    timeout: 30000
  })
  
  return {
    get: <T>(url: string, options?: object) =>
      client<T>(url, { method: 'GET', ...options }),
    
    post: <T>(url: string, body: object, options?: object) =>
      client<T>(url, { method: 'POST', body, ...options }),
    
    put: <T>(url: string, body: object, options?: object) =>
      client<T>(url, { method: 'PUT', body, ...options }),
    
    delete: <T>(url: string, options?: object) =>
      client<T>(url, { method: 'DELETE', ...options })
  }
}

性能数据

前端(Nuxt 4)

指标值基准
首次内容绘制~1.2s比 Nuxt 3 快 33%
最大内容绘制~1.9s比 Nuxt 3 快 34%
累积布局偏移~0.08比 Nuxt 3 好 47%
构建时间~18s比 Nuxt 3 快 60%

后端(Quarkus 原生)

指标值基准
冷启动~50ms领先的 Java 框架
内存 RSS~12MB容器的理想选择
P99 延迟~95ms一致的性能
吞吐量~50K req/s高并发

适合什么场景

需要无障碍、设计完整的 UI 时,Nuxt UI 110 多个组件省了大量造轮子的时间。Quarkus 的低资源消耗和毫秒级响应适合微服务和 serverless。MongoDB 对需求变化频繁的初创项目来说迁移成本低。面向全球用户的应用,Nuxt Edge 加 Quarkus 可以把延迟压到很低。

结论

这套栈用下来,我的感受是每个组件都在自己的位置上做对了事。Nuxt 4 负责前端的速度和类型安全,Nuxt UI 负责界面的一致性和可访问性,MongoDB 负责数据的灵活性,Quarkus 负责后端的性能和资源效率。文档质量过关,社区活跃,学习曲线可控,长期维护可预期。

不是每个项目都需要这套组合,但如果你的需求落在上面这些场景里,值得试试。


额外资源: