Rust+WebAssemblyのプロジェクト作成で困ったことについて
Rust and WebAssemblyを読んで,チュートリアルに沿ってwasm-game-of-lifeを作成しようとしたところいくつか問題が発生したため,ここにその修正方法を残す.
cargo install cargo-generate
は問題なく実行できた
npm install npm@latest -g
もOK
cargo generate --git https://github.com/rustwasm/wasm-pack-template
も大丈夫
今回はこの記事のために「wasm-zenn-test」と命名
wasm-pack build
も特に問題なし
npm init wasm-app www
も大丈夫
かつての自分はどこで詰まったんだ?
\wasm-zenn-test\www
に移動してnpm install
を実行すると,
...
...
42 vulnerabilities (2 low, 5 moderate, 30 high, 5 critical)
To address all issues, run:
npm audit fix
Run `npm audit` for details.
という結果が得られた.
上の実行結果は
42件の脆弱性(低度2件, 中程度5件, 高度30件, 致命的5件)がある
これらの問題を解決するにはnpm audit fix
を実行する
npm audit
を実行することで詳細を見ることができる
と言っている
言われた通り,まずはnpm audit
で詳細を見てみよう
...
ansi-html <0.0.8
Severity: high
Uncontrolled Resource Consumption in ansi-html - https://github.com/advisories/GHSA-whgm-jr23-g3j9
fix available via `npm audit fix`
node_modules/ansi-html
webpack-dev-server <=4.7.2
Depends on vulnerable versions of ansi-html
Depends on vulnerable versions of chokidar
Depends on vulnerable versions of selfsigned
Depends on vulnerable versions of webpack-dev-middleware
node_modules/webpack-dev-server
...
package <version
該当パッケージが特定のバージョン未満であることを示している
Severity: Level
脆弱性の深刻度を示している
その下はその他の詳しい説明
次にnpm audit fix
で破壊的ではないところは修復してみる
...
...
9 vulnerabilities (1 low, 8 high)
To address issues that do not require attention, run:
npm audit fix
To address all issues (including breaking changes), run:
npm audit fix --force
上の実行結果は
9件の脆弱性(低度1件, 高度8件)
破壊的な変更を伴わない問題を解決するにはnpm audit fix
を実行する
破壊的な変更を含むすべての問題を解決するにはnpm audit fix --force
実行する
と言っている
特にバックアップが必要なものは無いのでnpm audit fix --force
で無理やり修復させてみる
npm audit fix --force
を実行しても
...
...
5 high severity vulnerabilities
To address all issues, run:
npm audit fix
などとほざいている
じゃあお望み通りもう一度npm audit fix
やってやろうじゃないか
npm error While resolving: webpack-dev-server@5.0.4
npm error Found: webpack@4.43.0
npm error node_modules/webpack
npm error dev webpack@"^4.29.3" from the root project
npm error peer webpack@"^4.0.0 || ^5.0.0" from copy-webpack-plugin@5.1.2
npm error node_modules/copy-webpack-plugin
npm error dev copy-webpack-plugin@"^5.0.0" from the root project
npm error 2 more (terser-webpack-plugin, webpack-cli)
初めて見るエラーが出た
読んでみると
webpack-dev-serverのv5.0.4を期待したが,v4.43.0が見つかった
的なことを言っている.
バージョンを上げればいい感じ?
まずパッケージのバージョンを確認する.
package.jsonファイルを開いてwebpackとwebpack-dev-serverのバージョンが一致しているか確認
自分の環境では
...
"devDependencies": {
"webpack": "^4.29.3",
"webpack-dev-server": "5.0.4"
...
},
...
となっていた.webpackを5.0.4に合わせれば良いっぽい
その為にまず,
npm install -g npm-check-updates
// or
yarn add global npm-check-updates
でnpm-check-updates
をインストール.(自分は前者)
ncu
コマンドでバージョンアップが必要なパッケージをリストアップ
ncu
> copy-webpack-plugin ^5.0.0 → ^12.0.2
> webpack ^4.29.3 → ^5.91.0
> webpack-cli ^3.1.0 → ^5.1.4
> Run ncu -u to upgrade package.json
ncu -u
コマンドでpackage.jsonを最新バージョンに更新する
ncu -u
> copy-webpack-plugin ^5.0.0 → ^12.0.2
> webpack ^4.29.3 → ^5.91.0
> webpack-cli ^3.1.0 → ^5.1.4
> Run npm install to install new versions.
これでnpm install
については解決した
次に,npmのhello-wasm-pack
ではなくlocalのwasm-zenn-test
パッケージを使用したいので,\wasm-zenn-test\www\package.json
に
{
...
"dependencies": {
"wasm-zenn-test": "file:../pkg"
}
...
}
を追加
再びnpm install
を実行.これも問題なくいけた
ここでnpm run start
でサーバーを開始させようとすると,
[webpack-cli] Failed to load 'C:\Users\MyName\Desktop\wasm-zenn-test\www\webpack.config.js' config
[webpack-cli] Invalid options object. Copy Plugin has been initialized using an options object that does not match the API schema.
- options[0] should be an object:
object { patterns, options? }
というエラーが
これはwebpack.config.js
のCopy Plugin
の設定がAPIスキーマと一致しないために発生しているらしい.該当箇所を確認してみると,
...
module.exports = {
...
plugins: [
new CopyWebpackPlugin(['index.html'])
],
...
}
となっていた.
本来CopyWebpackPlugin
は
new CopyWebpackPlugin({
patterns: [...],
options: {...},
})
となっているべきらしい(patternsとoptionsで括弧の種類が違うことに注意)
あるべき姿に合わせて修正した
new CopyWebpackPlugin({
patterns: ["index.html"],
options: {},
})
optionsはとりあえず空にしておいた.後で何かに変更するかも.
追記:opotionsはなくても良いっぽい.
new CopyWebpackPlugin({
patterns: ["index.html"],
})
これでnpm run start
を実行すると
...
modules by path ../pkg/ 1.32 KiB
../pkg/wasm_zenn_test_bg.wasm 336 bytes [built] [code generated] [1 error]
...
ERROR in ../pkg/wasm_zenn_test_bg.wasm 1:0
Module parse failed: Unexpected character '' (1:0)
The module seem to be a WebAssembly module, but module is not flagged as WebAssembly module for webpack.
BREAKING CHANGE: Since webpack 5 WebAssembly is not enabled by default and flagged as experimental feature.
You need to enable one of the WebAssembly experiments via 'experiments.asyncWebAssembly: true' (based on async modules) or 'experiments.syncWebAssembly: true' (like webpack 4, deprecated).
For files that transpile to WebAssembly, make sure to set the module type in the 'module.rules' section of the config (e. g. 'type: "webassembly/async"').
(Source code omitted for this binary file)
@ ../pkg/wasm_zenn_test.js 1:0-49 3:15-19
@ ./index.js 1:0-39 3:0-10
@ ./bootstrap.js 4:0-20
webpack 5.91.0 compiled with 1 error in 667 ms
...
これはWebpackがWebAssemblyモジュールとしてフラグが立っていないモジュールを解析しようとして失敗しているらしい.Webpack5からはWebAssemblyはデフォルトでは無効になっており,実験的な機能としてフラグが立てられている.
これを解決するために,Webpackの設定でWebAssemblyの実験を有効にする必要がある.以下のようにwebpack.config.js
ファイルを変更する.
...
module.exports = {
...
experiments: {
asyncWebAssembly: true,
},
}
これでnpm run start
を実行すると,うまくいった.完了
次は,これに似たRustとWebAssemblyによるゲーム開発のセットアップもやってみる
まず
mkdir test-dir
cd test-dir
npm init rust-webpack
すると
> npx
> create-rust-webpack
🦀 Rust + 🕸 WebAssembly + Webpack = ❤️
Installed dependencies ✅
という可愛い実行結果が返ってくる.ここまでは良い,非常に.
ここで,npm run start
を実行.
既にwasm-packはインストールされているので,本に書いてあるようなエラーは出なかった.
このエラー解消については,本を参照していただきたい
Rustの最新バージョンであるedition2021を利用するために,Cargo.toml
ファイルの設定を
...
[package]
...
edition = "2021"
...
とした
これでnpm run start
したら色々エラーが出た
...
i 「wdm」: Compiled successfully.
i 「wdm」: Compiling...
i 「wdm」: wait until bundle finished: /index.js
× 「wdm」: Hash: fef9f69763b18842e1fd
Version: webpack 4.47.0
Time: 22ms
Built at: 2024/05/03 13:23:37
2 assets
Entrypoint index = index.js
[./pkg/index.js] 0 bytes {0} [built]
+ 59 hidden modules
ERROR in Rust compilation.
...
これが3セットくらい
まずはcargo build
で依存関係が正しくビルドされることを確認する
→これは問題なし
cargo check
でコードのエラーなどをチェック
→これも問題なし
wasm-pack
とwebpack
が正しくインストールされているか確認
→webpack
がインストールされていなかった
npm install -g webpack
でwebpack
をインストールする
CLI for webpack must be installed.
webpack-cli (https://github.com/webpack/webpack-cli)
We will use "npm" to install the CLI via "npm install -D webpack-cli".
Do you want to install 'webpack-cli' (yes/no):
webpack用のCLIがインストールされている必要があるので,今(npm install -D webpack-cli
を使って)インストールしますか?みたいなことを言われている.
とりあえずyesでインストールする
Installing 'webpack-cli' (running 'npm install -D webpack-cli')...
up to date, audited 591 packages in 3s
40 packages are looking for funding
run `npm fund` for details
10 vulnerabilities (1 low, 9 high)
To address issues that do not require attention, run:
npm audit fix
To address all issues (including breaking changes), run:
npm audit fix --force
Run `npm audit` for details.
Error: Cannot find module 'webpack-cli/package.json'
Require stack:
- C:\Users\sohtn\AppData\Roaming\nvm\v21.7.3\node_modules\webpack\bin\webpack.js
at Module._resolveFilename (node:internal/modules/cjs/loader:1142:15)
at Function.resolve (node:internal/modules/helpers:190:19)
at runCli (C:\Users\sohtn\AppData\Roaming\nvm\v21.7.3\node_modules\webpack\bin\webpack.js:78:26)
at C:\Users\sohtn\AppData\Roaming\nvm\v21.7.3\node_modules\webpack\bin\webpack.js:180:5
at process.processTicksAndRejections (node:internal/process/task_queues:95:5) {
code: 'MODULE_NOT_FOUND',
requireStack: [
'C:\\Users\\sohtn\\AppData\\Roaming\\nvm\\v21.7.3\\node_modules\\webpack\\bin\\webpack.js'
]
}
という実行結果がでた,,,見たことあるな(勘のいいガキ)
新たにパッケージをインストールしたことでまた脆弱性が見つかったようだ.
npm audit
で詳細を確認する.
10 vulnerabilities (1 low, 9 high)
To address issues that do not require attention, run:
npm audit fix
To address all issues (including breaking changes), run:
npm audit fix --force
上の方でやったようにnpm audit fix --force
の後にnpm audit fix
で修復を試みる.
同じようなエラーが出たので,先ほどと同じ方法で解消する.
...
npm error While resolving: copy-webpack-plugin@12.0.2
npm error Found: webpack@4.47.0
npm error node_modules/webpack
npm error dev webpack@"^4.42.0" from the root project
npm error peer webpack@"^4.0.0" from terser-webpack-plugin@1.4.5
npm error node_modules/terser-webpack-plugin
npm error terser-webpack-plugin@"^1.4.3" from webpack@4.47.0
npm error 1 more (webpack-cli)
...
こんなエラーが出たので,この解消法を詳しくやっていく.
copy-webpack-plugin
のv12.0.2はwebpack
のv4.47.0と互換性がないので,webpack
をv5.xに変更する必要がある.
package.json
で
{
...
"devDependencies": {
...
"webpack": "^5.0.0",
...
}
}
としてからnpm audit fix
をするとうまくいった
npm run start
を実行すると
> rust-webpack-template@0.1.0 start
> rimraf dist pkg && webpack-dev-server --open -d
The command moved into a separate package: @webpack-cli/serve
Would you like to install serve? (That will run npm install -D @webpack-cli/serve) (yes/NO) :
が出て,yesを選択すると
npm error While resolving: rust-webpack-template@0.1.0
npm error Found: webpack@5.91.0
npm error node_modules/webpack
npm error dev webpack@"^5.0.0" from the root project
npm error peer webpack@"5.x.x" from @webpack-cli/serve@2.0.5
npm error node_modules/@webpack-cli/serve
npm error dev @webpack-cli/serve@"*" from the root project
npm error
npm error Could not resolve dependency:
npm error peer webpack@"4.x.x" from webpack-cli@3.3.12
npm error node_modules/webpack-cli
npm error dev webpack-cli@"^3.3.12" from the root project
が出たので,例によって
{
...
"devDependencies": {
...
"webpack-cli": "^4.0.0",
...
}
}
で再びnpm run start
npm error While resolving: rust-webpack-template@0.1.0
npm error Found: webpack-cli@4.10.0
npm error node_modules/webpack-cli
npm error dev webpack-cli@"^4.0.0" from the root project
npm error
npm error Could not resolve dependency:
npm error peer webpack-cli@"5.x.x" from @webpack-cli/serve@2.0.5
npm error node_modules/@webpack-cli/serve
npm error dev @webpack-cli/serve@"*" from the root project
またこれ(呆)
{
...
"devDependencies": {
...
"webpack-cli": "^5.0.0",
...
}
}
これでさすがに行けるやろ(フラグ)
npm run start
すると
> rust-webpack-template@0.1.0 start
> rimraf dist pkg && webpack-dev-server --open -d
[webpack-cli] Error: Option '-d, --devtool <value>' argument missing
[webpack-cli] Run 'webpack --help' to see available commands and options
てなった(フラグ回収)
これはpackage.json
でnpm run start
のscriptがrimraf dist pkg && webpack-dev-server --open -d
に設定されているが,この-d
というのはソースマップの種類を指定するためのものなのにソースマップが与えられていないことが原因らしい
これを解消するにはソースマップを引数に与えるか,そもそも-d
を消す必要がある.
面倒なので後者をしてから再びnpm run start
すると
> rust-webpack-template@0.1.0 start
> rimraf dist pkg && webpack-dev-server --open
[webpack-cli] Failed to load 'C:\Users\sohtn\Desktop\test-dir\webpack.config.js' config
[webpack-cli] Invalid options object. Copy Plugin has been initialized using an options object that does not match the API schema.
- options[0] should be an object:
object { patterns, options? }
上の方で似たエラーが出たので,同様に解消する
...
module.exports = {
...
plugins: [
new CopyPlugin([
path.resolve(__dirname, "static")
]),
...
],
};
となっていたものを
module.exports = {
...
plugins: [
new CopyPlugin({ patterns: [path.resolve(__dirname, "static")] }),
...
],
};
と変更した
またまたまたまたまたnpm run start
します
[webpack-cli] Invalid options object. Dev Server has been initialized using an options object that does not match the API schema.
- options has an unknown property 'contentBase'. These properties are valid:
object { allowedHosts?, bonjour?, client?, compress?, devMiddleware?, headers?, historyApiFallback?, host?, hot?, ipc?, liveReload?, onListening?, open?, port?, proxy?, server?, setupExitSignals?, setupMiddlewares?, static?, watchFiles?, webSocketServer? }
はい(怒)ちなみにここでは分かりづらいかもしれませんが,このメッセージは全て真っ赤なのでかなり怖いしイライラします.
このエラーはwebpack.config.js
の
...
module.exports = {
...
devServer: {
contentBase: dist,
},
...
};
のcontentBase
が認識されていないことを示している.
webpack-dev-server
の新しいバージョンでは,contentBase
の代わりにstatic
オプションを使用する必要がある.よって
...
module.exports = {
...
devServer: {
static: {
directory: path.join(__dirname, "dist"),
},
},
...
};
これでnpm run start
をすると前回の最後と同じエラーが出たので,同じように修復する.以下をwebpack.config.js
に追加
...
module.exports = {
...
experiments: {
asyncWebAssembly: true,
},
}
完璧
この2つの方法の違いを知りたい
まずCargo.toml
ファイルの内容.(ここからはcargo generate
→npm init rust-webpack
の順で比較する)
[package]
name = "wasm-zenn-test"
version = "0.1.0"
authors = ["so-hey <soh.tngt@gmail.com>"]
edition = "2021"
[lib]
crate-type = ["cdylib", "rlib"]
[features]
default = ["console_error_panic_hook"]
[dependencies]
wasm-bindgen = "0.2.84"
# The `console_error_panic_hook` crate provides better debugging of panics by
# logging them with `console.error`. This is great for development, but requires
# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for
# code size when deploying.
console_error_panic_hook = { version = "0.1.7", optional = true }
[dev-dependencies]
wasm-bindgen-test = "0.3.34"
[profile.release]
# Tell `rustc` to optimize for small code size.
opt-level = "s"
# You must change these to your own details.
[package]
name = "rust-webpack-template"
description = "My super awesome Rust, WebAssembly, and Webpack project!"
version = "0.1.0"
authors = ["You <you@example.com>"]
categories = ["wasm"]
readme = "README.md"
edition = "2021"
[lib]
crate-type = ["cdylib"]
[profile.release]
# This makes the compiled code faster and smaller, but it makes compiling slower,
# so it's only enabled in release mode.
lto = true
[features]
# If you uncomment this line, it will enable `wee_alloc`:
#default = ["wee_alloc"]
[dependencies]
# The `wasm-bindgen` crate provides the bare minimum functionality needed
# to interact with JavaScript.
wasm-bindgen = "0.2.45"
# `wee_alloc` is a tiny allocator for wasm that is only ~1K in code size
# compared to the default allocator's ~10K. However, it is slower than the default
# allocator, so it's not enabled by default.
wee_alloc = { version = "0.4.2", optional = true }
# The `web-sys` crate allows you to interact with the various browser APIs,
# like the DOM.
[dependencies.web-sys]
version = "0.3.22"
features = ["console"]
# The `console_error_panic_hook` crate provides better debugging of panics by
# logging them with `console.error`. This is great for development, but requires
# all the `std::fmt` and `std::panicking` infrastructure, so it's only enabled
# in debug mode.
[target."cfg(debug_assertions)".dependencies]
console_error_panic_hook = "0.1.5"
# These crates are used for running unit tests.
[dev-dependencies]
wasm-bindgen-test = "0.2.45"
futures = "0.1.27"
js-sys = "0.3.22"
wasm-bindgen-futures = "0.3.22"
[lib]について
"cdylib"
はC Dynamic Libraryで「C互換の動的ライブラリ」を意味している.他の言語(特にC言語)からロードできる動的ライブラリを生成する.これは他の言語からRustのコードを使用するための一般的な方法である.
"rlib"
はRust Libraryで「Rustライブラリ」を意味している.他のRustのコードから使用するための静的ライブラリを生成する.これはCargoが内部で使用する中間生成物とも言える.
このプロジェクトから生成されるライブラリのタイプを設定しているっぽい.
[profile.release]はリリースビルドの設定を指定する.
lto = true
はリンク時最適化(Link Time Optimization)を有効にすることを指示している.LTOはコンパイラが生成するすべてのクレートを一緒に最適化する機能で,これにより生成されるコードがより高速かつ小さくなる.ただし,LTOを有効にするとコンパイル時間が長くなるため,通常はリリースモードでのみ有効にされるらしい.
[features]はこのプロジェクトをライブラリとしたときのfeatureフラグについての記述をするところっぽい.
default =
で設定したfeatureはパッケージがビルドされるときにデフォルトで有効になる.
console_error_panic_hook
はRustのパニックフックの1つで,パニックメッセージをconsole.error
に転送する.
コメントアウトされているwee_alloc
は「Wasm-Enabled, Elfin Allocator」の略で,WebAssembly向けに設計されたメモリアロケータのこと.wee_allocは非常に小さなコードサイズを持つことを特徴としている.
ただ,コードサイズの小型化を目的としているので,デフォルトのグローバルアロケータなどに比べてパフォーマンスが劣る場合がある.そのため,動的なメモリ割り当てが頻繁に行われるような場面では,wee_alloc
の使用は適していないかもしれない.