Deno 是什么?Deno 和 Node 有什么关系?Deno 和我有什么关系?前端
Deno 将于 2020-05-13 发布 1.0,若是你还有上面的疑惑,能够和我一块儿经过Deno 1.0: What you need to know这篇文章一块儿了解 Deno 基础知识。node
但愿你带着疑问思考,将来 10 年看今天,会不会出现 Deno 官方生态壮大,彻底替代 Node 进而影响到 Web 生态的局面呢?这个思考结果会影响到你将来职业发展,你须要学会本身思考,并对这个思考结果负责。react
Deno 的做者是 Ryan Dahl,他是 Nodejs 背后的策划者,曾经说过我对 Nodejs 感到遗憾的 10 件事。这也是为何新开一个坑的缘由,但 Deno 并不定位为 Nodejs 的替代品,从总体功能来看,Deno 有更大的野心,据个人推测是想要取代如今陈旧的先后端开发模式,让 Deno 一统先后端开发全流程。webpack
Nodejs 是由 C++ 写的,而 Deno 则是由 Rust 写的,并选择了Tokio这个异步编程框架,并使用 V8 引擎解析 Javascript,并内置了对 Ts 的解析。git
Deno 支持以下安装方式:github
Shell:web
curl -fsSL https://deno.land/x/install/install.sh | sh
PowerShell:shell
iwr https://deno.land/x/install/install.ps1 -useb | iex
Homebrew:npm
brew install deno
Chocolatey:编程
choco install deno
脚本执行方式为deno run
,能够类比为node
,但功能不一样且支持远程文件,实际上远程依赖是 Deno 的一大特点,也是有争议的地方:
deno run https://deno.land/std/examples/welcome.ts
在 ts 文件中容许用远程脚本加载资源,这个后面还会提到:
import { serve } from "https://deno.land/std@v0.42.0/http/server.ts"; const s = serve({ port: 8000 }); console.log("http://localhost:8000/"); for await (const req of s) { req.respond({ body: "Hello World\n" }); }
Deno 是默认安全的,这体如今默认没有环境、网络访问权限、文件读写权限、运行子进程的能力。因此若是直接运行一个依赖权限的文件会报错:
deno run file-needing-to-run-a-subprocess.ts # error: Uncaught PermissionDenied: access to run a subprocess, run again with the --allow-run flag
能够经过参数方式容许权限的执行,有--allow-read
、--allow-write
、--allow-net
等:
deno --allow-read=/etc
上面表示/etc
文件夹下的文件拥有文件读权限。
除了直接加参数调用、Bash 脚本调用外,还能够用 Make 运行,或者使用相似的drake启动。
或者使用deno install
命令,将脚本转化为一个快捷指令:
deno install --allow-net --allow-read -n serve https://deno.land/std/http/file_server.ts
-n
表示--name
,能够对这个脚本进行重命名,好比上面的例子中,serve
命令就等同于deno run --allow-net --allow-read https://deno.land/std/http/file_server.ts
。
Deno 在标准库上颇有特色,对经常使用功能提供了官方版本,保证可用性与稳定性。原文中列出了一些与 Npm 三方库的对比:
从这个点上来看,Deno 既作运行环境又作基础生态,缓解了 Npm 生态下选择困难症,这件事须要辩证来看:集成了官方包对功能肯定的模块来讲是颇有必要的,并且提升了底层库的稳定性;但 Deno 生态也有三方库,并且本质上三方库和官方库在功能上没有任何壁垒,由于实现代码都相似,惟一区别是谁能为其稳定性站台,假设微软和 Deno 同时出了基于 Npm 生态与 Deno 生态官方库,都保证会持续维护,你更相信谁呢?官方是否有优点要取决于官方自身的实力。
Deno 内置支持了 TS,所以不须要ts-node
咱们就能够用deno run test.ts
运行 Typescript 文件。值得注意的是,Deno 内部也是利用 Typescript 引擎解析为 Js 后交由 V8 引擎解析,所以本质上没太大的变化,只是这样 Deno 的生态会更规范。
因为内置了 TS 支持,天然也不须要写tsconfig.json
配置了,但你依然能够定制它:
deno run -c tsconfig.json [file-to-run.ts]
Deno 默认还开启了 TS 严格模式,因此看到这里,能够认为 Deno 是为了构建高质量理想库而诞生的运行环境,基于已有的生态来作,但作了更多内置技术选型,这和 Facebook 的rome很像,但作的却更完全。
其实从实现上来看,咱们基于 Javascript 生态也能写出deno run test.ts
这样相似的引擎,只不过是由 JS 驱动执行,可能编译还会选择 Webpack,但 Deno 自己基于 Rust 实现,并从新实现了一套模块加载标准,能够说从更底层的方式从新解读了 W3C 标准规范,以指望解决 Javascript 生态的各类痛点问题。
Deno 还支持 W3C 标准规范,所以像fetch
、setTimeout
等 API 均可以被直接使用,若是你按照 Deno 支持的那几个函数写代码,能够保证在 Deno、Node、Web 三个平台实现跨平台运行。
虽然距离彻底实现 W3C 全部标准规范还有一些路要走,但咱们看到了 Deno 兼容规范的决心。
模块化是 Deno 的亮点,Deno 使用官方 ESModule 规范,但引用路径必须加上后缀:
import * as log from "https://deno.land/std/log/mod.ts"; import { outputToConsole } from "./view.ts";
Deno 不须要申明依赖,代码的引用路径就是依赖申明,会包括完整的路径以及文件后缀,也支持网络资源,能够摆脱 NPM 中心化的包管理模式,由于这个路径能够是任何网络地址。
对于import * as log from "https://deno.land/std/log/mod.ts";
这行代码,Deno 会下载到一个缓存文件夹,用户不会感知到这个文件夹与这个过程的存在,也就是说,Deno 环境中是没有node_modules
的。
也能够经过deno --reload
的方式强制刷新缓存。
但这里也要辩证的看待 “Deno 去中心化” 这件事,虽然引用了网络源,但会引起下面几个问题:
deps.ts
使用,这个后面会提到。即便被打上 “中心化恶人” 的 npm 也有去中心化的一面,由于 npm 支持私有化部署,不管是速度仍是稳定性均可以由公司本身掌控,从稳定性来讲仍是 npm 拥有压倒性优点。
Deno 还有第三方库生态,截止目前共有221 个三方库 "%5B%5D(https://deno.land/x/)")。
因为 Deno 走网络资源,咱们能够借助Pika提供的 CDN 服务直接引用网络资源包:
import * as pkg from "https://cdn.pika.dev/preact@^10.3.0";
虽然这样看上去很轻量,但对公司来讲仍是须要自建一个 “Pika” 保障稳定性,以及作全球 CDN 缓存等的工做。
npm 生态下包信息存放在package.json
,包含但不限于下面的内容:
dependencies
、devDependencies
甚至peerDependencies
。main
和module
,还有 TS 用的types
与typings
,脚手架的bin
等等。随着标准的不断更新,package.json
信息已经很是臃肿了。
对于 Deno 来讲,则使用deps.ts
集中管理依赖:
export { assert } from "https://deno.land/std@v0.39.0/testing/asserts.ts"; export { green, bold } from "https://deno.land/std@v0.39.0/fmt/colors.ts";
deps.ts
就是一个普通文件,只是将项目的依赖精确描述出来,这样其余地方引用assert
时,就能够这么写了:
// import { assert } from "https://deno.land/std@v0.39.0/testing/asserts.ts"; import { assert } from "./deps.ts";
若是须要锁定依赖,能够经过deno --lock=lock.json
方式申明。
deno doc <filename>
命令能够根据文件按照 JS Doc 规则生成文档,同时也支持 TS 语法,好比下面这段代码:
/** Asynchronously fulfill a response with a file from the local file * system. */ export async function send( { request, response }: Context, path: string, options: SendOptions = { root: "" } ): Promise<string | undefined> { // ... }
生成文档以下:
function send(_: Context, path: string, options: SendOptions): Promise<string | undefined> Asynchronously fulfill a response with a file from the local file system.
deno 自己文档就是用这个命令生成的,能够访问官方文档查看使用效果。
前端 Javascript 工具链至关混乱,虽然业界已有 Umi 等框架作了开箱即用的封装,但回到 Javascript 设计的初衷就是能够在浏览器直接使用的,包括浏览器对不依赖构建工具的模块化支持,注定了将来 Webpack 必定会被消灭。
Deno 经过内置一套工具链的方式解决这个问题,包括:
deno test
命令与Deno.test()
测试函数。deno bundle
命令。不过值得注意的是,在最重要的编译环节,deno bundle
目前提供的能力是相对欠缺的,好比还不支持 Tree Shaking。
用 Rust 等语言提高构建效率是业界一直在尝试的事,好比 @陈成 就基于esbuild作了@umijs/plugin-esbuild插件用于提高 Umi 构建速度,但为了防止生产构建产物与 Webpack 默认规则不一致,仅使用了其压缩(minifier)功能。
对 deno 来讲也同样,目前其实没有任何证据代表 deno 的构建结果能够完美适配 webpack 环境,因此请勿认为 deno 发布了 1.0 版本就等于能够在生产环境使用。
正如原文结尾所说的,Deno 虽然将要发布 1.0 版本,但仍不能彻底替代 Nodejs,这背后的缘由主要是历史兼容成本,也就是完整支持整个 Node 生态不仅是设计的问题,更是一个体力活,须要一个个高地去攻克。
一样 Deno 对 Web 的支持也让人耳目一新,但仍不能放到生产环境使用,除了官方和三方生态还在逐渐完善外,deno bundle
对 Tree Shaking 能力的缺失以及构建产物没法保证与如今的 Webpack 彻底相同,这样会致使对稳定性要求极高的大型应用迁移成本很是高。
最亮眼的改动是模块化部分,依赖彻底去中心化从长远来看是一个很是好的设计,只是基础设施和生态要达到一个较为理想的水平。
最后,让咱们站在一个预言者角度思考一下 Deno 到底会不会火吧:
Deno 作的初心是作一个更好的 Node,但很不信,对于这种级别的生态底层工具来讲,从新作一个并从新火起来的难度,不亚于从新作一个阿里巴巴并取代如今阿里的难度。也就是不一样的时间点作同一件事,哪怕后者能够吸收教训,大几率也没法复制之前成功的路线。
从 Deno 的功能来看,解决了 Node 不少痛点,其中就包括去中心化管理,有点云开发的意思,但在 2020 年,基于 Nodejs 和 Webpack 的云开发都搞出来了,说实话是没有 Deno 什么空间的。从功能上来看,开篇就说了 Deno 基于 V8 解析 Javascript,对于性能和功能都没有革命性提高,从技术上做出突破也几乎不可能了。
Deno 的思想确实比 Node 先进,但不能说比 Node 好十倍,则没法撼动 Node 的生态,即使是 Node 做者本身可能也不行。
然而我上面说的可能都是错的。