webpack5 构建 worker
背景
目前项目需要开始突破性能瓶颈了,最极限的目标是希望主线程能非常及时地响应到各种操作,使用户操作平滑且低延迟(eg:mousemove事件从发生到触发监听时间小于0.5ms),因此需要将一些耗时的任务丢到单独的线程去执行。
构建worker方式
- worker-loader
- webpack5内置方式
worker-loader
想到构建worker,第一反应就想到这个,一顿猛如虎的操作完成后,一运行,发现worker完全没响应,哪怕写在全局下的console都没运行
定位问题
运到问题不要慌,先谷歌一下,结果并没有找到什么有用的信息,基本都是说webpack5推出了新的构建worker的方式,替代掉了worker-loader,而且worker-loader存在冲突,但是为什么会不执行呢,还是得看下打包后的代码
- test.worker.js
// test.worker.js代码
console.log(123123);
- worker-loader+webpack5打包后的主要代码
// worker-loader打包后核心代码
598: function (t, n, r) {
var e, o, i;
r(5094),
'undefined' != typeof globalThis ? globalThis : 'undefined' != typeof self && self,
(o = [n, r(1005)]),
void 0 ===
(i =
'function' ==
typeof (e = function (t, n) {
'use strict';
var e = r(4859);
function o() {
// 此处consolo.log为worker内容,通过new Worker引用后不会执行
return (0, n.default)('console.log(123123);', 'Worker', void 0, void 0);
}
Object.defineProperty(t, '__esModule', { value: !0 }), (t.default = o), (n = e(n));
// 此处缺少t.default()的调用
})
? e.apply(n, o)
: e) || (t.exports = i);
},
可以看出,代码通过worker-loader在webpack5下构建后,通过new Worker加载下来是不会直接执行的。
- ps:本项目属于library: 'umd'打包输出的,其他打包输出方式会有不一样的结论
webpack5内置方式
既然使用了webpack5,官方也在推新的方案,那就尝试下新的方案来替代worker-loader
使用
使用方式根据文档,很简单,代码如下
this.myWorker = new Worker(
new URL(
/* webpackChunkName: "test.worker" */ './test.worker',
import.meta.url
)
);
最后build会生成一个worker的chunk以及worker依赖模块的chunk,如:
- test.worker.js
- 952.js
worker加载的路径由打包的publicPath决定,若设为'auto',会使用js所在origin
问题
若放在同域下不存在问题,但放在cdn等情况下,会出现跨域问题,谷歌一番后没有找到官方的解决方法,此时针对问题做如下修改
- 一般来说解决worker跨域可以通过importScript引入来解决,因此做出如下修改
if (workerUrl) {
const workerBlob = new Blob([`importScripts("${workerUrl}?t=${Date.now()}")`], {
type: 'application/javascript',
});
const blobUrl = window.URL.createObjectURL(workerBlob);
this.myWorker = new Worker(blobUrl);
} else {
this.myWorker = new Worker(
new URL(
/* webpackChunkName: "test.worker" */ './test.worker',
import.meta.url
)
);
}
else部分可以令webpack将worker部分代码打包生成对应的worker文件,之后根据当前脚本地址生成worker地址,如:
const scriptUrl = document.currentScript ? document.currentScript.src || '' : '';
const scriptOrigin = scriptUrl.replace(/\/[^\/]+.js$/, '');
{
workerUrl: `${scriptOrigin}/test.worker.js`,
}
依赖chunk文件地址错误
通过以上方式解决跨域问题后,test.worker.js在引用952.js chunk模块时地址错误,此时可考虑不对依赖进行提取,修改webpack配置
optimization: {
splitChunks: {
minChunks: 999999 // 設置為極大值,禁止拆分
}
}