分类
前端工具链

使用 webpack-rpc-inline-plugin 打包内联函数体

使用 Puppeteer 的时候,我们常常要使用 page.evaluate() 或者 page.evaluateHandle() 函数到目标页面的环境里执行一段代码。

如果是简单的代码,比如返回页面标题、改变某个节点的属性,那么直接写在 .evaluate() 里面就行了;但实际生产中,尤其是前厂的 Showman 产品里,要执行的函数往往非常复杂,经常需要组合多个函数:

page.evaluate(() => {
  function func1() {}
  function func2() {}
  // ...
  function funcN() {}

  func1();
  func2();
  // ...
  funcN();
});

这种场景下,我们必须用上面这种写法,而不是下面这种我们更熟悉的写法:

import func1 from './func1';
import func2 from './func2';
// ...
import funcN from './funcN';

page.evaluate(() => {
  func1();
  func2();
  // ...
  funcN();
});

因为被执行的函数会被转换成字符串,传输到目标环境,然后重新实例化成函数,再执行。所以上面这种写法,引擎会在全局环境下查找需要的函数,而那些函数都没传递过去,就会找不到。

如果开发时按照方案一组织代码,会遇到几个问题:

  1. 子函数放在主函数体内部,不方便独立开发、调试、测试
  2. 每个主函数内部都需要写死子函数,不方便共享复用

所以我就想从工具链入手,写一个专用工具,可以继续用方案二的形式组织代码,但是编译打包之后,就恢复到方案一的状态。

我选择了 webpack 插件,原因有二:

  1. 我比较熟悉 webpack
  2. 这种情况不能用 loader

最后我选择在 compilation.afterProcessAssets 钩子处理 JS。此时 JS 已经打包了所有资源,并且经过 terser 压缩。所以我会先将 bundle 解开(直接用 string.substring),然后 return webpack 对象,从中找到目标函数替换。

具体的代码在 GitHub 仓库里,我就不详细解释了(困了),感兴趣的同学可以看看。

欢迎需要在 rpc 环境下执行 JS 的同学使用,欢迎反馈需求和问题。