WebWorker(Offscreen)でCanvasを描画する
これの続き。
grekumu.hatenablog.jp
前回、WebWorker上でcanvas使うなら、OffscreenCanvas使おうって書いた。
ただ実際に試しては無かったので、試してみたよって話。
worker-loader
をインストール
前回いろいろやって、アンインストールしたworker-loader
を再インストールした。
config-overrides.js
config.module.rules.push({ test: /\.worker\.js$/ , use: { loader: 'worker-loader' } });
import Worker from 'worker-loader!./wasm.worker';
CanvasをWebWorkerへ渡す
とりあえずコード
App.tsx
const canvas = document.getElementById('canvas') as HTMLCanvasElement; const offscreen = canvas.transferControlToOffscreen(); worker.postMessage({ canvas: offscreen }, [offscreen]);
wasm.worker.ts
self.onmessage = (event: any)=> { const data = event.data; const canvas = data.canvas.getContext('webgl'); // wasm側にCanvasを渡す call(canvas); }
とりあえずこれで描画できるはず。
再描画しようとして詰まった
CanvasをgetELementById
で取得して、再描画しようとしたら出たエラー。
InvalidStateError: Failed to execute 'transferControlToOffscreen' on 'HTMLCanvasElement': Cannot transfer control from a canvas for more than one time.
解決策
このサイトを参考にしたらできた。
newinweb.com
useRef
でうまくできないし、いい案が思い浮かばず直接DOM操作してる。
// HTML <div id="canvas-container"></div> // TS document.getElementById('canvas-container')!.innerHTML = '<canvas id="canvas"></canvas>' canvas = document.getElementById('canvas')! as HTMLCanvasElement;
WebWorkerが複数作成される。
これは再描画する際にnew Worker()
をしていた。
解決策
新しく作成させない。
or
worker.terminate()
を行う。
おわり
一応できた。
webworker内でwasmを使用しようとして失敗した(WebGL)
IPFactory Advent Calendar 2020 - Qiitaの8日目の記事
これの続き。
grekumu.hatenablog.jp
wasmの勉強で、こんな感じのやつGLSL Sandbox Gallery作ろうとしていて、wasmの処理をWebWorkerで行うつもりだったが、うまくできなかったって話。
WebWorker使おうと思った理由
www.sitepen.com
インストール
とりあえずworker-loader
をインストール。
npm install worker-loader --save-dev
config-overrides.js
に追加。
config.module.rules.push({ test: /\.worker\.js$/, use: { loader: 'worker-loader' } });
けどうまくいかない。
エラーや試したこと。
Uncaught SyntaxError: Unexpected token <
DevToolsで確認すると、WebWorkerがHTMLを返している。
あんまりWebWorker使ってこなかったから、構文が間違ってるか、loaderあたりだと思う。
グローバルオブジェクトの設定
webpackでHMRが有効だと、WebWorkerでwindow is not defined
ってなる話。
config-overrides.js
にグローバルオブジェクト設定してないせいかと思い、
config.output.globalObject = 'this';
と、設定した。
wasmのDynamic import
worker-loader
を使用し、WebWorker上からDynamic importするとエラーが出る。
これを見る限り、worker-loader
を使用しなければいいらしいので、とりあえず試してみた。
github.com
ReferenceError: Window is not defined.
Windowが大文字なのはlib.dom.d.ts
を参照しているから?
んで、よく考えるとこれDOM参照しようとしてる。
てか、そもそもwasm側でweb-sys
でcanvasを参照しており、結果的にWebWorker内でwindow
オブジェクトを参照していた。(早く気付け俺。)
解決策 OffScreenCanvas
を使う
今回の敗因はこれ。
描画はDOMに直接依存している。そのため、WebWorker上ではCanvasやWebGLの描画ができない。(これ理解してなかった。)
OffscreenCanvas
のレンダリングはDOMから完全に切り離されているため、WebWorker上で描画ができるようになる。
developers.google.com
MDN見た感じsafariとかFirefoxが未対応。
これ使えば対応してないブラウザは色々置き換えてくれるらしい?
GitHub - ai/offscreen-canvas: Polyfill for OffscreenCanvas to move Three.js/WebGL/2D canvas to Web Worker
おわり
ただ失敗したよって話。
customize-cra
やworker-plugin
とか色々試したけどそもそも無理だった。
まだOffScreenCanvas
を試してないから、まず試してみる。
アドカレ、他の人の記事と比べて内容ショボいとか言わないで。
LinuCを受けようと思っている
LinuCの本を買った。
学校を通して受験すると安くなるらしい。
Rust 文字列
文字列型
String
型&str
型
// ヒープに割り当てる let a = String::from("test"); let a = "test".to_string(); let a: String = "test".into(); // read only memory上に割り当てられた文字列への参照 let b: &'static str = "test"; // &str let b = "test";
リテラル
// "test" let byte_escape = "\x74\x65\x73\x74"; // [116, 101, 115, 116] let byte_escape = b"\x74\x65\x73\x74"; // unicode "א" let ucode = "\u{05D0}"; // raw string "\x74 \u{05D0}" let raw_str = r"\x74 \u{05D0}"; // 引用符使う場合 let raw_str = r#" "test" "#; // バイト文字列 [116, 101, 115, 116] let a: &[u8; 4] = b"test";
Create React AppしたReactでWebAssemblyをインポートした
Webpackはwasmファイルの扱い方を知らないため、そのままwasmファイルをインポートすると、エラーが発生する。
コマンド
npm install --save-dev react-app-rewired wasm-loader
config-overrides.js
というファイルを作成し、下記を記述。
const path = require('path'); module.exports = function override(config, env) { const wasmExtensionRegExp = /\.wasm$/; config.resolve.extensions.push('.wasm'); config.module.rules.forEach(rule => { (rule.oneOf || []).forEach(oneOf => { if (oneOf.loader && oneOf.loader.indexOf('file-loader') >= 0) { oneOf.exclude.push(wasmExtensionRegExp); } }); }); config.module.rules.push({ test: wasmExtensionRegExp, include: path.resolve(__dirname, 'src'), use: [{ loader: require.resolve('wasm-loader'), options: {} }] }); return config; };
package.json
を変更する。
"scripts": { "start": "react-app-rewired start", "build": "react-app-rewired build", "test": "react-app-rewired test", "eject": "react-scripts eject" },
WASMまとめ
WebAssemblyとは
バイナリコードをブラウザで動かせるようにしたもの。
JavaScriptは動的型付けのインタプリタ言語ということで、実行速度の遅さが課題となっている。
その課題を解決するため、2013年頃にasm.jsというサブセットが生まれたが、
ファイルサイズが大きくなってしまうことなどの問題があった。
その代替案として生まれたのがWebAssembly(wasm)である。
wasmはファイルサイズがasm.jsと比べて小さくなっている。
使用できる言語一覧
github.com
DOMの処理やFetchAPI、WebAudioなどのAPIも使用できる。
しかしwasmは、jsをすべて置き換えようというものではなく、高速化したい部分をwasmで記述し、
jsと併用することを想定されている。
いろいろなTool
Binaryen
stdweb
wasm-bindgen周り
wasm-bindgen
js-sys
web-sys
wasm-pack
バイナリ表現とテキスト表現関連のツール群
- wabt
IoTでwasm
IoTデバイスでwasmを使用するという動きもある。
様々な言語がwasmへコンパイルできるようになっている。そのため、特定の言語に縛られることが無くなる。
wasmランタイ厶
Wasmer
WAMR
Lucet
Wasmtime
IoT × wasmについて
liux120.github.io
名前が似ていて混乱するやつら(実際に混乱した)
wasm
WebAssembly
wat
WebAssembly Text Format(バイナリ表現のwasmをテキスト表現にしたもの。wasmのテキスト表現は.wat
や.wast
が使われる。)
wast
watと同じ (昔の呼び方?コードの形式が違うらしい。)
wabt
WebAssembly Binary Toolkit (バイナリ表現とテキスト表現関連のツール群。)
wasi
WebAssembly System Interface (安全にOSやホストシステムの機能を呼び出そうという仕様
詳しくはStandardizing WASI: A system interface to run WebAssembly outside the web - Mozilla Hacks - the Web developer blog)
WAMR
WebAssembly Micro Runtime (組み込みデバイスを目的としたランタイム)
Next.jsのメモ
Next.jsのメモ(自分用)
・ 静的ルーティング(pages
ディレクトリ)
・ 動的ルーティング(file name[id].tsx
)
・ クライアントサイドルーティング(<Link>
)
クライアントサイドでナビゲーションを行っているため、ブラウザ全体でリロードすること無く、遷移が行われる。
本番環境では<Link>
コンポーネントが表示されると、バックグラウンドでリンク先のページのコードをプリフェッチしてくれる。
・ CSS-in-JS
・ プリレンダリング(SSR, SSG)
SSRについて
- アクセス時にサーバー側でHTMLを生成
- リクエストごとに生成される
SSG
- ビルド時にHTMLを生成
- 事前にビルドされる
- CDNを利用するため、SSRより高速
更新頻度が高いページ(SNS等)はSSR、そうでない場合はSSG
ページごとに選択可能
可能な限りSSGを利用すべき
・ 拡張性が高い
・ ホットリロードをサポート
・ コード分割
リクエストしたページのコードだけを読み込み、ほかはバックグラウンドでプリフェッチを行う
・ Dynamic Routers
- [id].tsx
・ SSG getStaticProps
- 開発環境では毎回のリクエストごとに実行される
- 本番環境ではビルド時にのみ実行される
- サーバーサイドでのみ実行される
・ SSG getStaticPaths
- Dynamic Routesを使用する際にも静的なファイルを生成するためのAPI
- 開発環境では毎回のリクエストごとに実行される
- 本番環境ではビルド時にのみ実行される
- サーバーサイドでのみ実行される
・ SSR getServerSideProps
- リクエスト時に実行される
- サーバーサイドでのみ実行される
・ CSR SWR
- データフェッチ用のReactフック
- クライアント側でフェッチする際にはこれを使う
今後追加