halo,大家好,俺是 132,今天给大家带来的是一个很有意思的东西
起因是 stackblitz 团队在 Chrome I/O 上分享了一篇文章,可以将 node 跑到浏览器中
blog.stackblitz.com/posts/intro…
然后惊艳四座,国内外都在猜测内部的可能实现……因为他们也不开源,于是……
经过我好几天的研究,我特么终于搞懂了o(╥﹏╥)o
先放 github 地址,欢迎大家提 pr,点 star,蟹蟹大家啦
然后接下来我简单阐述一下这个的底层原理
基本实现原理
code => service worker(js runtime) => go wasm API
复制代码
一句话就是,在 server worker 中,借助 wasm 实现一个 js runtime
举例子:
const a = readFileSync('a.js')
复制代码
首先可以肯定的是,这段 js 是在 service worker 中跑的,service worker 充当了 v8 的角色
new Function('global', `with(global){
const a = readFileSync('a.js')
}`)
复制代码
到这里,我们执行会提示缺少 readFileSync
API,剩下的工作,我们就是要使用 wasm 实现这个 API,然后注入到 global 上
wasm 充当了 deno 中的 rust 角色
js.Global().Set("readFileSync", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
readFile(args[0].String())
return nil
}))
复制代码
大功告成!基本原理就是这么简单的啦
事前准备
根据 stackblitz 的 demo 可以看到,他们是可以读文件系统的
const a = readFileSync('./a.js')
复制代码
实际上如果我们没有文件系统的话,访问 ./a.js
是拿不到内容的,所以重点来了
我们要在首次加载的时候,把所有文件都存到内存里,也就是需要构建一个 dependency graph
如果你有写过打包工具的经验,肯定会对 dependency graph 比较熟悉了,我之前也有一次技术分享详细讲过
简化就是这样的:
new Map([
['./a.js', buffer],
['./b.go', buffer]
])
复制代码
在我们初始化的时候,就是要生成一张这样的图,这是我们实现文件系统的关键
除了文件系统,另一个重点就是 http
好消息是 go 的 net/http
包对 WASI 的支持程度非常好,出乎意料
web container 的场景
- webIDE
这次的 stackblitz demo 就是 webIDE,因为可以直接在浏览器中直接跑 js runtime,直接启一个 server,所以节省了通往 server 的链路
类比的场景比如组件化实施预览,lowcode 的预览,物料市场的预览等等
- better worker
实际上 web container 也可以理解为,借助 wasm 能力进行增强的 worker,你可以用它做很多以前 worker 里做不了的事情
比如我在公司里是负责小程序底层架构的,小程序的模拟器是需要启动一个 server 的,然后每次重新编译就得重启 server,现在有了 labor,我就可以全部在浏览器中完成工作,可以说非常完美了
- 双 worker 同构
前阵子 cloudflare worker 的形态令人耳目一新,我当时觉得这个形态的 serverless 真的是太赞了
但是 cloudflare 是 server 端的 js runtime,它一直缺少一个本地调试的终端
labor 就可以做这件事情,我们在本地通过 labor 开发,线上通过 cloudflare 运行,两个 worker API 完全相同,最终做到同构
这可以说是 serverless 的最绝美形态了
- ssr/esr
esr 是最近比较火的,就是在 serverless 平台下做 ssr,和上面的双 worker 同构一样,想象一下开发环境走 labor 的 ssr 会多么爽
web container 的优势
- 不再需要开发者关注 server
尤其是对于 ssr 的场景,非常非常赞
- 调试更好
Chrome devtools 是最好的调试工具
- 更省钱
咳咳咳。。。
web container 的限制
因为 labor 是在浏览器中实现 js runtime,所以主要限制来自于浏览器
- http 不能启端口
也就是 go 的 ListenAndServe
不能用
- 不能访问本地文件
web.dev/file-system… 这个 API 看着不太靠谱
- wasm 性能差
实测,go 的 wasm 版本,平均比 native go 慢 30 倍,比 js 慢 10 倍
这主要是 go 的 GC 导致的,所以社区内有一些替代方案,比如 tinygo,可以扳回一局
总结
社区内很多人对 web container 评价比较不好,比如太花里胡哨,比如性能差限制多
但是我问,当年双线程前端框架也是花里胡哨来着?
但最终还是成就了小程序这么一个无敌的产品
web container 也是同理,最终肯定有绝美的产品落地的
不多说啦
快点来点赞吧,以后有机会再来分享啊哈