Require Strategy in Electron

Electron

因为 Electron 项目天然的集成了 Node.js,可以直接使用 require 命令来加载其他的模块。因此,很多项目中就不再使用 Webpack 或 Rollup 来对项目进行打包操作。简单的使用 TypeScript 或 Babel 进行转化,保证 import 转化成了 require 命令,就能顺利的跑起来了。

然而,如果细究下去,直接使用 require 依次加载各个文件和通过打包将所有需要加载的部分一次性载入,两者之间还是存在这性能上的差距。具体的数据差异,可以通过这个测试项目来实际了解。

实测中,大约 1000 个文件,打包和不打包的版本,载入的时间差距在 200ms 以上。对于用户来说,这个已经是可感知的延迟了(参考数据)。

一次 Electron require 涉及的步骤包括:

  1. 根据请求的地址,寻找文件(Electron 的 _resolveFilename 方法 > Node.js 中的 _resolveFilename 方法 > _findPath 方法 > stat 方法)
  2. 根据实际地址读取文件(Node.js 的 Module.prototype.load 方法 > Module._extensions[‘.js’] 方法 > fs.readFileSync 方法)
  3. 编译加载文件内容(Node.js 的 Module.prototype._compile 方法)

其中,第一步和第二步的 IO 都是比较耗时的操作。特别是对于第一步来说,寻找文件是一个过程。对于非相对路径的文件来说,如果不能在当前的 node_modules 下找到,Node.js 就会逐级往上寻找,直到成功或最终失败。第三步编译和运行的过程,耗时将和内容具体的长短以及具体执行的内容相关。

由于不论是直接 require 的方法还是打包的操作,最终需要执行的程序都是基本相同的(对于 Webpack 来说,有一些 runtime 代码的消耗),也就是第三步的时间两个方案都是大体相同的。因而总体上来说,两种方案的差异主要体现在第一步和第二步的耗时上。由于单个打包文件加载的方案可以节省多次 IO 的查找和读取操作,因而最终会节省不少的时间。