使用webpack worker-loader与nuxt.js

12

我正在尝试在 nuxt.js 框架 中使用 Web Worker,但是一直收到引用错误:ReferenceError: Worker is not defined

我已经通过 npm 安装了 worker-loader 1.1.1,并在我的 nuxt.config.js 文件中添加了以下规则:

module.exports = {
  build: {
    extend (config, { isDev, isClient }) {
      if (isDev && isClient) {
        config.module.rules.push({
          enforce: 'pre',
          test: /\.(js|vue)$/,
          loader: 'eslint-loader',
          exclude: /(node_modules)/
        })
      }
      // Web Worker support
      config.module.rules.push({
        test: /\.worker\.js$/,
        use: { loader: 'worker-loader' },
        exclude: /(node_modules)/
      })
    }
  }
}

如果我通过nuxt build创建构建,那么看起来Web Worker文件已经被创建了。

Asset                           Size                      
2a202b9d805e69831a05.worker.js  632 bytes          [emitted]

我将它作为一个 Vuex 模块导入,像这样:

import Worker from '~/assets/js/shared/Loader.worker.js'

console.log(Worker)
const worker = new Worker // <- this line fails!
在控制台中,我得到了一个看起来像是创建worker函数的东西:
ƒ () {
  return new Worker(__webpack_require__.p + "345c16d02e75e9312f73.worker.js");
}

在worker内,我只是有一些虚拟代码来检查它是否有效:

const msg = 'world!'

self.addEventListener('message', event => {
  console.log(event.data)
  self.postMessage({ hello: msg })
})

self.postMessage({ hello: 'from web worker' })

我也尝试使用workerize-loader,但是出现了不同的错误。我确定这与我的配置有关,但我仍然不知道该怎么做。https://github.com/developit/workerize-loader/issues/27 - dotnetCarpenter
1
难道不应该是 new Worker() 吗? - lukas-reineke
3
如果在JS中没有向构造函数传递参数,则圆括号是可选的。无论如何,我尝试了两种方法(和许多其他方法),但都失败了。 - dotnetCarpenter
尝试以以下方式导入:import * as Worker from "worker-loader!~/assets/js/shared/Loader.worker.js'"; 然后创建一个实例。 - Neha Tawar
2个回答

9

首先让我们澄清一些事情:

  • 工作线程只能在客户端使用 -> 没有服务器端渲染

因此,您需要使用no ssr组件或将应用程序设置为no ssr

有了这个知识,我们将修改nuxt.config.js如下:

mode: 'spa',
build: {
  extend(config, { isDev, isClient }) {
    ...
    // Web Worker support
    if (isClient) {
      config.module.rules.push({
        test: /\.worker\.js$/,
        use: { loader: 'worker-loader' },
        exclude: /(node_modules)/
      })
    }
  }
}

在执行npm run buildnpm run start之后,它应该像魅力一样工作。

我为您创建了一个仓库,它是一个标准的nuxt模板,使用了worker-loader:Github仓库


使用最新的nuxt源代码,worker-loader在dev模式下可以正常工作。我刚刚进行了git克隆并且它可以工作。 - dotnetCarpenter
我只是匆忙赶到这里,因为这个想法突然冒出来了。Webworkers在Dev模式下确实会被注册,我会相应地更新我的答案。 - Greaka
服务器端不能使用工作线程。如果您只想预取数据,请使用asyncdata。另一个选项是编写自己的加载器,如果!isClient则调用它。例如,加载器可以更改路径,例如将*.worker.js更改为*.js。缺点:您必须多次编写相同的代码。解决方法:在工作线程中导入非工作线程脚本并仅调用函数。WebWorker将只是在客户端中卸载它的包装器。 - Greaka
1
我尝试了一下,并最终得到了一个示例PR:https://github.com/nuxt/nuxt.js/pull/3044 - dotnetCarpenter
2
@husayt 看起来你在 https://github.com/nuxt/nuxt.js/pull/3480#issuecomment-404150387 中已经回答了这个问题。 - dotnetCarpenter
显示剩余6条评论

2
使用worker-loader时,有回退选项,但我个人(也是我正在做的)只会将通信代码保留在即时工作文件中,并导入第二个文件以执行实际工作负载。这样第二个文件也可以在服务器端导入。除非您处于FaaS上下文并且主线程确实没有其他任务要执行,否则很可能在分叉线程/线程池中运行。
此外,在nuxt.config.js中是否必须使用以下内容?对我来说,如果没有它,就会出现“窗口未定义”的错误。(在浏览器中尝试实例化worker时)
extend(config, ctx) {
    /*
    ** Required for HotModuleReloading to work with worker-loader
    */
    config.output.globalObject = 'this'
}

2
这是由于@husayt的评论引起的 https://github.com/nuxt/nuxt.js/pull/3480#issuecomment-404150387。然而在1.4.0中,它似乎无论如何都不起作用。所以我把它移除了,在nuxt页面中,我通过`async fetch({app}) { app.$worker}获取引用,在store中仍然可以使用this.$worker`。对于糟糕的格式化表示抱歉,但是SO peeps认为这很棒(!) - https://meta.stackexchange.com/questions/216927/code-in-comments-does-not-work - dotnetCarpenter

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接