特性与优缺点
特性与优缺点
特性
Deno 含有以下功能亮点:
-
默认安全。外部代码没有文件系统、网络、环境的访问权限,除非显式开启。
-
支持开箱即用的 TypeScript 的环境,尽管它仍需要编译为 JavaScript 才能运行,但这是在内部完成的,因此对用户来说 TypeScript 的行为就好像它是原生支持的一样。
-
只分发一个独立的可执行文件(deno)。
-
有着内建的工具箱,比如一个依赖信息查看器(deno info)和一个代码格式化工具(deno fmt)。
-
有一组经过审计的标准模块,保证能在 Deno 上工作。
-
脚本代码能被打包为一个单独的 JavaScript 文件。
安全性
默认情况下,Deno 是安全的。相比之下,Node.js 拥有对文件系统和网络的完全访问权限。要在没有权限的情况下运行程序,请使用:
deno run file-needing-to-run-a-subprocess.ts
如果代码需要权限设置,则会提醒你。
error: Uncaught PermissionDenied: access to run a subprocess, run again with the –allow-run flag
Deno 使用命令行选项来显式许可访问系统的各个部分。最常用的包括:环境访问 网络访问,文件系统读 / 写访问,运行一个子进程,要查看权限示例的完整列表,请输入 deno run -h。
这里的最佳实践是在 read、write 和 net 上使用权限白名单。这样你就可以更清楚地了解 Deno 被允许访问哪些内容。例如,要允许 Deno 在 /etc 目录中只读文件,请使用:deno –allow-read=/etc
标准库
Deno 标准库是由 Deno 项目维护,并保证可用于 Deno 的常用模块集合。它涵盖了用户最常用的常见任务代码,并且是基于 Go 编程语言提供的标准库。JavaScript 一直以来困扰用户的一个问题就是缺乏标准库。用户被迫一次又一次地重新发明轮子,开发人员不得不经常在 npm 上搜索第三方模块,以解决本应由平台制造商解决的常见问题。
React 之类的库可以解决很多复杂问题,这些第三方包很好用。但是对于 UUID 生成等简单的事情来说,我们最好使用官方的标准库。这些小型库可作为大型库的构建块,从而加快了开发速度并减少了开发人员的负担。曾一度流行的库被遗弃,留给用户自己维护或者需要用户找一个替代品的事情时有发生。
内置 TypeScript
TypeScript 是添加了显式类型的 JavaScript。任何有效的 JavaScript 代码也是有效的 TypeScript 代码,因这个将你的代码转换为 TypeScript 是非常容易的。只需将扩展名更改为.ts 并开始添加类型即可。
要在 Deno 中使用 TypeScript 无需执行任何操作。没有 Deno 时,必须将 TypeScript 编译为 JavaScript 才能运行。Deno 会在内部为你完成这个步骤,让 TypeScript 更容易上手。
尽可能使用 Web 标准
创建一个 Web 标准需要很长时间,但一旦标准被确定下来,我们就不应该忽略它。虽然框架来来去去,但 Web 标准是会长期存在的。花费在学习标准化 API 上的时间永远不会白费,因为没有人敢于破坏 Web;它可能已经使用了数十年,甚至可能在你剩下的职业生涯中一直发光发热。
fetch 这个 Web API 提供了用于提取资源的接口。浏览器中有一个 JavaScript fetch() 方法。如果你想在 Node.js 中使用这个标准,则需要使用第三方库 Node Fetch。在 Deno 中它是内置的,并且就像浏览器版本一样开箱即用。
ECMAScript 模块
相比 Node.js,Deno 的一项主要进步是它使用了官方的 ECMAScript 模块标准,而不是老式的 CommonJS。Node.js 直到 2019 年底才在 13.2.0 版本中启用 ECMAScript 模块,但支持还是不够成熟,并且仍然包含有争议的.mjs 文件扩展名。
Deno 在模块系统中使用了现代 Web 标准,从而避免了旧时代的影响。模块使用 URL 或文件路径引用,并包含必需的文件扩展名。例如:
import * as log from "https://deno.land/std/log/mod.ts";
import { outputToConsole } from "./view.ts";
缺点
包管理器
Deno 包管理器的主要问题是,它在 CI/CD 中很难用。我的意思是,如果你需要快速执行 CI/CD,则必须将所有软件包手动加载到你的应用 Git 中(否则,每次 CI/CD 启动后开发人员和测试人员都需要等待从网络加载所有内容——这只是在浪费开发时间和预算)。如果选择 Git 这个选项,那么你的开发人员需要像上世纪那样手动进行所有升级(或者干脆换成带有 NPM 的 Node.js)。
import { connect } from "https://deno.land/x/amqp/mod.ts";
import * as base64 from "https://denopkg.com/chiefbiiko/base64/mod.ts";
import { createLogger } from "https://denolib.com/yamboy1/deno-structured-logging/mod.ts";
...
另外,我不喜欢 Deno 不在一个文件中指示所有包的做法。在大型企业级应用程序中这是会造成混乱的。试想一下,超过 20 位开发人员无需任何系统化方法即可导入软件包。而且根本没有版本控制(仅在某些 URL 中或手动创建的带有依赖项文件中才有,这不是严格的默认设置)。我认为这是不对的。
包
我希望 Deno 具有所有 Express 功能,这样就不用任何框架了。但 Deno 并没有这样做,而是引入了那个 Oak 框架(“Oak”是它的名字):
为了记录日志,我们需要再导入一个包:
https://deno.land/x/deno_structured_logging
为了其他一些简单的开发功能——我们需要越来越多的包:
奇怪的是,Deno 默认(“开箱即用”)几乎没有集成其中的任何功能,要知道它的使用场景是非常清晰的。至少应该集成最基本的功能,例如路由、日志记录和调试吧。
安全策略
Deno 的安全策略仅适用于相对较小的应用程序。大型企业应用程序需要大量权限,因此在我看来,我们必须为每个软件包指定策略。这就是为什么我们需要一个带有包的根文件或生成器(用于单体应用、服务等)的原因所在。使用现在的方法时,如果一个包被感染,并且在应用级别为另一个包提供了权限(所以被感染的程序包将具有该权限),那么整个应用的这个权限都会失效。
deno run --allow-net .\main.ts
# it allows running the server via the net
# basically, there is one permission for the whole app right now