上文说过,deno目前最大的问题是生态,也就是说仍无法无缝继承nodejs的生态。那它也意味着可以使用一部分nodejs的资源。
以AST(抽象语法树)为例,它在底层工作时还是很有必要的,我们可能会用它写个小工具,实现一些简单的代码转换。但我们在deno.land中查找第三方库,却没有找到合适的。
文章图片
?
怎么办?
这时你首先想到的不该是“正是我辈大展身手造轮子的时候到了”,而是应该想,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上看下这两个包的依赖情况:
文章图片
文章图片
一个零依赖,一个依赖了5个包。还是很有希望通过CDN转义过来的。
deno版本 【deno怎么复用node的包】我们试试CDN(通常有https://esm.sh/和https://cdn.skypack.dev/两个,这里任选一个)转下:
https://cdn.skypack.dev/esprima
文章图片
https://cdn.skypack.dev/escodegen
文章图片
似乎是可以的,于是我们可以试下:
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生成的文件内容:
文章图片
这里有个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上看下:
文章图片
果然是用js写的。
针对这种情况,我们要么这么忍了,要么只能自己给写个.d.ts文件了。
?
typescript类型推断 对于本身是用ts写的npm包,以jwfetch为例,只需要在后面加个?dts即可,如:
import { BaseAjax } from "https://cdn.skypack.dev/jwfetch?dts";
运行代码,控制台显示:
文章图片
我们看到,类型文件.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已经发展了十余年,其中积累了不可计数的资源,我们要尽可能地复用它们,以提升开发效率。