やりたいこと
- Nuxt.jsなプロジェクトでWeb Workerを使いたい
- webpackのHMRに対応する
Web Workerとは
Web Workers API - Web API インターフェイス | MDN
Nuxt.jsでWeb Workerを使う
nuxt.config.js
worker-loaderを使います。
module.exports = {
build: {
extend: ({ module, output }) => {
// rulesの先頭に追加
module.rules.unshift({
test: /\.worker\.js$/,
loader: 'worker-loader'
})
// HMR時にWebWorkerでwindow is not definedになる問題対策
output.globalObject = 'this'
}
}
}
worker-loaderの設定をArray.push()
でmodule.rules
の最後に追加すると、うまく動きませんでした。なのでArray.unshift()
で配列の先頭に追加しました。
vue-loaderとかbabel-loaderが先に処理してしまうからでしょうか。
また、webpackのHMRが有効になっていると(Nuxtではデフォルトで有効ですが)、Web Workerをimportした時にwindow is not defined
と怒られます。webpackのoutput.globalObject
をthis
に設定すると解決できます。
参考:Webpack 4.0.1 | WebWorker `window is not defined` · Issue #6642 · webpack/webpack
assets/scripts/hoge.worker.js
動作確認として、受け取ったメッセージをコンソールに表示するだけのWorkerを作ります。
self.addEventListener('message', (message) => {
console.log(message.data)
})
components/Hoge.vue
<template>
<h1>Hoge Component</h1>
</template>
<script>
import Worker from '~/assets/scripts/hoge.worker'
export default {
mounted() {
const worker = new Worker()
worker.postMessage('hello worker')
}
}
</script>
pages/index.vue
サーバーサイドではwindow
オブジェクトがないので、Web Workerは使えません。
※webworker-threadsとかいうのがあるらしいですが、未検証
なので、Web Workerを呼び出すコンポーネント自体をno-ssr
コンポーネントでラップします。するとSSR時にはコンポーネントが呼び出されなくなるので、window
がない!とかWorker
がない!とか言われなくなります。
<template>
<no-ssr>
<hoge-component />
</no-ssr>
</template>
<script>
import HogeComponent from '~/components/Hoge.vue'
export default {
components: {
HogeComponent
}
}
</script>
yarn dev
$ yarn dev
してブラウザでlocalhost:3000にアクセスして、コンソールを見ると「hello worker」と表示されていると思います。
以上
無事にNuxt.jsでもマルチスレッドで処理できるようになりました。めでたい。