使用 React、Vue、Express 等框架在 Deno 中构建应用程序。
在 JavaScript 中构建网站和应用程序的框架并不少见。(事实上,当你阅读本文时,一个新的框架刚刚发布。)由于 npm 已成为许多 JavaScript 事物的主要分发平台,因此大多数框架都需要 npm 才能使用。
使用 Deno 1.28,您现在可以使用这些 JavaScript 框架,例如 Express、React、Vue 等。
这篇文章将向您展示如何在 Deno 中开始使用这些 JavaScript 框架。
查看我们的手册以获取更多关于使用 npm 与 JavaScript 框架的“如何”指南。.
编写更少的代码
使用这些框架构建将更快,需要更少的配置,并且使用更少的样板代码。
- 花更少的时间评估和构建自己的工具 - Deno 附带了 强大的工具链,其中包括
deno test
、deno lint
、deno fmt
等。 - 没有
package.json
、.tsconfig
或node_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
,我们会看到
看起来不错。
添加路由器
我们的应用程序将有两个路由:/
和 /: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>
开始。此页面将 fetch
到 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
然后点击应用程序
成功!
有关使用 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 应用程序。
添加后端
下一步是添加后端 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
,我们会看到
到目前为止,一切顺利。
添加 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.vue
和 Dinosaur.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");
让我们运行它看看我们得到了什么。
太棒了!
接下来是什么?
希望这些示例说明了使用 Deno 和 JavaScript Web 框架进行启动和运行是多么容易。它们也是构建应用程序的起点。从那里,您可以 添加适当的数据持久性、添加其他路由、实现身份验证等。最后,我们计划继续在我们的 手册 中添加“如何做”指南。
我们还很高兴宣布,我们将在明天,11 月 17 日星期四,太平洋时间上午 9 点,在我们的 YouTube 频道上直播 直播,我们将
- 讨论如何在 Deno 中使用 npm,
- 回答直播聊天或我们 Discord 上的任何问题,以及
- 进行一些现场编码!
我们希望您能加入我们!
遇到问题?在我们的 Discord 上寻求帮助。