在遥远的几个月前,还在上家公司的时候,老板突发奇想,想要搞个代码片段平台,类似于 snipit,实现代码片段的复用。本身这个需求并不难实现——简单的前端界面 + 简单的 node CURD,搞定收工,下班回家。
但是,在实际使用中,发现了一个使用痛点——没有在线调试功能,所有代码只能 copy 到本地,在本地进行调试。本着发现痛点就要解决痛点的指导思想,我当时思考了一段时间,希望寻找一个合适的解决方案来完美的解决这个痛点。总体来说,分为两种方案:
相比于服务端构建方案,浏览器实时构建方案的优势在于:即时、高效以及最宝贵的——可离线运行(前提是做了合适的缓存方案)。
最终,出于各种因素,最终我选择了浏览器实时构建方案。
浏览器实时构建是最近两年前端的热门方向,所以也涌现了一大批成熟的解决方案。
个人总结为:bundle 方案以及 unbundle 方案两种。
大部分投入生产环境的浏览器实时构建方案都采用了该方案,该方案基本采用了 codesandbox-client 的方案,所以我一般称之为类 CodeSandBox 方案。
bundle 方案的核心在于在浏览器上实现一个打包工具,如 webpack,配合 indexDB 进行本地文件存储。当然,不仅仅是这么简单,由于在浏览器端做构建工作效率相对较低,所以需要大量的性能优化,比如 CodeSandBox 在浏览器端实现了一个线程池,当进行构建时,从线程池中取出线程,从而实现多线程打包。
总的来说,bundle 方案依然没有跳出构建的思路,当项目较为复杂时,依然会出现构建工具遇到的那个问题——慢。针对 bundle 方案的缺点,业界推出了 unbundle 方案(当然最主要还得感谢浏览器的支持)。
unbundle 方案的出现,需要感谢 ESM。啥是 ESM 呢?ESM 全称为 ECMAScript modules,即浏览器原生支持模块化规范。效果如下:
<script type="module">
// 引用别的模块
import { util } from './utils.js';
// 使用别的模块中的函数
util()
</script>
当浏览器解析到 import
语句时,会像开发态一样自动引入对应模块。得益于 ESM,我们可以不经过构建即可直接在浏览器端运行模块化代码。
相比于 bundle 方案,unbundle 方案在各种意义上都快了许多,特别当项目复杂度上来以后,这个差异将会异常明显;另一方面,unbundle 不需要在浏览器端实现一个打包工具,对于快速实现浏览器实时构建也有着很大的意义。
由于 unbundle 的各种优点,最终我选择了使用 unbundle 方案来实现浏览器实时构建。
接下来,到了实战环节,我们来尝试实现一个单文件浏览器实时构建。
该系统分为两部分:
首先是 UI 部分,UI 简单的分成三部分:代码编辑器(如:monaco editor),按钮(用于执行实时构建函数)以及构建结果展示部分,主要负责调试代码并展示结果。
当点击按钮后,触发构建函数,开始执行构建逻辑,整个构建流程主要分为以下几步:
总体思路其实和 vite 非常像,也可以认为是在浏览器端实现了一个小 vite。详细的代码可以参考 vite 源码,在此不再赘述。
服务端的功能非常简单,即接收请求,返回对应的依赖打包文件。由于 ESM 只支持 ESM 规范,所以,需要将各种模块规范(主要指的是 commonjs)统一转为 ESM。
当依赖服务器接收到客户端的请求时,具体工作流程如下:
通过上面的思路,我们就可以实现一个最简单的单文件浏览器实时构建了,但是其实有非常多的问题,比如:
本来我很想直接来一句:这些问题留作课后思考[doge],但是怕被打,所以接下来就聊下我对这几个问题的看法吧。
以上就是我的思路,如果大佬们有不同的思路,欢迎一起探讨。
按照惯例,发个招聘帖:
字节跳动招人啦,HC 巨多,北上广深杭皆有坑位。
团队详情见:https://webinfra.org/about
提供内推及面试辅导服务,目前我内推的几个同学皆通过了面试,欢迎咨询~
暂时不看机会,之后有想法来字节试试的同学,也一样欢迎你加入 ??。
有意者可发送邮件到 hubin.gzx@bytedance.com