deno怎么复用node的包

上文说过,deno目前最大的问题是生态,也就是说仍无法无缝继承nodejs的生态。那它也意味着可以使用一部分nodejs的资源。
以AST(抽象语法树)为例,它在底层工作时还是很有必要的,我们可能会用它写个小工具,实现一些简单的代码转换。但我们在deno.land中查找第三方库,却没有找到合适的。
deno怎么复用node的包
文章图片

?
怎么办?
这时你首先想到的不该是“正是我辈大展身手造轮子的时候到了”,而是应该想,node的npm包是不是可以复用?
node版本 AST有各种实现版本,比较出名的是babel。这里我找两个简单的esprima和escodegen。

const esprima = require('esprima'); const escodegen = require('escodegen'); const encodeJs = function () { const str = ` global.x = 10; name += '-abc'; age = 12; `; const AST = esprima.parse(str); // console.log(AST); // console.log(AST.body[0].expression.left.object.name); // console.log(result.body[0].consequent.body[0].expression.left); AST.body.splice(0, 1); // remove global.x = 10; const originReback = escodegen.generate(AST); console.log(originReback); // name += '-abc'; age = 12; }; encodeJs();

我们先在npm上看下这两个包的依赖情况:
deno怎么复用node的包
文章图片

deno怎么复用node的包
文章图片

一个零依赖,一个依赖了5个包。还是很有希望通过CDN转义过来的。
deno版本 【deno怎么复用node的包】我们试试CDN(通常有https://esm.sh/和https://cdn.skypack.dev/两个,这里任选一个)转下:
https://cdn.skypack.dev/esprima
deno怎么复用node的包
文章图片

https://cdn.skypack.dev/escodegen
deno怎么复用node的包
文章图片

似乎是可以的,于是我们可以试下:
import * as esprima from 'https://cdn.skypack.dev/esprima'; import * as escodegen from "https://cdn.skypack.dev/escodegen"; const encodeJs = function () { const str = ` global.x = 10; name += '-abc'; age = 12; `; const AST = esprima.parse(str); AST.body.splice(0, 1); // remove global.x = 10; const originReback = escodegen.generate(AST); console.log(originReback); // name += '-abc'; age = 12; }; encodeJs();

执行deno run xx.js,成功!
?
真是个愉快的消息。这意味着我们不需要再造轮子。这样即使这两个包有什么bug,你只需要去github提issue,到时候升级版本就行了。
?
注意 不过有点儿需要注意,假设你要在项目中使用,最好将版本号写上,比如:
import * as esprima from 'https://cdn.skypack.dev/esprima@v2.0.0';

但这样还不够,如果你要使用deno的lock.json文件来保障项目各成员或各个环境都能使用相同的版本,我们所用的这个CDN并不能保障它的hash值不变化(也就是说隔断时间对应的hash值会变化,也会导致deno cache --lock=lock.json校验失败),即使版本号是固定的。
那么应该怎么办呢?
?
再回头仔细看上面CDN生成的文件内容:
deno怎么复用node的包
文章图片

这里有个Pinned URL,它便是正解。
所以,最终的代码变成这样:
import * as esprima from 'https://cdn.skypack.dev/pin/esprima@v4.0.1-2bFId5CSQMZAdjdZliQ2/mode=imports/optimized/esprima.js'; import * as escodegen from "https://cdn.skypack.dev/pin/escodegen@v2.0.0-MB39rvARiyYcecqDvQhe/mode=imports/optimized/escodegen.js"; const encodeJs = function () { const str = ` global.x = 10; name += '-abc'; age = 12; `; const AST = esprima.parse(str); AST.body.splice(0, 1); // remove global.x = 10; const originReback = escodegen.generate(AST); console.log(originReback); // name += '-abc'; age = 12; }; encodeJs();

缺点 我们使用deno,推荐直接使用TS,但这个包没有ts文件,也就没有类型文件。到github上看下:
deno怎么复用node的包
文章图片

果然是用js写的。
针对这种情况,我们要么这么忍了,要么只能自己给写个.d.ts文件了。
?
typescript类型推断 对于本身是用ts写的npm包,以jwfetch为例,只需要在后面加个?dts即可,如:
import { BaseAjax } from "https://cdn.skypack.dev/jwfetch?dts";

运行代码,控制台显示:deno怎么复用node的包
文章图片

我们看到,类型文件.d.ts都下载下来了。这样类型推断就有了。
?
但要按上面说的,固定我们的版本与hash的话,就只能:
import { BaseAjax } from "https://cdn.skypack.dev/pin/jwfetch@v1.1.2-1LpCExuOCuNK2LPTj1mF/mode=imports/optimized/jwfetch.js";

这种情况又会有个问题,这只是一个js文件,并没有类型文件,怎么办?别慌,只需要加// @deno-types就行了:
// @deno-types='https://cdn.skypack.dev/-/jwfetch@v1.1.2-1LpCExuOCuNK2LPTj1mF/dist=es2019,mode=types/dist/index.d.ts' import { BaseAjax } from "https://cdn.skypack.dev/pin/jwfetch@v1.1.2-1LpCExuOCuNK2LPTj1mF/mode=imports/optimized/jwfetch.js"; BaseAjax.defaults.baseURL = "https://api.github.com"; console.log(BaseAjax);

总结 本文以AST为例,教你在使用deno进行开发的过程中,如何利用CDN来复用npm的node包。node.js已经发展了十余年,其中积累了不可计数的资源,我们要尽可能地复用它们,以提升开发效率。

    推荐阅读