webpack5 umd打包,使用worker摸索记录

1,834 阅读3分钟

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  // 設置為極大值,禁止拆分
    }
}