VueCLI + javascript環境で、WebWorkerを使用する


web workerでの記事は、webpack環境(nuxt.js環境)や、typescriptでの記事が多く存在し、
所々詰まっていたので記事にします。
Web Worker の使用(MDN)
Vue.js で WebWorker を使う
laravel-mix + Vue.js (ES) + WebWorker (TS)
これらの記事を参考にしました。

今回作成したgitリポジトリ

導入

vue ui 等でvueを立ち上げたものとして、
プロジェクト直下で
npm install worker-loader
とし、worker-loaderを導入します。

そして、プロジェクト直下のvue.config.js(無ければ作成し)に、
下記の内容を記述します

vue.config.js
module.exports = {
  chainWebpack: config => {
    config.module
      .rule('worker-loader')
      .test(/\.worker\.js$/)
      .use({
        loader: 'worker-loader',
        options: {
          inline: true
        }
      })
      .loader('worker-loader')
      .end()
  }
  //...
}

実行準備

次に、srcフォルダ直下に
workersというフォルダと、worker1というjsファイルを作成します。
(※名称はなんでも良いと思います。また、フォルダは存在していなくても良いと思います。)

src
 |-assets
 |-components
 |- ...
  |-workers
     |-worker1.js
 |-App.vue
 |-main.js

このような構成になるかと思います。
次に、worker1.jsの中身を

worker1.js
addEventListener('message', e => {
    const { data } = e
    if (data && typeof data == 'number') {
        return postMessage(data*data)
    } else {
        return postMessage(10)
    }
})

export default {}

としてみます。
workerに投げられた変数が、int型の場合、二乗を返し、
それ以外の場合10を返す関数です。

次に、実際にvueファイルでworkerを呼び出します。
試しに、vuecliで生成されるHome.vueに書いていきます。

Home.vue
<script>
import Worker1 from 'worker-loader!@/workers/worker1'
export default {
  name: 'Home',
  components: {
  },
  data () {
    return {
      reload: 0
    }
  },
  methods: {
    workerTest: function () {
      const worker = new Worker1()
      worker.onmeessage = e => {
        const { data } = e
        this.reload = data
        worker.terminate()
      }
      worker.postMessage(20)
    }
  }
}
</script>

このようにします。
import文に、worker-loader!をpath名の前に挿入することに気をつけ、また、
worker.onmessageで、workerの処理が終わった場合(つまりpostMessageが返った場合)の処理を記述します。
今回の場合は、処理が終わり次第、this.reloadに代入し他で参照できるようにします。
また処理を終えたあとにworkerが存在する意味はないので、terminateで削除します。
(※importがlintに怒られるかもしれないので、その場合はruleに記述しましょう...)

実行

Home.vue
<template>
  <div class="home">
    <button @click="workerTest()">worker!!</button>
    {{ this.reload }}
  </div>
</template>

実際に、このようにして試してみると...

実際に、workerを通して、値が変更されたのがわかります。
また、

Home.vue
workerTest: function () {
      const worker = new Worker1()
      worker.onmessage = e => {
        const { data } = e
        this.reload = data
      }
      worker.postMessage(20)
    }

とし、
開発者ツールのSourcesをみると

実際にworkerが立っているのがわかります。

other

ループの中で実行

試しに

Home.vue
workerTestLoop: function () {
      for (let i = 0; i < 10; i++) {
        const worker = new Worker1()
        worker.onmessage = e => {
          const { data } = e
          this.reload += data
          worker.terminate()
        }
        worker.postMessage(20)
      }
    }

とし、先ほど同様に実行してみると、
実際に、先ほどの数字が4000(400 * 10)となっているのがわかります。