deno.com
本页内容

使用 Deno 构建 Nuxt 应用

Nuxt 是一个框架,提供了一种直观的方式来创建基于 Vue 的全栈应用程序。它开箱即用地提供了基于文件的路由、多种渲染选项和自动代码分割。凭借其模块化架构,Nuxt 通过提供一种结构化的方法来构建 Vue 应用程序,从而简化了开发过程。

在本教程中,我们将使用 Deno 构建一个简单的 Nuxt 应用程序,它将显示恐龙列表,并允许您在点击名称时了解更多关于每只恐龙的信息。

您可以在此 仓库 中找到此项目的代码。

使用 Deno 搭建 Nuxt 应用 跳转到标题

我们可以像这样使用 Deno 创建一个新的 Nuxt 项目

deno -A npm:nuxi@latest init

我们将使用 Deno 管理我们的包依赖,并可以从 npm 获取 Nuxt 包。这将创建一个具有此项目结构的 nuxt-app

NUXT-APP/
├── .nuxt/                   # Nuxt build directory
├── node_modules/           # Node.js dependencies
├── public/                 # Static files
│   ├── favicon.ico        
│   └── robots.txt         
├── server/                # Server-side code
│   └── tsconfig.json     
├── .gitignore            
├── app.vue               # Root Vue component
├── nuxt.config.ts        # Nuxt configuration
├── package-lock.json     # NPM lock file
├── package.json          # Project manifest
├── README.md            
└── tsconfig.json        # TypeScript configuration

设置服务器 API 路由 跳转到标题

我们首先创建提供恐龙数据的 API 路由。

首先,我们的 恐龙数据 将作为 server/api/data.json 存在于 server 目录中

server/api/data.json
[
  {
    "name": "Aardonyx",
    "description": "An early stage in the evolution of sauropods."
  },
  {
    "name": "Abelisaurus",
    "description": "\"Abel's lizard\" has been reconstructed from a single skull."
  },
  {
    "name": "Abrictosaurus",
    "description": "An early relative of Heterodontosaurus."
  },
  ...etc
]

这是我们将从中提取数据的地方。在一个完整的应用程序中,这些数据将来自数据库。

⚠️️ 在本教程中,我们对数据进行了硬编码。但您可以使用 Deno 连接到各种数据库,甚至使用像 Prisma 这样的 ORM

此应用程序将有两个 API 路由。它们将提供以下内容

  • 用于索引页的完整恐龙列表
  • 用于单个恐龙页面的单个恐龙信息

两者都将是 *.get.ts 文件,Nuxt 会自动将其转换为 API 端点以响应 GET 请求。文件名约定同时决定了 HTTP 方法和路由路径

最初的 dinosaurs.get.ts 相当简单,它使用 defineCachedEventHandler 创建一个缓存端点以获得更好的性能。此处理程序只是返回我们完整的恐龙数据数组,没有任何过滤

server/api/dinosaurs.get.ts
import data from "./data.json" with { type: "json" };

export default defineCachedEventHandler(() => {
  return data;
});

单个恐龙的 GET 路由逻辑稍微多一些。它从事件上下文中提取名称参数,执行不区分大小写的匹配以查找请求的恐龙,并包含对缺失或无效恐龙名称的适当错误处理。我们将创建一个 dinosaurs 目录,然后为了传递名称参数,我们将创建一个名为 [name].get.ts 的新文件

server/api/dinosaurs/[name].get.ts
import data from "../data.json";

export default defineCachedEventHandler((event) => {
  const name = getRouterParam(event, "name");

  if (!name) {
    throw createError({
      statusCode: 400,
      message: "No dinosaur name provided",
    });
  }

  const dinosaur = data.find(
    (dino) => dino.name.toLowerCase() === name.toLowerCase(),
  );

  if (!dinosaur) {
    throw createError({
      statusCode: 404,
      message: "Dinosaur not found",
    });
  }

  return dinosaur;
});

使用 deno task dev 运行服务器,并在浏览器中访问 https://:3000/api/dinosaurs,您应该会看到显示所有恐龙的原始 JSON 响应!

Setting up API

您还可以通过访问特定的恐龙名称来检索单个恐龙的数据,例如:https://:3000/api/dinosaurs/aardonyx

Setting up API

接下来,我们将使用 Vue 设置前端,以显示索引页和每个单独的恐龙页。

设置 Vue 前端 跳转到标题

我们希望在应用程序中设置两个页面

  • 一个将列出所有恐龙的索引页
  • 一个显示有关所选恐龙更多信息的单个恐龙页。

首先,创建索引页。Nuxt 使用文件系统路由,因此我们将在根目录中创建一个 pages 目录,并在其中创建一个名为 index.vue 的索引页。

为了获取数据,我们将使用 useFetch 可组合函数来访问我们在上一节中创建的 API 端点

pages/index.vue
<script setup lang="ts">
const { data: dinosaurs } = await useFetch("/api/dinosaurs");
</script>

<template>
  <main>
    <h1 class="text-2xl font-bold mb-4">Welcome to the Dinosaur app</h1>
    <p class="mb-4">Click on a dinosaur below to learn more.</p>
    <ul class="space-y-2">
      <li v-for="dinosaur in dinosaurs" :key="dinosaur.name">
        <NuxtLink
          :to="'/' + dinosaur.name.toLowerCase()"
          class="text-blue-600 hover:text-blue-800 hover:underline"
        >
          {{ dinosaur.name }}
        </NuxtLink>
      </li>
    </ul>
  </main>
</template>

对于显示每个恐龙信息的页面,我们将创建一个新的动态页面 [name].vue。此页面使用 Nuxt 的动态路由参数,其中文件名中的 [name] 可以在 JavaScript 中作为 route.params.name 访问。我们将使用 useRoute 可组合函数来访问路由参数,并使用 useFetch 根据名称参数获取特定恐龙的数据

pages/[name].vue
<script setup lang="ts">
const route = useRoute();
const { data: dinosaur } = await useFetch(
  `/api/dinosaurs/${route.params.name}`
);
</script>

<template>
  <main v-if="dinosaur">
    <h1 class="text-2xl font-bold mb-4">{{ dinosaur.name }}</h1>
    <p class="mb-4">{{ dinosaur.description }}</p>
    <NuxtLink to="/" class="text-blue-600 hover:text-blue-800 hover:underline">
      Back to all dinosaurs
    </NuxtLink>
  </main>
</template>

接下来,我们必须将这些 Vue 组件连接起来,以便当我们访问域的根目录时它们能够正确渲染。让我们更新目录根部的 app.vue 来提供我们应用程序的根组件。我们将使用 NuxtLayout 来实现一致的页面结构,并使用 NuxtPage 来实现动态页面渲染

app.vue
<template>
  <NuxtLayout>
    <div>
      <nav class="p-4 bg-gray-100">
        <NuxtLink to="/" class="text-blue-600 hover:text-blue-800">
          Dinosaur Encyclopedia
        </NuxtLink>
      </nav>

      <div class="container mx-auto p-4">
        <NuxtPage />
      </div>
    </div>
  </NuxtLayout>
</template>;

使用 deno task dev 运行服务器,并在 https://:3000 查看效果

看起来很棒!

添加 Tailwind 跳转到标题

就像我们说的,我们将为这个应用程序添加一点样式。首先,我们将设置一个布局,它将使用 Nuxt 的布局系统与基于插槽的内容注入,为所有页面提供一致的结构

layouts/default.vue
<template>
  <div>
    <slot />
  </div>
</template>;

在这个项目中,我们还将使用 Tailwind 进行一些基本设计,因此我们需要安装这些依赖项

deno install -D npm:tailwindcss npm:@tailwindcss/vite

然后,我们将更新 nuxt.config.ts。导入 Tailwind 依赖项并为 Deno 兼容性配置 Nuxt 应用程序,我们将启用开发工具,并设置 Tailwind CSS

nuxt.config.ts
import tailwindcss from "@tailwindcss/vite";

export default defineNuxtConfig({
  compatibilityDate: "2025-05-15",
  devtools: { enabled: true },
  nitro: {
    preset: "deno",
  },
  app: {
    head: {
      title: "Dinosaur Encyclopedia",
    },
  },
  css: ["~/assets/css/main.css"],
  vite: {
    plugins: [
      tailwindcss(),
    ],
  },
});

接下来,创建一个新的 css 文件,assets/css/main.css,并添加一个 @import 导入 Tailwind 以及 Tailwind 工具

assets/css/main.css
@import "tailwindcss";

@tailwind base;
@tailwind components;
@tailwind utilities;

运行应用程序 跳转到标题

然后我们可以使用以下命令运行应用程序

deno task dev

这将启动应用程序在 localhost:3000

我们完成了!

🦕 Nuxt 应用程序的下一步可能是使用 Nuxt Auth 模块添加身份验证,使用 Pinia 实现状态管理,使用 PrismaMongoDB 添加服务器端数据持久性,并使用 Vitest 设置自动化测试。这些功能将使其为大型应用程序做好生产准备。

您找到所需内容了吗?

隐私政策