Deno 是一个安全的 JavaScript 和 TypeScript 运行时,作者是 Ryan Dahl(也是 Node.js 的原作者)。Deno 的诞生之初是为了解决 2009 年首次设计 Node.js 时的一些疏忽。我认为这种改造动机很有道理,因为我相信每个程序员都希望有机会能重写他们已有 10 年历史的代码。
deno 刚出的时候就听闻了,传言 deno 是下一代 node.js。不过如今看来,还革不了 node.js 的命。如果要说两者字面上的区别,Deno 的来源是 Node 的字母重新组合(Node = no + de),表示"拆除 Node.js"(de = destroy, no = Node.js)。
趁着假期学了一段时间的 deno(指文档刷了一遍),想分享本人作为 node 开发者在学习 deno 时认为的一些亮点,以及个人对 deno 与 node 见解。
开发环境
默认情况下 deno 会根据不同的系统,选择相应的安装目录,以及依赖目录,你 可以配置环境变量来改变 deno 的默认行为。
这里我选用 vscode 进行开发,安装deno 官方插件。此时创建一个项目工程文件夹,打开 vscode,并创建 .vscode/settings.json 内容如下
{
"deno.enable": true,
"deno.lint": true,
"editor.formatOnSave": true,
"[typescript]": { "editor.defaultFormatter": "denoland.vscode-deno" }
}
在 vscode 中默认会将 ts 代码认为是 node 运行时环境,因此需要在项目工程下手动配置并启用 deno,让 vscode 以 deno 运行时环境来语法解析 ts 代码。
deno 的一些亮点💡
因为 deno 与 node 一样,都是 javascript 运行时(deno 合理来说是 typescript 运行时)。所以在 javascript 的部分就没什么好说的了,主要对比 deno 相比与 node 的优势,或说我个人觉得一些使用亮点。
官方所介绍的亮点
以下是官方所介绍的亮点,我对其做了翻译
-
提供web 平台功能,采用网络平台标准。例如,使用 ES 模块、Web worker 和支持
fetch()。 -
默认安全。除非显式启用,否则无法访问文件、网络或环境。
-
支持开箱即用的 TypeScript。
-
提供单个可执行文件 (
deno)。 -
为编辑器提供内置的开发工具,如代码格式化程序 (deno fmt)、linter (deno lint)、测试运行程序(deno test)和语言服务器。
-
拥有一组经过审查(审核)的标准模块,保证与 Deno 一起使用。
-
支持使用现有的 npm 模块
以下会针对部分亮点,进行个人的见解。
自带实用工具
deno 则是自带代码格式化(deno fmt)、代码风格(deno lint)、代码测试(deno test)、依赖检查器(deno info)等等的功能。而这些在 node 中,你需要通过第三方的库,如 eslint,jest 才能实现。
你可以在项目工程中添加配置文件 deno.json来定制化代码风格(rust 中也有类似的功能),但在 node 中必须要借助第三方的库,或是 IDE 才能实现。
不过也能理解,在当时的编程环境背景下,javascript 还主要作为前端的脚本语言使用,又怎能让 node 来做相关规范呢?(这句话可能有点不妥)
这点我认为对开发者是否选用你这门语言的一个加分项,并且这些功能也应该作为编程语言所自带的,有官方的背书(保证),对代码风格才更有所保障。
这里有份 官方小抄 可以知道通过deno xxx等命令能够做到 node 原本需要通过第三方库才能实现的功能。
| Node.js | Deno |
|---|---|
node file.js | deno run file.js |
ts-node file.ts | deno run file.ts |
npm i -g | deno install |
npm i / npm install | n/a |
npm run | deno task |
eslint | deno lint |
prettier | deno fmt |
rollup / webpack / etc | deno bundle |
package.json | deno.json / deno.jsonc / import_map.json |
tsc | deno check |
typedoc | deno doc |
jest / ava / mocha / tap / etc | deno test |
nodemon | deno run/lint/test --watch |
nexe / pkg | deno compile |
npm explain | deno info |
nvm / n / fnm | deno upgrade |
tsserver | deno lsp |
nyc / c8 / istanbul | deno coverage |
benchmarks | deno bench |
远程导入
与 node 不同,使用 node 通常需要从 npm 官方包来下载并导,有 npm 这样的包管理器来统一管理这些包(package),我们通常称这种为中心化,而 deno 与 go 的做法很像,你可以将你的封装好的代码定义成一个包,并将其放在任何网络可访问的地方,比如 github,或是私有地址,然后通过网络读取文件的方式来导入,这种称为去中心化。
关于中心化与去中心化管理,各有优缺,这里不做细致讨论。
以下是 deno 官方远程导入的代码示例:
import { add, multiply } from 'https://x.nest.land/ramda@0.27.0/source/index.js'
function totalCost(outbound: number, inbound: number, tax: number): number {
return multiply(add(outbound, inbound), tax)
}
console.log(totalCost(19, 31, 1.2))
console.log(totalCost(45, 27, 1.15))
/**
* Output
*
* 60
* 82.8
*/
而这里的 https://x.nest.land/ramda@0.27.0/source/index.js 可以替换成任何 ES module 特性(import/export)的模块。
http 的方式运行代码
既然都能通过 http(cdn)远程导入模块,那远程运行文件自然也不成大问题。有时候像快捷体验一下别人的代码,或是想要在浏览器中运行一下代码,这时候就可以通过 http 的方式来运行代码。
这里我准备了一段代码,并部署到我的站点上,你可以通过如下命令得到该代码的执行结果(如果你有安装 deno 的话),放心这段代码并无危害,就是一段简单的 console.log 输出。
deno run https://deno.kuizuo.cn/main.ts
在第一次使用时下载并缓存代码,你可以通过
deno info http://deno.kuizuo.cn/main.ts
来查看文件信息,如下

deno info 还可以查看 deno 的相关配置,默认缓存都设置在 C 盘,你也可以设置DENO_DIR 环境变量来更改 deno 目录,可以到 Set Up Your Environment 查看 deno 相关环境变量。
依赖管理
经常使用 node 的开发者应该对 node 的依赖感到无比厌烦,关于这部分强烈建议看 node_modules 困境,你就能知道 node 的 node_modules 设计的是有多少问题。看完你也就能知道为啥越来越多的 node 项目都使用 pnpm 作为包管理。
虽然 node 有了 pnpm 包管理器这种情况会好一些,但本质在项目目录还是需要 node_modules 文件。也许你用过其他语言的包管理器,你会发现基本都是将所有用到的依赖全局缓存起来,当不同的项目工程需要用到依赖时,直接去全局缓存中找,而不是像 npm 一样,下载到项目工程目录下,存放在 node_modules 里。
而 deno 也是采用这种这种方式,no npm install,no package.json,no node_modules/ ,使用 npm 包可以像下面这样,当你使用 deno run 时便会下载好依赖置全局缓存中。
// @deno-types="npm:@types/express@^4.17"
import express from 'npm:express@^4.17'
const app = express()
app.get('/', (req, res) => {
res.send('Hello World')
})
app.listen(3000)
console.log('listening on http://localhost:3000/')
deno 刚发布的时候,甚至还不支持 NPM 软件包,这无非是要告诉用户 deno 社区没有轮子,要求用户自己去造一个。不过 deno 团队还是做出了比较正确的选择,支持 npm 软件包,并且还非常友好。
不过如果你在 deno 中使用了 npm 包,可能会存在一些兼容性问题,万一遇到了,也可以通过添加 --node-modules-dir 标识,在当前运行目录下创建 node_modules 文件夹。详见 --node-modules-dir flag