写点什么

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

  • 2020-06-03
  • 本文字数:4903 字

    阅读完需:约 16 分钟

手把手教你从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, <html> <body> <h1>1</h1> </body> </html> `, ...sharedOptions,});
const webview2 = new WebView({ title: "Multiple deno_webview example", url: `data:text/html, <html> <body> <h1>2</h1> </body> </html> `, ...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/bashdeno run -A myCode.ts
复制代码


然后


➜ pm2 <span>start</span> ./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";
let request = new ServerRequest();request.headers = new Headers();request.headers.set("Cookie", "full=of; tasty=chocolate");
const cookies = 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 = new Application();
app.use((ctx) => { ctx.response.body = "Hello World!";});
await app.listen({ port: 8000 });
复制代码

Abc(第三方库)

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


import { Application } from "https://deno.land/x/abc/mod.ts";
const app = new Application();
app.static("/static", "assets");
app.get("/hello", (c) => "Hello!") .start({ port: 8080 });
复制代码

Deno-Express(第三方库)

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


import * as exp from "https://raw.githubusercontent.com/NMathar/deno-express/master/mod.ts";
const port = 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" }]);});
const server = await app.listen(port);console.log(`app listening on port ${server.port}`);
复制代码

MongoDB

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



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


import { init, MongoClient } from "https://deno.land/x/mongo@v0.6.0/mod.ts";
// Initialize the pluginawait init();
const client = new MongoClient();client.connectWithUri("mongodb://localhost:27017");
const db = client.database("test");const users = db.collection("users");
// insertconst insertId = await users.insertOne({ username: "user1", password: "pass1"});
// findOneconst user1 = await users.findOne({ _id: insertId });
// findconst users = await users.find({ username: { $ne: null } });
// aggregationconst docs = await users.aggregation([ { $match: { username: "many" } }, { $group: { _id: "$username", total: { $sum: 1 } } }]);
// updateOneconst { matchedCount, modifiedCount, upsertedId } = await users.updateOne( username: { $ne: null }, { $set: { username: "USERNAME" } });
// deleteOneconst deleteCount = await users.deleteOne({ _id: insertId });
复制代码

PostgreSQL


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


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


import { Client } from "https://deno.land/x/postgres/mod.ts";
const client = 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 = await new Client().connect({ hostname: "127.0.0.1", username: "root", db: "dbname", poolSize: 3, // connection limit password: "password",});
let result = await client.execute(`INSERT INTO users(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";
const redis = await connect({ hostname: "127.0.0.1", port: 6379});const ok = await redis.set("example", "this is an example");const example = await redis.get("example");
复制代码

Nodemon


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


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


https://github.com/eliassjogreen/denon


➜ denon server.<span>ts</span>
复制代码

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)})
复制代码


要运行测试:


➜ deno <span>test</span>
复制代码

Webpack、Parcel、Rollup……


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


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


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


➜ deno bundle myLib.ts myLib.bundle.js
复制代码


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


<script type="module">  import * as myLib from "myLib.bundle.js";</script>
复制代码

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.yamlscripts:  start: deno run --allow-net server.ts  test: deno test --allow-net server_test.ts
复制代码


这样执行:


➜ vr run <SCRIPT>
复制代码


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

Nvm


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


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


https://github.com/axetroy/dvm


➜ dvm use 1.0.0
复制代码

Npx

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


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


➜  deno run https://deno.land/std/examples/welcome.ts
复制代码


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

在 Docker 上运行


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


FROM hayd/alpine-deno:1.0.0
EXPOSE 1993 # Port.
WORKDIR /app
USER deno
COPY deps.ts .RUN deno cache deps.ts # Cache the deps
ADD . .RUN deno cache main.ts # main entrypoint.
CMD ["--allow-net", "main.ts"]
复制代码


构建 + 运行:


➜  docker build -t app . && docker run -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";
export async function handler( event: APIGatewayProxyEvent, context: Context): Promise<APIGatewayProxyResult> { 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


2020-06-03 18:079193

评论 3 条评论

发布
用户头像
作者 Aral Roca 感谢译者
2020-06-09 03:17
回复
用户头像
各种标题党 一股头条自媒体的味道
2020-06-04 11:19
回复
用户头像
这叫快速迁移?明明是重写好吗
2020-06-04 09:06
回复
没有更多了
发现更多内容

PPDE迎新 | 欢迎18位AI开发者加入飞桨开发者技术专家计划

百度大脑

自己动手写Docker系列 -- 6.2创建网络

Go Docker 4月月更

Apache SkyWalking 告警动态配置源码简析

爱好编程进阶

Java 面试 后端开发

BS-XX-020基于SSM实现停车位租赁系统

爱好编程进阶

Java 面试 后端开发

ConcurrentHashMap1-8源码解读及如何保证线程安全

爱好编程进阶

Java 面试 后端开发

Linux驱动开发-编写超声波测距模块的驱动

DS小龙哥

4月月更

外包学生管理系统详细架构设计

Geek_bc9c8d

Java性能优化的35个细节(珍藏版)

爱好编程进阶

Java 面试 后端开发

检测、跟踪、行为识别All-In-One!产业级行人分析系统重磅开源!

百度大脑

Java程序员2021年金三银四面试必备:高速突击学习框架+性能优化

爱好编程进阶

Java 面试 后端开发

格灵深瞳与华为签署合作协议,共同推进昇腾AI产业创新发展

Geek_32c4d0

昇腾AI

聚焦信息抽取前沿难题,CCKS-千言通用信息抽取竞赛报名启动

百度大脑

Eclipse快捷键 10个最有用的快捷键

爱好编程进阶

Java 面试 后端开发

利用String.intern 减少相同值的String内存占用

lich0079

内存 intern java MAT String类

大咖云集,星环科技春季新品发布周【数字化转型专题】精彩抢先看

星环科技

数据库

2021最新版SpringBoot实战项目教程,美团专家带你深入SpringBoot

爱好编程进阶

Java 面试 后端开发

7步搞懂分布式全内容,我不信面试官还敢“怼

爱好编程进阶

Java 面试 后端开发

Java工程师的进阶之路-Kafka篇(二)

爱好编程进阶

Java 面试 后端开发

keepalived实现双机热备

爱好编程进阶

Java 面试 后端开发

ERNIE-GeoL:“地理位置-语言”预训练模型

百度大脑

ModStart 是基于 Laravel 的模块化开发框架

ModStart开源

前端食堂技术周刊第 33 期:IE 退休倒计时:3 个月、TypeScript 4.7 Beta、TypeScript 编译器工作原理、Rust 编码规范

童欧巴

前端 Web 前端工程师

B站,牛逼!

爱好编程进阶

Java 面试 后端开发

gRPC学习之三:初试GO版gRPC开发

爱好编程进阶

Java 面试 后端开发

Java面试过了京东五面之后,发现掌握了这些技术也没有那么难

爱好编程进阶

Java 面试 后端开发

Java基础08 方法

爱好编程进阶

Java 面试 后端开发

数据分析之前知道这 7 件事,少花 80% 时间

龙国富

数据分析 数据采集

专有云如何精准、及时地实现故障定位?丨智能运维

百度大脑

5分钟搞懂MySQL - 索引下推优化

爱好编程进阶

Java 面试 后端开发

JAVA学习(3)

爱好编程进阶

Java 面试 后端开发

JVM基本概念

爱好编程进阶

Java 面试 后端开发

手把手教你从Node快速迁移到Deno_开源_Aral Roca_InfoQ精选文章