简介
Deno简略说是Node.js的替代品,是Node.js之父Ryan Dahl 为挽回Node.js的谬误而开发的。
Node.js存在的问题有:
- npm包治理(node_modules)简单。
- 历史起因导致的api保护,比方晚期变态的callback设置。
- 没有安全措施,用户只有下载了内部模块,就只好放任他人的代码在本地运行,进行各种读写操作。
- 性能不欠缺,导致各种工具层出不穷,比方webpack、babel等。
因为下面这些起因,Ryan Dahl 决定放弃 Node.js,从头写一个替代品,彻底解决这些问题。
deno 这个名字就是来自 Node 的字母重新组合(Node = no + de),示意"拆除 Node.js"(de = destroy, no = Node.js)。
跟 Node.js一样,Deno 也是一个服务器运行时,然而反对多种语言,能够间接运行 JavaScript、TypeScript 和 WebAssembly 程序。
- 它内置了 V8 引擎,用来解释 JavaScript。同时,也内置了 tsc 引擎,解释 TypeScript。
- 它应用 Rust 语言开发,因为 Rust 原生反对 WebAssembly,所以它也能间接运行 WebAssembly。
- 它的异步操作不应用 libuv 这个库,而是应用 Rust 语言的 Tokio 库,来实现事件循环(event loop)。
它的架构如下图所示:
阐明:
1、Rust 是由 Mozilla 主导开发的通用、编译型编程语言。设计准则为 “平安、并发、实用”,反对函数式、并发式、过程式以及面向对象的编程格调。Deno 应用 Rust 语言来封装 V8 引擎,通过 libdeno 绑定,咱们就能够在 JavaScript 中调用隔离的性能。
2、Tokio 是 Rust 编程语言的异步运行时,提供异步事件驱动平台,构建疾速,牢靠和轻量级网络应用。利用 Rust 的所有权和并发模型确保线程平安。Tokio 构建于 Rust 之上,提供极快的性能,使其成为高性能服务器应用程序的现实抉择。在 Deno 中 Tokio 用于并行执行所有的异步 IO 工作。
3、V8 是一个由 Google 开发的开源 JavaScript 引擎,用于 Google Chrome 及 Chromium 中。V8 在运行之前将JavaScript 编译成了机器代码,而非字节码或是解释执行它,以此晋升性能。更进一步,应用了如内联缓存(inline caching)等办法来进步性能。有了这些性能,JavaScript 程序与 V8 引擎的速度媲美二进制编译。在 Deno 中,V8 引擎用于执行 JavaScript 代码。
劣势
Deno凭什么来吸引开发者改换门庭,转投它的怀抱呢?于我而言,次要有以下几点:
- 人造反对ts。如果用Node.js,须要咱们手动将ts编译成js,或者应用ts-node这种第三方工具。Deno不须要配置,开箱即用。
- 内存平安。相较于Node.js,它的性能劣势并不显著,因为就是js换了个运行环境而已,Rust并不见得比C++更高效,不过Rust会人造让它的内存平安和外围代码的健壮性更有保障些。
- 平安机制。除非明确启用,否则没有文件,网络或环境拜访权限。对于运行权限的划分,能清晰晓得你的程序须要领有哪些权限,对网络资源没有信赖的同学能够释怀了。
- 没有历史包袱。不像Node.js一开始自定义了commonjs标准,Deno间接反对ES Modules。没有回调天堂,代码构造更清晰,利于tree shaking;也能够间接应用顶级await。
- 去中心化。不必每个工程都装置一大堆node_modules,有个线上的url就能获取代码。
- 内置浏览器API。Deno实现了fetch、FormData、WebSocket等浏览器的API,尽管被某些开发者诟病,但对前端开发者而言是真的敌对,比方进行接口调用,与在浏览器里应用简直没有区别。
- 全家桶似的服务,比方打包、格式化、代码校验,能够让你更专一业务,而不是成为某工具的配置工程师。
毛病
Deno的毛病也很显著:
没有针对Node.js压倒性的性能劣势,所以对以上劣势不感兴趣的开发者而言,就没有吸引力了。
Deno 是一个适合的异步服务器,每秒 25k 申请足以满足大多数目标,此外,因为广泛应用 Promise,Deno 有更好的尾部提早。目前 Deno HTTP 服务器每秒解决约 25 000 个申请,最大提早为 1.3 毫秒,与之相比,Node 程序每秒解决 34 000 个申请,最大提早介于 2 到 300 毫秒之间。
能够看出,Deno的劣势在于提早低,但并没有压倒性劣势。- 无奈齐全继承Node.js的生态。尽管Deno提供了几款CDN服务,能够将旧的npm包转换为Deno可应用的格局,但并非所有npm包都能转换胜利。因为Node.js仍有局部API官网没有实现,如果某个偏底层的包转换失败,所有依赖它的包都无奈胜利。所以,你很有可能在开发的某个环节须要造轮子。当然,这对于喜爱钻研技术的同学而言反而是个利好。
去中心化后,国内就没有方法像npm做镜像,官网搭建deno.land来存储github上各种资源,但目前只反对github上公有资源。想要援用公有文件,就必须本人搭建服务器,在CICD中构建的话,又有额定的技术难点须要解决。
装置
1、 Mac/Linux
鉴于国内的网速起因,@justjavac 大佬搞了国内的镜像减速:
curl -fsSL https://x.deno.js.cn/install.sh | sh
我用Linux部署后,报没有glibc-2.18这个版本依赖。
按网上教程,又装置了一下:
curl -O http://ftp.gnu.org/gnu/glibc/glibc-2.18.tar.gztar zxf glibc-2.18.tar.gzcd glibc-2.18/mkdir buildcd build/../configure --prefix=/usrmake -j2make install
后两步比较慢,不要退出。
2、Windows
https://github.com/denoland/deno/releases
间接在这里下载exe文件吧。
当然,Mac与Linux也能够这样装置,但最新的Mac零碎可能会因为平安权限而禁止程序应用,须要参考这里配置下。
设置环境变量
你可能还须要设置环境变量。以下是Mac/Linux命令行操作:
echo 'export DENO_INSTALL="$HOME/.deno"export PATH="$DENO_INSTALL/bin:$PATH"export DENO_DIR=$HOME/.deno' >> ~/.bash_profilesource ~/.bash_profile
测试
deno --version
降级
deno upgrade
或降级到特定版本,例如v1.3.0
:
deno upgrade --version 1.3.0
平安机制
Deno 具备安全控制,默认状况下脚本不具备读写权限。如果脚本未受权,就读写文件系统或网络,会报错。
必须应用参数,显式关上权限才能够。
--allow-read:关上读权限,能够指定可读的目录,比方--allow-read=/temp。--allow-write:关上写权限。--allow-net=google.com:容许网络通信,能够指定可申请的域,比方--allow-net=google.com。--allow-env:容许读取环境变量。--allow-run:容许运行子过程。
要应用不稳固的新个性,须要这样:
--unstable
还有新加的--allow-ffi
和--allow-hrtime
,个别用不到,这里不再赘述,请情参考官网文档。
运行
应用deno run来运行程序,当然,个别须要加上下面的平安机制。
如果你的程序什么权限都没应用,只是上面这种:
console.log('app start');
那么间接用deno run main.ts就能够了。
留神,咱们举荐应用ts,但也能够运行js。
如果须要读取文件,比方
const decoder = new TextDecoder("utf-8");const data = await Deno.readFile("hello.txt");console.log(decoder.decode(data));
天然得这样:deno run --allow-read main.ts
如果须要网络,比方开启一个tcp:
/** * echo_server.ts */import { copy } from "https://deno.land/std@0.106.0/io/util.ts";const listener = Deno.listen({ port: 8080 });console.log("listening on 0.0.0.0:8080");for await (const conn of listener) { copy(conn, conn).finally(() => conn.close());}
你必须:deno run --allow-net main.ts
如果懒得管理权限,则应用-A
(deno run -A main.ts
),那就后果自负了。
当然,也能够运行近程服务器上的文件,比方官网的hello world
:
deno run https://deno.land/std/examples/welcome.ts
更新模块
默认代码中援用中的ts或js文件,会缓存到本地。如果你援用的文件url中没有带版本号,那么就是最新版的代码。这时,你想要更新代码,那么你须要这样操作:
deno cache --reload my_module.ts
更新线上与本地文件:
deno cache --reload=https://deno.land/std@0.106.0 my_module.ts
更新线上某个文件与某文件夹:
deno cache --reload=https://deno.land/std@0.106.0/fs/copy.ts,https://deno.land/std@0.106
锁定文件校验
举荐建一个deps.ts
文件,来治理内部援用的文件。其实就是起到相似package-lock.json
的作用,治理援用的文件与版本。
// deps.tsexport { xyz } from "https://unpkg.com/xyz-lib@v0.9.0/lib.ts";
而后用deno cache
生成一个lock.json
文件:
# Create/update the lock file "lock.json".deno cache --lock=lock.json --lock-write deps.ts
另一台机器克隆下代码,运行后:
# Download the project's dependencies into the machine's cache, integrity# checking each resource.deno cache --reload --lock=lock.json deps.ts# Done! You can proceed safely.deno test --allow-read src
导入地图
能够应用带有--import-map=<FILE>CLI
标记的导入映射,这样开发时应用体验相似于Node.js了。
不过如果是公布给他人应用的模块,不倡议用它,因为这须要他人也把你的map文件复制过去。
例:import_map.json
{ "imports": { "fmt/": "https://deno.land/std@0.106.0/fmt/" }}
main.ts:
import { red } from "fmt/colors.ts"; console.log(red("hello world"));
而后:
deno run --import-map=import_map.json main.ts
来自CDN的包
目前,举荐将共享的代码公布在官网搭建的平台https://deno.land/x/上,它的公布也很简略,在你的github仓库里配置一个web hook,就能够了。
具体详见疏导,非常简单,这里不再赘述。
esm.sh
https://esm.sh/是个转换npm包为Deno应用的线上地址,它应用esbuild进行转换,速度很快。比方咱们要应用React,能够这样间接应用:
import React from "https://esm.sh/react";export default class A extends React.Component { render() { return <div></div>; }}
当然也反对版本号:
import React from "https://esm.sh/react@17.0.2";
Skypack
https://www.skypack.dev/也是相似:
import React from "https://cdn.skypack.dev/react";export default class A extends React.Component { render() { return <div></div>; }}
装置脚本
应用deno install能够不便地装置一个脚本,相似于npm i -g xxx
模块。
$ deno install --allow-net --allow-read https://deno.land/std@0.106.0/http/file_server.ts[1/1] Compiling https://deno.land/std@0.106.0/http/file_server.ts✅ Successfully installed file_server./Users/deno/.deno/bin/file_server
打包
打包为js
能够打包线上或本地文件为一个js文件:
deno bundle https://deno.land/std@0.106.0/examples/colors.ts colors.bundle.jsdeno bundle main.ts main.js
打包后的文件是能够运行的:
deno run -A bundle.js
因为导出的是个ES模块化的代码,甚至能够放到浏览器里应用:
<script type="module" src="website.bundle.js"></script>
或者在另一个js里援用:
<script type="module"> import * as website from "website.bundle.js";</script>
编译为可执行文件
deno compile https://deno.land/std/examples/welcome.ts
也能够通过增加--targetCLI
标记为其余平台编译二进制文件,比方在linux服务器上打包一个exe文件供windows应用。详见此处。
生成文档
deno doc后跟一个或多个源文件的列表将打印每个模块导出成员的 JSDoc 文档。
例如,给定一个add.ts蕴含以下内容的文件:
/** * Adds x and y. * @param {number} x * @param {number} y * @returns {number} Sum of x and y */export function add(x: number, y: number): number { return x + y;}
运行 deno doc命令,将函数的 JSDoc 正文打印到stdout。
应用--json
标记以 JSON 格局输入文档。这种 JSON 格局由 deno doc 网站应用,用于生成模块文档。
代码格调
格式化
应用deno fmt
。它会将代码格式化为官网举荐的样子,其实起到的相似eslint --fix
的成果。
# format all JS/TS files in the current directory and subdirectoriesdeno fmt# format specific filesdeno fmt myfile1.ts myfile2.ts# check if all the JS/TS files in the current directory and subdirectories are formatteddeno fmt --check# format stdin and write to stdoutcat file.ts | deno fmt -
代码校验
应用deno lint
。有了它,就不用再应用eslint
了。
# lint all JS/TS files in the current directory and subdirectoriesdeno lint# lint specific filesdeno lint myfile1.ts myfile2.ts# print result as JSONdeno lint --json# read from stdincat file.ts | deno lint -
编码格调指南
参见官网指南,举几条对咱们有用的:
- 应用 TypeScript 而不是 JavaScript
- 在文件名中应用下划线,而不是破折号
- 不要应用文件名index.ts/ index.js。入口文件应用mod.ts/mod.js
- 导出的函数:最多 2 个参数,将其余的放入选项对象中
- 顶级函数不应应用箭头语法。顶级函数应该应用function关键字。箭头语法应该仅限于闭包
调试
像Node.js一样,Deno程序也能够在chrome浏览器中调试,具体就不介绍了。
次要说下vscode中调试。
须要在我的项目根目录下配置.vscode/launch.json
文件,内容大略如下:
{ "version": "0.2.0", "configurations": [ { "name": "Deno: Run", "request": "launch", "type": "pwa-node", "program": "src/main.ts", // 具体文件门路 "cwd": "${workspaceFolder}", "runtimeExecutable": "deno", "runtimeArgs": [ "run", "--unstable", "--inspect", "--allow-all" ], "attachSimplePort": 9229 } ]}
如果你的入口文件有多个,写起来比拟麻烦,能够这样:
{ "version": "0.2.0", "configurations": [ { "name": "Deno", "type": "pwa-node", "request": "launch", "cwd": "${workspaceFolder}", "runtimeExecutable": "deno", "runtimeArgs": [ "run", "--inspect-brk", "-A", "--config", "tsconfig.json", "--unstable", "${file}" ], "attachSimplePort": 9229 } ]}
详情能够参考这里。
各大支流库代替计划
Electron
咱们晓得,当初Electron是个优良的桌面端解决方案,咱们罕用的vscode就是用它写的,基于Node.js + Chromium 的 Electron 来依靠 Web 技术栈创立桌面应用程序。那么咱们能够在 Deno 下应用 Electron 吗?或者还有其它更多抉择吗?
答案是现在的 Electron 还远远不能运行在 Deno 上,咱们必须寻找其它的解决方案。自从 Deno 抉择用 Rust 语言构建其内核后,咱们能够应用 Rust 生态上的 Web View @Bosop/web-view 来在 Deno 上运行桌面利用。
于是 @eliassjogreen/deno_webview 应运而生。
import { Webview } from "https://deno.land/x/webview/mod.ts";const html = ` <html> <body> <h1>Hello from deno v${Deno.version.deno}</h1> </body> </html>`;const webview = new Webview( { url: `data:text/html,${encodeURIComponent(html)}` },);await webview.run();
pm2
咱们应用pm2
来守护Node.js
过程,能够让代码运行在后盾。事实上,它也能够运行 Node.js
之外的的脚本语言。
所以,如果要运行deno,须要创立一个app.sh
文件:
#!/bin/bashdeno run -A main.ts
再应用pm2启动:
pm2 start ./app.sh
Express / koa
这俩Node.js祖师爷级别的web框架,在deno里当然少不了,Express不倡议应用,举荐用koa的高仿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 });
nestjs
nestjs
是一个用于构建高效、可扩大的Node.js服务器端应用程序的开发框架。它利用 JavaScript 的渐进加强的能力,应用并齐全反对 TypeScript(依然容许开发者应用纯 JavaScript 进行开发),并联合了 OOP (面向对象编程)、FP (函数式编程)和 FRP (函数响应式编程)。从它身上,咱们能看到Spring和Angular的影子。
咱们能够利用nestjs
轻松构建一个REST服务,以Controlller的用法为例:
@Controller('cats')export class CatsController { @Get() findAll(): string { return 'This action returns all cats'; }}
官网目前并没有打算做deno的版本,所以我基于oak实现了一个简版的oak_nest
,包含Controller、平安守卫和各类参数装璜器。感兴趣的同学能够试用,有问题随时能够找我。
罕用数据库
这里列举俩,其它在这里本人搜寻。
MongoDB
有deno_mongo,有罕用的API。当然,它没有mongoose
那么丰盛,更简单的性能可能就须要你来本人造轮子了。
如果想应用Schema,能够试用deno_mongo_schema,它是基于deno_mongo的扩大。
Redis
有deno-redis。
Nodemon
咱们应用nodemon
来监控Node.js程序,能够主动重启服务,在开发阶段十分不便。
deno中替代品为denon,咱们须要保护一个scripts.json,起到Node.js中package.json里script命令的作用。
一个简略的样例领会下:
# 应用denon dev启动服务scripts: dev: cmd: "deno run example/main.ts" desc: "run example main.ts file" allow: - net - env - write unstable: false lock: lock.json log: info env: PORT: "1000" build: cmd: "deno bundle example/main.ts example/main.js" watch: false
测试工具
在Node.js里,咱们有jest、Jasmine等库,而deno能够应用官网测试std库测试: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 test
nvm
咱们应用nvm来治理Node.js版本,在Deno中有dvm。
在docker中运行
Dockerhub 现已提供 Deno 的官网 Docker 镜像。
- Alpine Linux: denoland/deno:alpine
- Centos: denoland/deno:centos
- Debian: denoland/deno:debian(默认)
- Distroless: denoland/deno:distroless
- Ubuntu: denoland/deno:ubuntu
要在 Docker
外部运行 Deno,咱们能够创立以下 Dockerfile
:
FROM denoland/deno:1.16.2# The port that your application listens to.EXPOSE 1993WORKDIR /app# Prefer not to run as root.USER deno# Cache the dependencies as a layer (the following two steps are re-run only when deps.ts is modified).# Ideally cache deps.ts will download and compile _all_ external files used in main.ts.COPY deps.ts .RUN deno cache deps.ts# These steps will be re-run upon each file change in your working directory:ADD . .# Compile the main app so that it doesn't need to be compiled each startup/entry.RUN deno cache main.tsCMD ["run", "--allow-net", "main.ts"]
而后这样应用:
docker build -t app . && docker run -it -p 1993:1993 app
详见这里。
以下是一个咱们我的项目中的样例:
FROM denoland/deno:alpine-1.16.2EXPOSE 3000WORKDIR /app# Prefer not to run as root.RUN chown -R deno /appRUN chmod 755 /appADD . .ENV DENO_DIR=deno-dirCMD deno run --allow-net --allow-env --allow-write --allow-read --config tsconfig.json --unstable mod.ts
这里设置了DENO_DIR
,起因是在后面CICD
的流水线中,曾经缓存了工程的依赖包在deno-dir
目录下,在这里就不用再下载了。
最佳计划其实是运行打包后的js
文件,这样服务的启动速度能快许多,遗憾的是官网bundle
有个全局命名抵触的bug仍未修复。
据说1.17.0曾经修复了,但因为其它工具包的兼容问题,我还没有验证。
总结
本文次要是为了科普Deno,介绍了它的劣势与毛病,装置应用与罕用Node.js库的代替计划。它相较于Node.js,没有历史包袱,所以能够轻装上阵。
但想要代替Node.js成为前端人员的标配,就不是一年两年能够做到的事件了。除非Deno 真的推出了 Node.js 无奈复制的弱小性能,那才有可能会扭转游戏规则。
Deno当初正在致力做的是兼容Node.js的API,升高后者开发者的迁徙难度,这样才有可能将Node.js长达十余年的生态继承过去。
尽管Deno没有达到石破天惊的成果,但仍是个优良的工具,我看好它。心愿大家都有趣味玩一玩。
参考:
- 20 分钟入门 deno
- Deno手册【官网】
- 从 Node 到 Deno:摸索各大支流库代替计划
- 了不起的 Deno 入门与实战