LoginSignup
3
1

More than 3 years have passed since last update.

create-react-app でも WebWorker を使う (TypeScript 対応)

Last updated at Posted at 2021-01-16

概要

create-react-app は React で開発を始めるのに便利 だが、重い計算をバックグラウンドで行いたくなったので WebWorker を使おうとしたら サポートされていない ことがわかった。WebWorker 自体 onmessage/postMessage のような低レベル API を使用しないといけないようで型の恩恵を受けづらいのが難だなと調べていたら dominique-mueller/create-react-app-typescript-web-worker-setup を見つけた。だいたいこのとおりでうまくいった。

ReferenceError: $RefreshReg$ is not defined

しばらく悩まされたランタイムエラーがこれ。worker 内で起こっていて、シンボルの名前で調べてみると react-refresh に関係している らしい。トランスパイル後の JavaScript なんて読めないよと思いつつ何に対応して reference が生成されているか追っていったら 関数名が大文字で始まっている のを見つけた。まあ関係ないだろうと思いつつ直しておくとエラーがなくなった…。

たしかに React コンポーネントは大文字から始まるし、と react-refresh を見返すと isComponentishName 判定を通ったものは他のシンボルと違う処理が入っているらしい。

手順

詳しくは dominique-mueller/create-react-app-typescript-web-worker-setup を。

準備

  • react-app-rewired, worker-loader を入れる: package.json
  • react-app-rewired の設定を行う: package.json, react-app-rewired.config.js
    • .worker.ts で終わる名前のファイルは worker-loader を使って変換する、というような意味

使用

Worker 側では必要なものを expose する:

import { expose } from 'comlink'
import { f } from 'mylibrary'
export default {} as typeof Worker & { new (): Worker }
expose({f})

使う側では wrap すると Promise が返ってくる:

import { wrap } from 'comlink'
import MyWorker from 'My.worker'
const myWorker = wrap(new MyComlinkWorker()) as { f: (x: number) => Promise<number> }
:
myWorker.f(x).then(g)

TODO

as 以下を書くのが面倒なので any にしてしまっている。勝手になんとかしてくれる方法は?

参考

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1