在这篇文章中,我们将探讨Deno,一个相对较新的工具,作为Node.js的竞争者/替代者,它提供了一个更安全的环境,并且开箱即有TypeScript支持。
我们将使用Deno构建一个命令行工具,向第三方API--星球大战API--发出请求,并看看Deno提供了哪些功能,它与Node有什么不同,以及它的工作情况。
Deno是一个更有主见的运行时,它是用TypeScript编写的,包括它自己的代码格式化器(deno fmt),并使用ES模块--没有看到CommonJSrequire 语句。它在默认情况下也是非常安全的:你必须明确地给你的代码提出网络请求,或从磁盘上读取文件,而这是Node默认允许程序做的事情。在这篇文章中,我们将介绍安装Deno,设置我们的环境,以及建立一个简单的命令行程序来进行API请求。
与以往一样,你可以在GitHub上找到本文的相关代码。
安装Deno
你可以查看Deno网站的完整说明。如果你使用的是macOS或Linux,你可以把这个命令复制到你的终端。
curl -fsSL https://deno.land/x/install/install.sh | sh
你还需要将安装目录添加到你的$PATH 。
如果你在Windows上,也不用担心,因为你可以通过Chocolatey等软件包管理器安装Deno。
choco install deno
如果Chocolatey不适合你,deno_install列出了多种安装方法,请选择最适合你的一种。
你可以通过运行以下命令来检查Deno的安装情况。
deno -V
这应该会输出Deno的版本。在写这篇文章的时候,最新的版本是1.7.5,也就是我所使用的。
如果你使用的是VS Code,我强烈建议你安装Deno VS Code插件。如果你使用其他编辑器,请查看Deno文档以找到合适的插件。
请注意,如果你使用的是VS Code,默认情况下,当你加载一个项目时,Deno插件不会被启用。你应该在你的资源库中创建一个.vscode/settings.json 文件,并添加以下内容来启用该插件。
{
"deno.enable": true
}
同样,如果你不是VS Code的用户,请查看上面的手册,为你选择的编辑器找到正确的设置。
编写我们的第一个脚本
让我们确定我们已经启动并运行了Deno。创建index.ts ,并把下面的内容放在里面。
console.log("hello world!");
我们可以用deno run index.ts 来运行它。
$ deno run index.ts
Check file:///home/jack/git/deno-star-wars-api/index.ts
hello world
注意,我们可能会在编辑器中看到一个TypeScript错误。
'index.ts' cannot be compiled under '--isolatedModules'
because it is considered a global script file. Add an import,
export, or an empty 'export {}' statement
to make it a module.ts(1208)
这个错误发生是因为TypeScript不知道这个文件要使用ES模块导入。它很快就会知道,因为我们要添加导入,但同时,如果我们想消除这个错误,我们可以在脚本的底部添加一个空的export 语句。
export {}
这将使TypeScript编译器相信我们正在使用ES模块,并摆脱错误。我不会在博文中的任何代码样本中包括这个,但如果我们添加它,除了消除TypeScript的噪音外,不会有任何改变。
在Deno中获取
Deno实现了对我们习惯于在浏览器中使用的相同的Fetch API的支持。它内置在Deno中--这意味着没有软件包需要安装或配置。让我们看看它是如何工作的,向我们将在这里使用的API,即星球大战API(或SWAPI)发出第一个请求。
向https://swapi.dev/api/people/1/ 发出请求,我们将得到我们需要的关于天行者卢克的所有数据。让我们更新我们的index.ts 文件来发出这个请求。更新index.ts ,看起来像这样。
const json = fetch("https://swapi.dev/api/people/1");
json.then((response) => {
return response.json();
}).then((data) => {
console.log(data);
});
试着在你的终端中用deno run 来运行这个。
$ deno run index.ts
Check file:///home/jack/git/deno-star-wars-api/index.ts
error: Uncaught (in promise) PermissionDenied: network access to "swapi.dev", run again with the --allow-net flag
throw new ErrorClass(res.err.message);
Deno默认是安全的,这意味着脚本需要有权限来做任何可能被认为是危险的事情--比如读/写文件系统和进行网络请求。我们必须在Deno脚本运行时给予它们权限,以允许它们执行此类操作。我们可以用--allow-net 标志来启用我们的。
$ deno run --allow-net index.ts
Check file:///home/jack/git/deno-star-wars-api/index.ts
{
name: "Luke Skywalker",
...(data snipped to save space)...
}
但是这个标志已经给了脚本访问任何URL的权限。我们可以更明确一些,只允许我们的脚本访问我们添加到允许列表中的URL。
$ deno run --allow-net=swapi.dev index.ts
如果我们运行的是我们自己编写的脚本,我们可以相信它们不会做任何不该做的事情。但是,很高兴知道,在默认情况下,我们执行的任何Deno脚本在没有得到我们允许的情况下都不会做任何破坏性的事情。从现在开始,每当我在本文中谈到运行我们的脚本时,这就是我正在运行的命令。
$ deno run --allow-net=swapi.dev index.ts
我们也可以用顶层 await 的方式来写这个脚本,这让我们使用await 关键字,而不是处理 promises。
const response = await fetch("https://swapi.dev/api/people/1/");
const data = await response.json();
console.log(data);
这是我喜欢的风格,也将在本文中使用,但如果你愿意坚持使用承诺,请随意。
安装第三方依赖
现在我们可以向《星球大战》的API发出请求了,让我们开始考虑如何让我们的用户使用这个API。我们将提供命令行标志,让他们指定要查询的资源(如人物、电影或星球),并通过查询来过滤它们。因此,对我们的命令行工具的调用可能看起来像这样。
$ deno run --allow-net=swapi.dev index.ts --resource=people --query=luke
我们可以手动解析这些额外的命令行参数,或者我们可以使用第三方库。在Node.js中,最好的解决方案是Yargs,而且Yargs也支持Deno,所以我们可以用Yargs来解析和处理我们想要支持的命令行标志。
然而,没有针对Deno的软件包管理器。我们不创建一个package.json ,也不安装一个依赖性。相反,我们从URLs导入。Deno软件包的最佳来源是Deno软件包库,你可以在那里搜索你想要的软件包。大多数流行的npm包现在也支持Deno,所以那里通常有大量的选择,你很有可能找到你想要的东西。
在写这篇文章的时候,在Deno资源库中搜索yargs ,我得到了yargs 16.2.0。为了在本地使用它,我们必须从它的URL中导入它。
import yargs from "https://deno.land/x/yargs/deno.ts";
当我们现在运行我们的脚本时,我们首先会看到大量的输出。
$ deno run --allow-net=swapi.dev index.ts
Download https://deno.land/x/yargs/deno.ts
Warning Implicitly using latest version (v16.2.0-deno) for https://deno.land/x/yargs/deno.ts
Download https://deno.land/x/yargs@v16.2.0-deno/deno.ts
Download https://deno.land/x/yargs@v16.2.0-deno/build/lib/yargs-factory.js
Download https://deno.land/x/yargs@v16.2.0-deno/lib/platform-shims/deno.ts
Download https://deno.land/std/path/mod.ts
Download https://deno.land/x/yargs_parser@v20.2.4-deno/deno.ts
...(more output removed to save space)
Deno第一次看到我们使用了一个新的模块,它将下载并缓存在本地,这样我们就不必在每次使用该模块并运行我们的脚本时都下载它。
注意上述输出中的这一行。
Warning Implicitly using latest version (v16.2.0-deno)
for https://deno.land/x/yargs/deno.ts
这是Deno告诉我们,我们在导入Yargs时没有指定一个特定的版本,所以它只是下载了最新的版本。这对于快速的辅助项目来说可能很好,但一般来说,将我们的导入固定在我们想使用的版本上是个好做法。我们可以通过更新URL来做到这一点。
import yargs from "https://deno.land/x/yargs@v16.2.0-deno/deno.ts";
我花了点时间才弄清楚这个URL。我发现,当我在Deno软件库中搜索 "yargs "时,我被带到的URL是https://deno.land/x/yargs@v16.2.0-deno 。然后我回头看了看控制台的输出,发现Deno实际上给了我准确的路径。
Warning Implicitly using latest version (v16.2.0-deno)
for https://deno.land/x/yargs/deno.ts
Download https://deno.land/x/yargs@v16.2.0-deno/deno.ts
我强烈建议像这样钉住你的版本号。它将避免有一天因为你碰巧在某个依赖的新版本之后运行而出现令人惊讶的问题。
deno fmt
在我们继续建立我们的命令行工具之前,先说一下。Deno有一个内置的格式化器。 deno fmt,它可以自动将代码格式化为一致的风格。想想看,它就像Prettier,但专门针对Deno,而且是内置的。这是我被Deno吸引的另一个原因;我喜欢那些开箱即用的工具,不需要配置任何东西就能为你提供这一切。
我们可以用这个在本地运行格式化器。
$ deno fmt
这将格式化当前目录下的所有JS和TS文件,或者我们可以给它一个文件名来格式化。
$ deno fmt index.ts
或者,如果我们有VS Code扩展,我们可以进入.vscode/settings.json ,在这里我们先前启用了Deno插件,并添加这两行。
{
"deno.enable": true,
"editor.formatOnSave": true,
"editor.defaultFormatter": "denoland.vscode-deno"
}
这就配置了VS Code在我们保存文件时自动运行deno fmt 。很完美!