2018 年,我已经在 deno 公布不久写过一篇《Deno 不是下一代 Node.js!》的文章,正好最近有一些钻研,站在 2021 年再来看看 deno。
无疑,deno 扭转了大家的对包治理的认识。自身 deno 够小,试错成本低,它确确实实引领了一个潮流方向。这个改良虽说不算新,但反应的确很好,大略是天下人苦 npm(npm 开玩笑的说法是:你怕吗)久已,用法简略,高效,甚至是衍生出很多对于 CDN for JavaScript modules 的思考。
上面,咱们就一起看一下吧。
缘起
咱们做了一个 imove 的开源我的项目,iMove 是一个逻辑可复用的,面向函数的,流程可视化的 JavaScript 工具库。
目前曾经反对的个性
- [x] 流程可视化 : 上手简略,绘图不便,逻辑表白更直观,易于了解
- [x] 逻辑复用 : iMove 节点反对复用,单节点反对参数配置
- [x] 灵便可扩大 : 仅需写一个函数,节点可扩大,反对插件集成
- [] 多语言编译 : 无语言编译出码限度(例: 反对 JavaScript, Java 编译出码)
其实,直白点讲,就是将经营配置的一套玩法给开发用。每个节点都是函数,可视化,可配置,可组装,可导出代码,做的是很克服的。基于 x6 图形和 json 协定,能够说是以最小的投入老本拿到最大的成果,从定位上看,还是相当精准的。咱们本人在业务中应用落地,无论体验还是成果,也是十分好的。
最近为了开源,小伙伴提了 2 个优化点:
- 双击图形,能够编辑函数,这样操作更不便。曾经做完了。
- 在这个界面上做到节点或流程可测试。的确会有这个问题,如果节点可测,性能上会更加实用。
第二点,我是十分认可这的。但问题来了,如何实现呢?
每个节点的代码等价于一个 js 文件,因而你不必放心全局变量的命名净化问题,甚至能够 import 现有的 npm 包,但最初必须 export 出一个函数。须要留神的是,因为 iMove 天生反对节点代码的异步调用,因而 export 出的函数默认是一个 promise。
举例,就拿 是否登录
这个分支节点为例,咱们来看下节点代码该如何编写:
import fetch from 'node-fetch';
export default async function (ctx) {return fetch('/api/isLogin')
.then(res => res.json())
.then(res => {const {success, data: {isLogin} = {}} = res;
return success && isLogin;
}).catch(err => {console.log('fetch /api/isLogin failed, the err is:', err);
return false;
});
}
引申出
- 这是 esm,基于 es module 的支流写法。
- 反对内部包导入,不然很难可能应答简单场景。
相似的 jsbin,或 codepen,或 codesandbox,能够应用 webpack 的 off-line 插件实现,也能够采纳 webide 初始化装置模块来实现,但这并不是好的形式。imove 是要兼容浏览器和 node 的,间接运行,不须要本地装置 npm 包,也可能在 node 里完满运行。这就导致,咱们必须要往 http import 方向思考问题。System.js 就是一个极好的抉择。
import-http
如果你去看 deno 链接内部代码文档(https://deno.land/manual/link…),它的做法是通过 –allow-net 参数选项,能够让 deno 的 runtime 能够下载 imports 并将其缓存在磁盘上。
这其实只是缓存在系统目录中,比方 mac 上是 $HOME/Library/Caches/deno。其实并没有啥实质晋升。
通过代码地址来援用代码,的确是很爽的一件事儿。
No more node_modules bloat, no dependency to install.
在 node 世界里,也有人实现了相似的机制,即 https://github.com/egoist/imp…。它是通过 webpack/rollup 编译时解决的。
看具体用法
先配置 webpack.config.js:
const ImportHttpWebpackPlugin = require('import-http/webpack')
module.exports = {plugins: [new ImportHttpWebpackPlugin()]
}
而后就能够在代码间接应用了:
import React from 'https://unpkg.com/react'
import Vue from 'https://unpkg.com/vue'
console.log(React, Vue)
原理:通过 webpack 的 compiler.resolverFactory.hooks.resolver 解析 import-http-resolver,即 import 里带有 http 和 https 的。而后通过 fileModuleCache 和 httpCache 对下载的内容进行缓存。
其实,Node.js 做这事儿也是很简略的。只有在 https://github.com/nodejs/nod…,实现下载和缓存就能够解决。可是,历史包袱过重,想做到 no filesystem imports of any kind from https sources,还是有一段路要走的。不过这块,也是大家可能参加奉献 Node.js 源码的很好的点。
- module: ESM loaders 下一步打算 https://github.com/nodejs/nod…
- 官网工作组 https://github.com/nodejs/mod…
反对第三方 ESM loader 也快了,大家刮目相待吧,用法相似于上面的
node-dev –experimental-loader ts-node/esm/transpile-only ./index.ts
esm.run
国外还有一个服务,名为 esm.run,它的定位是:”A New-Age CDN for JavaScript modules“。这话说的曾经相当间接了,它就是从新定义基于 CDN 的 JavaScript modules 的新的托管形式。
它的原理图。
以 npm 和 github 作为源,同步到亚马逊 s3 上,继而代理到各种 CDN,为用户提供服务。
cjs to esm
很早就有了 cjs 转 esm 的工具。比方 https://github.com/standard-t…,本人实现大量 polyfill,过渡态,尝试还行,早晚还是要回归到内核中的。
The brilliantly simple, babel-less, bundle-less ECMAScript module loader.
// Set options as a parameter, environment variable, or rc file.
require = require("esm")(module/*, options*/)
module.exports = require("./main.js")
这是本地的做法,如果变成 http import,这件事儿本地是不须要做的,把这些都交给 cdn 类的服务来做更适合。事实上,pika.dev/skypack.dev/jspm.io 都曾经做了这件事儿。
借助 http://jspm.io(或其余相似服务)来将 commonjs 转换为兼容的 esm 格局。
import cheerio from "https://dev.jspm.io/npm:cheerio/index.js";
引申一下,2 个问题。
- 国内还没有相似的服务,既然有 cnpm,会不会有相似的服务呢?我想会有人做的。
- 传统 CDN 厂商下一步也会朝着这个方向走的,要么收买,要么自建。这其实是很好的生意。一方面满足开发者的诉求,另一方面也可能为传统 CDN 厂商提供增量业务。它也是新基建的组成部分。
总结
deno 是一个很好的翻新,下面讲的 import-http,esm.run 或模块转化服务,能够说都是 deno 摸索间接或间接作用的后果。
但如果说想代替 Node,目前的这些个性和性能晋升,还不足以代替 node。Node 社区在 node 4 之后接收 es 个性之后还是很与时俱进的,cjs 和 esm 解决已经也很及时。那么既然机会已成熟,明天 node 拥抱 http import 还会远吗?