跳至主要内容
Deno 2 终于来了 🎉️
了解更多
Using frameworks in Deno.

使用 React、Vue、Express 等框架在 Deno 中构建应用程序。

在 JavaScript 中构建网站和应用程序的框架并不少见。(事实上,当你阅读本文时,一个新的框架刚刚发布。)由于 npm 已成为许多 JavaScript 事物的主要分发平台,因此大多数框架都需要 npm 才能使用。

使用 Deno 1.28,您现在可以使用这些 JavaScript 框架,例如 ExpressReactVue 等。

这篇文章将向您展示如何在 Deno 中开始使用这些 JavaScript 框架。

查看我们的手册以获取更多关于使用 npm 与 JavaScript 框架的“如何”指南。.

编写更少的代码

使用这些框架构建将更快,需要更少的配置,并且使用更少的样板代码。

  • 花更少的时间评估和构建自己的工具 - Deno 附带了 强大的工具链,其中包括 deno testdeno lintdeno fmt 等。
  • 没有 package.json.tsconfignode_modules 子目录(默认情况下),这可以让你专注于重要的代码。
  • 没有单独的 npm install 步骤 - 模块在特殊的全局目录中缓存一次。

在下面的示例中,我们将展示使用 npm 与 Deno 入门是多么容易。

Express

Express 是一个流行的 Web 框架,以简单、无意见且拥有庞大的中间件生态系统而闻名。

让我们使用 Express 和 Deno 创建一个简单的 API。

在这里查看源代码。

创建 main.ts

让我们创建 main.ts

touch main.ts

main.ts 中,让我们创建一个简单的服务器

// @deno-types="npm:@types/express"
import express from "npm:[email protected]";

const app = express();

app.get("/", (req, res) => {
  res.send("Welcome to the Dinosaur API!");
});

app.listen(8000);

让我们运行这个服务器

deno run --allow-net main.ts

并将我们的浏览器指向 localhost:8000。您应该看到

Welcome to the Dinosaur API!

添加数据和路由

下一步是添加一些数据。我们将使用从 这篇文章 中找到的恐龙数据。请随时 从这里复制它

让我们创建 data.json

touch data.json

并将恐龙数据粘贴进去。

接下来,让我们将这些数据导入到 main.ts 中。让我们在文件顶部添加这行代码

import data from "./data.json" with { type: "json" };

然后,我们可以创建访问这些数据的路由。为了简单起见,让我们只定义 GET 处理程序,用于 /api//api/:dinosaur。在 const app = express(); 行之后添加以下代码

app.get("/", (req, res) => {
  res.send("Welcome to the Dinosaur API!");
});

app.get("/api", (req, res) => {
  res.send(data);
});

app.get("/api/:dinosaur", (req, res) => {
  if (req?.params?.dinosaur) {
    const filtered = data.filter((item) => {
      return item["name"].toLowerCase() === req.params.dinosaur.toLowerCase();
    });
    if (filtered.length === 0) {
      return res.send("No dinosaurs found.");
    } else {
      return res.send(filtered[0]);
    }
  }
});

app.listen(8000);

让我们使用 deno run --allow-net main.ts 运行服务器,并查看 localhost:8000/api。您应该看到恐龙列表

[
  {
    "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."
  },
...

当我们转到 localhost:8000/api/aardonyx

{
  "name": "Aardonyx",
  "description": "An early stage in the evolution of sauropods."
}

太棒了!

React

虽然 Express 非常适合 API 和服务,但 React предназначен для пользовательских интерфейсов. Он популяризировал декларативный подход к проектированию интерфейсов с реактивной моделью данных. И учитывая его популярность, неудивительно, что он является наиболее востребованным фреймворком при создании веб-приложений с использованием Deno.

让我们创建一个应用程序,该应用程序将显示恐龙列表。当您点击其中一个恐龙时,它会将您带到一个包含更多详细信息的恐龙页面。

查看源代码按照视频指南进行操作

创建 Vite Extra

让我们使用 Vite 快速搭建一个 Deno 和 React 应用程序

deno run --allow-read --allow-write --allow-env npm:create-vite-extra@latest

我们将把项目命名为“dinosaur-react-app”。然后,cd 到新创建的项目文件夹中。

添加后端

下一步是添加后端 API。我们将创建一个非常简单的 API,用于返回有关恐龙的信息。

在目录中,让我们创建一个 api 文件夹。在这个文件夹中,我们将创建一个 main.ts 文件,它将运行服务器,以及一个 data.json 文件,它包含硬编码数据。

mkdir api && touch api/data.json && touch api/main.ts

此 json 文件 复制粘贴到您的 api/data.json 中。

然后,让我们更新 api/main.ts

import { Application, Router } from "https://deno.land/x/[email protected]/mod.ts";
import { oakCors } from "https://deno.land/x/[email protected]/mod.ts";
import data from "./data.json" with { type: "json" };

const router = new Router();
router
  .get("/", (context) => {
    context.response.body = "Welcome to dinosaur API!";
  })
  .get("/api", (context) => {
    context.response.body = data;
  })
  .get("/api/:dinosaur", (context) => {
    if (context?.params?.dinosaur) {
      const filtered = data.filter((item) =>
        item["name"].toLowerCase() === context.params.dinosaur.toLowerCase()
      );
      if (filtered.length === 0) {
        context.response.body = "No dinosaurs found.";
      } else {
        context.response.body = filtered[0];
      }
    }
  });

const app = new Application();
app.use(oakCors()); // Enable CORS for All Routes
app.use(router.routes());
app.use(router.allowedMethods());

await app.listen({ port: 8000 });

这是一个非常简单的 API 服务器,使用 oak,它将根据路由返回恐龙信息。让我们启动 API 服务器

deno run --allow-env --allow-net api/main.ts

如果我们转到 localhost:8000,我们会看到

json response of dinosaurs

看起来不错。

添加路由器

我们的应用程序将有两个路由://:dinosaur

我们将使用 react-router-dom 来实现我们的路由逻辑。让我们将其添加到 vite.config.mjs 中的依赖项中

import { defineConfig } from "npm:vite@^3.1.3";
import react from "npm:@vitejs/plugin-react@^2.1";

import "npm:react@^18.2";
import "npm:react-dom/client@^18.2";
import "npm:react-router-dom@^6.4"; // Add this line

// https://vite.vuejs.ac.cn/config/
export default defineConfig({
  plugins: [react()],
});

在添加依赖项后,我们就可以在整个 React 应用程序中无需 npm: 标识符就可以导入它们。

接下来,让我们转到 src/App.jsx 并添加我们的路由逻辑

import React from "react";
import {
  BrowserRouter as Router,
  Navigate,
  Route,
  Routes,
} from "react-router-dom";
import Index from "./pages/Index.jsx";
import Dinosaur from "./pages/Dinosaur.jsx";

export default function App(props) {
  return (
    <Router>
      <Routes>
        <Route exact path="/" element={<Index />} />
        <Route exact path="/:dinosaur" element={<Dinosaur />} />
        <Route path="*" element={<Navigate to="/" />} />
      </Routes>
    </Router>
  );
}

接下来,让我们添加 <Index><Dinosaur> 页面。

添加页面

此应用程序将包含两个页面

  • src/pages/Index.jsx:我们的索引页面,它列出了所有恐龙
  • src/pages/Dinosaur.jsx:我们的恐龙页面,它显示了恐龙的详细信息

我们将创建一个 src/pages 文件夹,并在其中创建 .jsx 文件

mkdir src/pages && touch src/pages/Index.jsx src/pages/Dinosaur.jsx

让我们从 <Index> 开始。此页面将 fetchlocalhost:8000/api 并通过 JSX 渲染它。

import React, { useEffect, useState } from "react";
import { Link, useParams } from "react-router-dom";

const Index = () => {
  const [dinos, setDinos] = useState([]);
  useEffect(() => {
    fetch(`https://127.0.0.1:8000/api/`)
      .then(async (res) => await res.json())
      .then((json) => setDinos(json));
  }, []);

  return (
    <div>
      <h1>Welcome to the Dinosaur app</h1>
      <p>
        Click on a dinosaur below to learn more.
      </p>
      <div>
        {dinos.map((dino) => {
          return (
            <div>
              <Link to={`/${dino.name.toLowerCase()}`}>{dino.name}</Link>
            </div>
          );
        })}
      </div>
    </div>
  );
};

export default Index;

接下来,在 <Dinosaur> 中,我们将执行相同的操作,只不过是针对 localhost:8000/api/${dinosaur}

import React, { useEffect, useState } from "react";
import { Link, useParams } from "react-router-dom";

const Dinosaur = () => {
  const { dinosaur } = useParams();
  const [dino, setDino] = useState({});
  useEffect(() => {
    fetch(`https://127.0.0.1:8000/api/${dinosaur}`)
      .then(async (res) => await res.json())
      .then((json) => setDino(json));
  }, []);

  return (
    <div>
      <h1>{dino.name}</h1>
      <p>
        {dino.description}
      </p>
      <Link to="/">See all</Link>
    </div>
  );
};

export default Dinosaur;

让我们启动 React 应用程序

deno task start

然后点击应用程序

demo of the app

成功!

有关使用 React 的更多信息,请 参阅其文档

Vue

Vue 是一个渐进式的前端 JavaScript 框架,专为性能和多功能性而构建。

让我们创建与 React 中相同的应用程序,但现在在 Vue 中。

查看源代码观看视频指南

运行 npm:create-vite-extra

我们将使用 Vite 来搭建我们的 Vue 应用程序。

deno run --allow-read --allow-write --allow-env npm:create-vite-extra@latest

命名您的项目,然后选择“deno-vue”。

然后,cd 到您的新项目并运行

deno task dev

您现在应该能够在浏览器中查看您的默认 Deno 和 Vue 应用程序。

default vue app

添加后端

下一步是添加后端 API。我们将创建一个非常简单的 API,用于返回有关恐龙的信息。

在目录中,让我们创建一个 api 文件夹。在这个文件夹中,我们将创建一个 main.ts 文件,它将运行服务器,以及一个 data.json 文件,它包含硬编码数据。

mkdir api && touch api/data.json && touch api/main.ts

此 json 文件 复制粘贴到您的 api/data.json 中。

然后,让我们更新 api/main.ts

import { Application, Router } from "https://deno.land/x/[email protected]/mod.ts";
import { oakCors } from "https://deno.land/x/[email protected]/mod.ts";
import data from "./data.json" with { type: "json" };

const router = new Router();
router
  .get("/", (context) => {
    context.response.body = "Welcome to dinosaur API!";
  })
  .get("/api", (context) => {
    context.response.body = data;
  })
  .get("/api/:dinosaur", (context) => {
    if (context?.params?.dinosaur) {
      const found = data.find((item) =>
        item.name.toLowerCase() === context.params.dinosaur.toLowerCase()
      );
      if (found) {
        context.response.body = found;
      } else {
        context.response.body = "No dinosaurs found.";
      }
    }
  });

const app = new Application();
app.use(oakCors()); // Enable CORS for All Routes
app.use(router.routes());
app.use(router.allowedMethods());

await app.listen({ port: 8000 });

这是一个非常简单的 API 服务器,使用 oak,它将根据路由返回恐龙信息。让我们启动 API 服务器

deno run --allow-env --allow-net api/main.ts

如果我们访问 localhost:8000/api,我们会看到

json response of dinosaurs

到目前为止,一切顺利。

添加 Vue 组件

让我们更新 src/components。我们将添加以下文件。

  • HomePage.vue,主页的组件
  • Dinosaurs.vue,列出所有恐龙名称作为锚链接的组件,以及
  • Dinosaur.vue,显示单个恐龙名称和描述的组件
touch src/components/HomePage.vue src/components/Dinosaurs.vue src/components/Dinosaur.vue

在创建组件之前,让我们添加一些状态管理。

使用 store 保持状态

为了在 <Dinosaur><Dinosaurs> 组件之间维护状态,我们将使用 Vue store。注意,对于更复杂的状态管理,请查看 Vue 支持的 Pinia 库。

创建一个 src/store.js 文件。

touch src/store.js

并在其中,让我们添加

import { reactive } from "vue";

export const store = reactive({
  dinosaur: {},
  setDinosaur(name, description) {
    this.dinosaur.name = name;
    this.dinosaur.description = description;
  },
});

我们将把 store 导入 Dinosaurs.vueDinosaur.vue,以便设置和检索恐龙名称和描述。

更新 Vue 组件

Dinosaurs.vue 中,我们将做三件事。

  • 向我们的 API 发送 GET 请求并将结果作为 dinosaurs 返回
  • 遍历 dinosaurs 并使用指向 <Dinosaur> 组件的 <router-link> 渲染每个 dinosaur
  • store.setDinosaur() 添加到每个 dinosaur@click 上,这将设置 store

以下是完整的代码。

<script>
import { ref } from 'vue'
import { store } from '../store.js'
export default ({
  async setup() {
    const res = await fetch("https://127.0.0.1:8000/api")
    const dinosaurs = await res.json();
    return {
      dinosaurs
    }
  },
  data() {
    return {
      store
    }
  }
})
</script>

<template>
  <div class="container">
    <div v-for="dinosaur in dinosaurs" class="dinosaur-wrapper">
      <span class="dinosaur">
        <router-link :to="{ name: 'Dinosaur', params: { dinosaur: `${dinosaur.name.toLowerCase()}` }}">
          <span @click="store.setDinosaur(dinosaur.name, dinosaur.description)">
            {{dinosaur.name}}
          </span>
        </router-link>
      </span>
    </div>
  </div>
</template>

<style scoped>
.dinosaur {
}
.dinosaur-wrapper {
  display: inline-block;
  margin: 0.15rem 1rem;
  padding: 0.15rem 1rem;
}
.container {
  text-align: left;
}
</style>

Dinosaur.vue 中,我们将添加

  • 导入 store
  • 在 HTML 中渲染 store.dinosaur
<script>
import { store } from '../store.js';
export default {
  data() {
    return {
      store
    }
  }
}
</script>

<template>
  Name: {{ store.dinosaur.name }}
  <br />
  Description: {{ store.dinosaur.description }}
</template>

接下来,我们将更新 HomePage.vue。由于 Dinosaurs 组件需要从 API 获取数据,我们将使用 <Suspense>,它在组件树中管理异步依赖关系。

<script>
import { ref } from 'vue'
import Dinosaurs from './Dinosaurs.vue'
export default {
  components: {
    Dinosaurs
  }
}
</script>

<template>
  <Suspense>
    <template #default>
      <Dinosaurs />
    </template>
    <template #fallback>
      <div>Loading...</div>
    </template>
  </Suspense>

  <p>
    Check out
    <a href="https://vuejs.ac.cn/guide/quick-start.html#local" target="_blank"
      >create-vue</a
    >, the official Vue + Vite starter
  </p>
  <p class="read-the-docs">Learn more about using Deno and Vite.</p>
</template>

<style scoped>
.read-the-docs {
  color: #888;
}
</style>

将它们整合在一起,让我们更新 src/App.vue

<template>
  <router-view />
</template>;

添加路由

您会注意到我们使用了 <router-link><router-view>。这些组件是 vue-router 的一部分,我们必须在另一个文件中进行设置和配置。

首先,让我们在 vite.config.mjs 文件中导入 vue-router

import { defineConfig } from "npm:vite@^3.1.3";
import vue from "npm:@vitejs/plugin-vue@^3.2.39";

import "npm:vue@^3.2.39";
import "npm:vue-router@4";

// https://vite.vuejs.ac.cn/config/
export default defineConfig({
  plugins: [vue()],
});

接下来,让我们创建一个名为 router 的文件夹。在其中,让我们创建 index.ts

mkdir router && touch router/index.ts

router/index.ts 中,我们将创建 router,其中包含有关每个路由及其组件的信息,并将其导出。有关使用 vue-router 的更多信息,请查看他们的 指南

import { createRouter, createWebHistory } from "vue-router";
import HomePage from "../components/HomePage.vue";
import Dinosaur from "../components/Dinosaur.vue";

const routes = [
  {
    path: "/",
    name: "Home",
    component: HomePage,
  },
  {
    path: "/:dinosaur",
    name: "Dinosaur",
    component: Dinosaur,
    props: true,
  },
];

const router = createRouter({
  history: createWebHistory("/"),
  routes,
});

export default router;

接下来,在我们的 src/main.ts 文件中,该文件包含前端应用程序的所有逻辑,我们将必须导入并使用 router

import { createApp } from "vue";
import "./style.css";
import App from "./App.vue";
import router from "./router/index.ts";

const app = createApp(App);
app.use(router);
app.mount("#app");

让我们运行它看看我们得到了什么。

Clicking on a dinosaur to get to an individual dinosaur page

太棒了!

接下来是什么?

希望这些示例说明了使用 Deno 和 JavaScript Web 框架进行启动和运行是多么容易。它们也是构建应用程序的起点。从那里,您可以 添加适当的数据持久性、添加其他路由、实现身份验证等。最后,我们计划继续在我们的 手册 中添加“如何做”指南。

我们还很高兴宣布,我们将在明天,11 月 17 日星期四,太平洋时间上午 9 点,在我们的 YouTube 频道上直播 直播,我们将

  • 讨论如何在 Deno 中使用 npm,
  • 回答直播聊天或我们 Discord 上的任何问题,以及
  • 进行一些现场编码!

我们希望您能加入我们!

遇到问题?在我们的 Discord 上寻求帮助。