泛微Ecology 9代码块开发框架:持续构建

问题

上一篇文章我们实现了基本构建功能,做到了在业务代码开发完成之后构建为脚本文件,但是在开发过程中还是不方便,因为每次修改都要重新手动运行构建。因此,我们需要实现持续构建,即每当源文件发生修改时,就自动重新构建所在的脚本目录。

初步实现

在构建程序中,创建全局变量watched,存放已监听的源文件路径列表,用于防止重复监听。

每当构建一个脚本目录时,除了构建脚本文件,还对源文件做监听。对于每个涉及的源文件(index.js、index.css(如果有);不监听template.js,因为不变),如果不在watched中,则:

  1. 调用fs.watchFile(),注册回调函数,监听源文件的改变。当源文件内容改变时(前后的mtimeMs不一致),则重新构建源文件所在的脚本目录(不递归)。
  2. 将源文件加入watched。

启动构建程序时:

  1. 删除dist/。
  2. 对src/执行构建(递归)。

在对src/递归构建一遍后,此时所有源文件都已被监听,每当源文件修改都会自动重新构建。

构建模式

构建有两种场景:

  1. 开发时,需要持续构建。
  2. 部署时,需要一次性构建。

因此,我们让构建程序接收一个可选的命令行参数--watch,决定是否对源文件监听,即是否开启持续构建。

将package.json改为:

"scripts": {
    "build": "node index.js",
    "watch": "node index.js --watch"
}

那么,可通过如下命令执行不同的构建模式:

# 一次性构建模式
npm run build
# 持续构建模式
npm run watch

优化监听性能

实测发现,通过fs.watchFile()实现监听,在发生修改到执行回调之间,有很大的延迟,这导致修改代码后总是不能立即重新构建,刷新页面时加载的还是旧代码,要等一会儿刷新,新代码才生效。

查阅Node.js API文档发现,fs.watchFile()是通过轮询文件的状态信息(stats)来检测文件变化的,效率很低。文档推荐使用fs.watch(),因为它是直接通过操作系统机制(通知、事件等)实现的,效率要高得多。

因此,将fs.watchFile()改为fs.watch(),将判断文件内容变化的条件改为eventType === "change"。

实测,及时性有了显著提高,可以做到立即重新构建。

支持源文件增删

目前只实现了对已有源文件修改的监听,但实际开发过程中还有增加、删除源文件的场景,例如:

目前只能重新启动构建程序,否则增、删源文件不会触发重新构建。

查阅fs.watch()的文档发现,它支持递归监听整个目录,目录下任何层级的文件变化都会触发回调,通过回调的filename参数可以知道是哪个文件/目录发生了变化。这就类似于在window上集中监听DOM树中所有节点的事件。

那么,现在不需要watched变量了,只需要在src/上注册一次递归监听。当src/中的任何文件/目录发生变化时,不必区分变化类型(增、删、改),直接将变化文件所属的目录作为脚本目录,对其调用构建函数(非递归)。在构建函数中,如果脚本目录存在,且index.js存在,则构建,否则不构建,即可。