手把手教你从 Node 快速迁移到 Deno

上周我发表了一篇文章,介绍了 Deno 以及如何使用 Deno 和 Preact 创建一个聊天应用。文章发布后收到了很多询问,大多数问题关心的是:如何使用新的 Deno 生态系统来做那些我们原来用 Node 做的事情。我试着收集了一些 Node 中最常用的主题,并找出了它们在 Deno 中的替代方案。

首先我想明确一点,在 Deno 中我们可以使用许多现有的 Node.js 模块。由于许多模块都是可重用的,因此用不着为所有的事情都寻找替代选项。你可以访问 pika.dev 查找可以在 Deno 中使用的模块。

本文最初发布于 Aral Roca 个人网站,经原作者授权由 InfoQ 中文站翻译并分享。

Electron

在 Node.js 中,我们可以使用 Electron 创建桌面应用程序。Electron 使用 Chromium 作为界面来运行 Web 环境。但是,我们可以在 Deno 中使用 Electron 吗?或者有其他选择吗?

现在,Electron 是完全不能用在 Deno 下的,我们必须寻找替代方案。由于 Deno 是用 Rust 开发的,因此我们可以使用 web-view rust bindings 在 Deno 中运行桌面应用程序。

这样,我们就可以使用原生 OS webview 来运行任意数量的 Web 视图了。

仓库:

https://github.com/eliassjogreen/deno_webview

复制代码

import{ WebView } from"https://deno.land/x/webview/mod.ts";

const sharedOptions = {
width:400,
height:200,
resizable:true,
debug:true,
frameless:false,
};

const webview1 = new WebView({
title:"Multiple deno_webview example",
url:`data:text/html,


1

`, ...sharedOptions, }); const webview2 = new WebView({ title:"Multiple deno_webview example", url:`data:text/html,

2

`, ...sharedOptions, }); await Promise.all([webview1.run(), webview2.run()]);

Forever/PM2

Forever 和 PM2 是用来确保作为守护程序的指定脚本可以持续运行的 CLI 工具。与 Forever 不同,PM2 功能更完善,还可以用作负载均衡器。两者在 Node 中都很好用,但是我们可以在 Deno 中使用它们吗?

Forever 只适用于 Node,因此在 Deno 中是用不了的。但我们可以使用 PM2 运行非 Node 脚本,因此可以将其用于 Deno。

创建一个 app.sh 文件

复制代码

#!/bin/bash
deno run -A myCode.ts

然后

复制代码

➜ pm2start ./app.sh

Express/Koa

Express 和 Koa 都是最出名的 Node 框架。它们拥有强大的路由系统和 HTTP helpers(重定向,缓存等),因而广受欢迎。我们可以在 Deno 中使用它们吗?答案是否定的,但是也有一些替代方法。

Http(标准库)Deno 自己的标准库就能提供 Express 或 Koa 提供的许多功能了:

https://deno.land/std/http/

复制代码

import { ServerRequest } from"https://deno.land/std/http/server.ts";
import { getCookies } from"https://deno.land/std/http/cookie.ts";

letrequest=newServerRequest();
request.headers =newHeaders();
request.headers.set("Cookie","full=of; tasty=chocolate");

constcookies = getCookies(request);
console.log("cookies:", cookies);

但是,它声明路由的方法看起来不怎么好用,因此我们来看看更多替代方案。

Oak(第三方库)

受 Koa 启发的 Oak 是目前最优雅的解决方案之一: https://github.com/oakserver/oak

复制代码

import{ Application, }from"https://deno.land/x/oak/mod.ts";

const app =newApplication();

app.use((ctx)=>{
ctx.response.body ="Hello World!";
});

awaitapp.listen({ port:8000});

Abc(第三方库)

类似 Oak: https://deno.land/x/abc

复制代码

import{ Application }from"https://deno.land/x/abc/mod.ts";

const app =newApplication();

app.static("/static","assets");

app.get("/hello",(c)=>"Hello!")
.start({ port:8080});

Deno-Express(第三方库)

也许是最接近 Express 框架的替代方案: https://github.com/NMathar/deno-express

复制代码

import * as expfrom"https://raw.githubusercontent.com/NMathar/deno-express/master/mod.ts";

constport= 3000;
const app = new exp.App();

app.use(exp.static_("./public"));
app.use(exp.bodyParser.json());

app.get("/api/todos", async (req, res) => {
await res.json([{ name:"Buy some milk"}]);
});

constserver= await app.listen(port);
console.log(`app listening onport${server.port}`);

MongoDB

MongoDB 是一个拥有强大可扩展性和灵活性的文档数据库。它在 JavaScript 生态系统中应用广泛,很多技术栈(如 MEAN 或 MERN)都会使用它,因此它非常受欢迎。

我们可以将 MongoDB 用在 Deno 生态中,可以使用以下驱动程序: https://github.com/manyuanrong/deno_mongo

复制代码

import { init, MongoClient }from"https://deno.land/x/[email protected]/mod.ts";

// Initialize the plugin
awaitinit();

constclient =newMongoClient();
client.connectWithUri("mongodb://localhost:27017");

constdb = client.database("test");
constusers = db.collection("users");

// insert
constinsertId =awaitusers.insertOne({
username:"user1",
password:"pass1"
});

// findOne
constuser1 =awaitusers.findOne({ _id: insertId });

// find
constusers =awaitusers.find({ username: { $ne:null} });

// aggregation
constdocs =awaitusers.aggregation([
{ $match: { username:"many"} },
{ $group: { _id:"$username", total: { $sum:1} } }
]);

// updateOne
const{ matchedCount, modifiedCount, upsertedId } =awaitusers.updateOne(
username: { $ne:null},
{ $set: { username:"USERNAME"} }
);

// deleteOne
constdeleteCount =awaitusers.deleteOne({ _id: insertId });

PostgreSQL

与 MongoDB 一样,PostgresSQL 也有一个驱动程序:

https://github.com/buildondata/deno-postgres

复制代码

import {Client}from"https://deno.land/x/postgres/mod.ts";

constclient= new Client({
user:"user",
database:"test",
hostname:"localhost",
port: 5432
});
await client.connect();
const result = await client.query("SELECT * FROM people;");
console.log(result.rows);
await client.end();

MySQL/MariaDB

与 MongoDB 和 PostgresSQL 一样,MySQL/MariaDB 也有一个驱动程序:

https://github.com/manyuanrong/deno_mysql

复制代码

import{ Client }from"https://deno.land/x/mysql/mod.ts";

const client = awaitnewClient().connect({
hostname: "127.0.0.1",
username: "root",
db: "dbname",
poolSize:3, //connectionlimit
password: "password",
});

let result = await client.execute(`INSERTINTOusers(name)values(?)`, [
"aralroca",
]);
console.log(result);
// { affectedRows:1, lastInsertId:1}

Redis

Redis 是最出名的缓存数据库,它也有 Deno 的驱动程序:

https://github.com/keroxp/deno-redis

复制代码

import { connect }from"https://denopkg.com/keroxp/deno-redis/mod.ts";

constredis =awaitconnect({
hostname:"127.0.0.1",
port:6379
});
constok =awaitredis.set("example","this is an example");
constexample =awaitredis.get("example");

Nodemon

Nodemon 被用来在开发环境中监视文件的任何更改,发现更改后会自动重新启动服务器。它显著提升了 Node 的开发体验,开发人员无需再手动停止和重启服务器以查看应用更改。它可以在 Deno 中使用吗?

抱歉,你不能,但是也有另一种选择:Denon,Denon 的用法和使用 deno run 执行脚本一样。

https://github.com/eliassjogreen/denon

复制代码

➜ denon server.ts

Jest、Jasmine、Ava……

在 Node.js 生态系统中,测试运行器有很多选项可用。但官方并没有提供一种测试 Node.js 代码的方法。

在 Deno 中有一种官方方法,你可以使用 testing 标准库:

https://deno.land/std/testing

复制代码

import { assertStrictEq } from 'https://deno.land/std/testing/asserts.ts'

Deno.test('My first test', async()=>{
assertStrictEq(true,false)
})

要运行测试:

复制代码

➜ denotest

Webpack、Parcel、Rollup……

Deno 的优势之一是我们可以搭配使用 ES 模块与 TypeScript,而无需诸如 Webpack、Parcel 或 Rollup 之类的打包器。

但你可能想要知道:如果给定了一棵文件树,我们是否可以制作一个包,将所有内容放到一个文件中以在 Web 环境中运行呢?

答案是肯定的。我们可以使用 Deno 的 CLI 做到这一点。这样就无需第三方打包器了。

复制代码

➜denobundlemyLib.tsmyLib.bundle.js

现在可以将其加载到浏览器中:

复制代码

import*asmyLibfrom"myLib.bundle.js";

Prettier

在过去的几年中,Prettier 在 JavaScript 生态系统中大受欢迎,因为有了它,你就不用再操心格式化文件的事情了。

其实它也能用在 Deno 上,但这没什么意义,因为 Deno 有自己的格式化程序。

你可以使用以下命令格式化文件:

➜ deno fmt

NPM Scripts

在 Deno 中,package.json 不复存在。而我非常想念的一个特性是在 package.json 中声明的脚本。

一个简单的解决方案是使用一个 makefile,并用 make 执行它。但如果你怀念 npm 语法,那么 Deno 也有一个 npm 样式的脚本运行器:

https://github.com/umbopepato/velociraptor

你可以使用脚本定义文件:

复制代码

# scripts.yaml
scripts:
start: deno run--allow-net server.ts
test: denotest--allow-net server_test.ts

这样执行:

复制代码

➜ vr run

另一个替代品是 denox,与 Velociraptor 非常相似。

Nvm

Nvm 是一个 CLI,用来管理多个活动 Node 版本,以便根据项目需求轻松升级或降级版本。

在 Deno 中 nvm 的等效方案是 dvm:

https://github.com/axetroy/dvm

复制代码

➜ dvm use1.0.0

Npx

近年来 Npx 非常流行,因为它可以直接执行 npm 软件包,而无需安装它们。现在,由于 Deno 是一个独立的生态系统,所以 npm 中的许多项目都不可用了。那么,我们能不能不用 deno install https://url-of-module.ts 安装 Deno 模块,就直接使用它们呢?

答案是可以的,就和我们运行项目的方法一样,只不过用的是模块而非文件的 URL:

复制代码

➜ denorunhttps://deno.land/std/examples/welcome.ts

如你所见,我们不仅需要记住模块的名称,而且还要记住整个 URL,所以用起来很麻烦。另一方面,它提供了更大的灵活性,因为我们可以运行任何文件,而不仅仅是在 package.json 中指定为二进制文件的文件(如 npx)。

在 Docker 上运行

要在 Docker 内部运行 Deno,我们可以创建以下 Dockerfile:

复制代码

FROMhayd/alpine-deno:1.0.0

EXPOSE1993# Port.

WORKDIR/app

USERdeno

COPYdeps.ts .
RUNdeno cache deps.ts# Cache the deps

ADD. .
RUNdeno cache main.ts# main entrypoint.

CMD["--allow-net","main.ts"]

构建 + 运行:

复制代码

➜ docker build -t app . && dockerrun-it--init -p 1993:1993 app

仓库: https://github.com/hayd/deno-docker

作为 lambda 运行

要将 Deno 用作一个 lambda,可以使用 Deno 标准库中的这个模块:

https://deno.land/x/lambda

复制代码

import{
APIGatewayProxyEvent,
APIGatewayProxyResult,
Context
}from"https://deno.land/x/lambda/mod.ts";

exportasyncfunctionhandler({1}
event: APIGatewayProxyEvent,
context: Context
{1}):Promise {
return{
body:`Welcome to deno${Deno.version.deno}  `,
headers: {"content-type":"text/html;charset=utf8"},
statusCode:200
};
}

有趣的参考:

总结

我肯定遗漏了一些 Node 主题以及它们的 Deno 替代方案,大家有兴趣的话可以在评论里补充。我希望本文能帮助你跨过 Deno 的入门门槛。

想要了解可以用在 Deno 中的所有库:

原文链接:

https://aralroca.com/blog/from-node-to-deno