跳到主要内容
Using frameworks in Deno.

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

JavaScript 中构建网站和应用的框架数不胜数。(事实上,就在你阅读这段文字时,又有一个新的框架发布了。)由于 npm 已经成为许多 JavaScript 事物的主要分发平台,因此大多数框架都需要使用 npm。

借助 Deno 1.28,你现在可以使用这些 JavaScript 框架进行构建,例如 ExpressReactVue 等。

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

查看我们的手册,了解更多关于将 JavaScript 框架与 npm 结合使用的教程.

编写更少代码

使用 Deno 构建这些框架将更快、配置更少、样板代码更少

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

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

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" };

然后,我们可以创建路由来访问这些数据。为了简单起见,我们只为 /api//api/:dinosaur 定义 GET 处理程序。在 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 构建 Web 应用时最受欢迎的框架。

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

查看源代码观看视频指南

创建 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> 开始。此页面将在 localhost: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> 组件
  • 在每个 dinosaur@click 事件中添加 store.setDinosaur(),这将设置 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 上获取帮助。