rust-wasm 與 react 集成
概要
爲什麼需要 Webassembly?
曾經複雜計算的需求,多數聚集在後端,隨着的技術和業務的日益發展,在前端也出現了越來越多的頻繁複雜計算和高性能的需求。此時通過 js 來和後端交互,反而優秀的 js 變成了應用的瓶頸
在這樣的情況下,WebAssembly(WASM) 提供了高性能和安全的環境,以接近本機的速度來運行計算。
WASM 是一種編譯目標,而不是一種語言,你可以通過各種語言 (Rust、Golang、C、C++...) 編譯得到。Chrome、FireFox、Safari、Edge 中得到了很好的支持。
準備
相關知識:
react
node
npm
wasm-pack
rust
rust-wasm
cargo
cargo-generate
wasm-bindgen
linux
linux常用命令
如果你對Rust
和React
沒有相關的知識儲備,請先參照官方文檔。
-
Rust: https://www.rust-lang.org/
-
React: https://reactjs.org/
環境準備:
注: 教程的環境爲 mac 系統。
我們需要npm
和cargo
。用來構建 react 應用和 rust-wasm。
如果你對兩者沒有了解。請先參照官方教程。
-
npm: https://www.npmjs.com/get-npm
-
cargo: https://doc.rust-lang.org/cargo/getting-started/installation.html
步驟概覽
-
創建 React 應用
-
Eject React 應用
-
cargo new
創建 Rust 應用 -
創建 Rust 應用
-
編譯 WASM
-
在 React 應用中使用 WASM
-
附加 使用
cargo-generate
創建 Rust-Wasm 應用
創建 React 應用
如果你已經使用 React 腳手架,那麼你應該會有npx
命令,這裏創建的 React 應用的方式和React
官方文檔一致。就不贅述。
-
創建目錄
mkdir react-wasm
-
進入目錄
cd react-wasm
-
創建應用
npx create-react-app react-client
當創建好以後我們得到目錄結構如下
➜ react-client git:(master) ls
README.md node_modules package-lock.json package.json public src
- 彈出配置 (Ejecting)
參考資料: https://stackoverflow.com/questions/49737652/what-does-eject-do-in-create-react-app
- 運行命令
npm run eject
命令完成後,結構如下:
➜ react-client git:(master) ✗ ls
README.md config node_modules package-lock.json package.json public scripts src
測試一下 React 應用是否正常
- 在
react-client
目錄下運行npm start
瀏覽器中訪問http://localhost:3000/
,看到以下的結果,證明 React 應用正常。
創建 Rust 應用
回到react-wasm
目錄下。
➜ react-wasm ls
react-client
-
我們使用
cargo
來創建一個新的文件夾 -
運行
cargo new wasm
, 結果如下
➜ react-wasm ls
react-client wasm
- 進入到
wasm
目錄下
➜ wasm git:(master) ✗ ls
Cargo.lock Cargo.toml src target
- 打開
Cargo.toml
[package]
name = "wasm"
version = "0.1.0"
authors = ["jim <303600370@qq.com>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
- 增加依賴
[package]
name = "wasm"
version = "0.1.0"
authors = ["jim <303600370@qq.com>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
crate-type = ["cdylib"]
path ="src/lib.rs"
[dependencies]
wasm-bindgen ="0.2.34"
- 進入到
src
目錄下 將main.rs
重命名或者刪除之後創建lib.rs
➜ wasm git:(master) ✗ ls
Cargo.lock Cargo.toml src target
➜ wasm git:(master) ✗ cd src
➜ src git:(master) ✗ ls
main.rs
➜ src git:(master) ✗ mv main.rs lib.rs
➜ src git:(master) ✗ ls
lib.rs
➜ src git:(master) ✗
- 運行
cargo build
看下是否能正常編譯
➜ src git:(master) ✗ cargo build
Compiling proc-macro2 v1.0.24
Compiling log v0.4.14
Compiling wasm-bindgen-shared v0.2.71
Compiling syn v1.0.60
Compiling bumpalo v3.6.1
Compiling quote v1.0.9
Compiling wasm-bindgen-backend v0.2.71
Compiling wasm-bindgen-macro-support v0.2.71
Compiling wasm-bindgen-macro v0.2.71
Compiling wasm-bindgen v0.2.71
Compiling wasm v0.1.0 (/Users/jim/dev/tmp/react-wasm/wasm)
Finished dev [unoptimized + debuginfo] target(s) in 11.70s
- 編輯
lib.rs
內容
use::wasm_bindgen::prelude::*;
#[wasm_bindgen]
extern "C" {
fn alert(s: &str);
}
#[wasm_bindgen]
pub fn hello() {
unsafe {
alert("Hello World");
}
}
宏#[wasm_bindgen]
會告訴wasm-bindgen
幫我們生成一個可以調用的方法
此時,你已經準備好了編譯 wasm 文件並在 react 應用中使用
關於 wasm-bindgen
-
將 JS 功能導入到 Rust 中,例如 DOM 操作, 控制檯日誌記錄或性能監控。
-
將 Rust 功能導出到 JS,例如類,函數等
-
使用豐富的類型,例如字符串,數字,類,閉包和對象,而不是簡單地使用 u32 浮點數。
-
自動爲 JS 使用的 Rust 代碼生成 TypeScript 綁定
可以參照官方文檔 : https://rustwasm.github.io/docs/wasm-bindgen/
編譯 WASM
我們已經完成了定義 Rust 函數並告訴 wasm-bindgen 編譯內容的工作。wasm-pack 幫助我們創建 Javascript 和 Typescript 接口。
-
使用
cargo
安裝wasm-pack
-
運行
cargo install wasm-pack
命令
由於本機環境已經安裝過,所以得到以下結果
➜ src git:(master) ✗ cargo install wasm-pack
Updating `git://mirrors.ustc.edu.cn/crates.io-index` index
Downloaded wasm-pack v0.9.1 (registry `git://mirrors.ustc.edu.cn/crates.io-index`)
Downloaded 1 crate (422.5 KB) in 3.23s
Ignored package `wasm-pack v0.9.1` is already installed, use --force to override
➜ src git:(master) ✗
同樣可以參考官方文檔
wasm-pack
: https://rustwasm.github.io/wasm-pack/installer/
-
確保你的
wasm-pack
已經安裝完成 -
運行
wasm-pack
命令,得到以下結果
➜ src git:(master) ✗ wasm-pack
wasm-pack 0.9.1
Ashley Williams <ashley666ashley@gmail.com>
📦 ✨ pack and publish your wasm!
USAGE:
wasm-pack [FLAGS] [OPTIONS] <SUBCOMMAND>
FLAGS:
-h, --help Prints help information
-q, --quiet No output printed to stdout
-V, --version Prints version information
-v, --verbose Log verbosity is based off the number of v used
OPTIONS:
--log-level <log_level> The maximum level of messages that should be logged by wasm-pack. [possible values:
info, warn, error] [default: info]
SUBCOMMANDS:
build 🏗️ build your npm package!
help Prints this message or the help of the given subcommand(s)
login 👤 Add an npm registry user account! (aliases: adduser, add-user)
new 🐑 create a new project with a template
pack 🍱 create a tar of your npm package but don't publish!
publish 🎆 pack up your npm package and publish!
test 👩🔬 test your wasm!
-
使用
wasm-pack build
命令編譯 wasm 文件 -
可以通過
--out-dir
來指定文件輸出位置 -
這裏我們不指定目錄直接運行
wasm-pack build
命令
➜ src git:(master) ✗ wasm-pack build
[INFO]: 🎯 Checking for the Wasm target...
[INFO]: 🌀 Compiling to Wasm...
Compiling proc-macro2 v1.0.24
Compiling unicode-xid v0.2.1
Compiling log v0.4.14
Compiling syn v1.0.60
Compiling wasm-bindgen-shared v0.2.71
Compiling cfg-if v1.0.0
Compiling bumpalo v3.6.1
Compiling lazy_static v1.4.0
Compiling wasm-bindgen v0.2.71
Compiling quote v1.0.9
Compiling wasm-bindgen-backend v0.2.71
Compiling wasm-bindgen-macro-support v0.2.71
Compiling wasm-bindgen-macro v0.2.71
Compiling wasm v0.1.0 (/Users/jim/dev/tmp/react-wasm/wasm)
warning: unnecessary `unsafe` block
--> src/lib.rs:13:5
|
13 | unsafe {
| ^^^^^^ unnecessary `unsafe` block
|
= note: `#[warn(unused_unsafe)]` on by default
warning: 1 warning emitted
Finished release [optimized] target(s) in 10.75s
⚠️ [WARN]: origin crate has no README
[INFO]: ⬇️ Installing wasm-bindgen...
[INFO]: Optimizing wasm binaries with `wasm-opt`...
[INFO]: Optional fields missing from Cargo.toml: 'description', 'repository', and 'license'. These are not necessary, but recommended
[INFO]: ✨ Done in 6m 50s
[INFO]: 📦 Your wasm pkg is ready to publish at /Users/jim/dev/tmp/react-wasm/wasm/pkg.
- 在
wasm
目錄下生成了一個pkg
目錄
➜ wasm git:(master) ✗ ls
Cargo.lock Cargo.toml pkg src target
➜ wasm git:(master) ✗ cd pkg
➜ pkg git:(master) ✗ ls
package.json wasm.d.ts wasm.js wasm_bg.js wasm_bg.wasm wasm_bg.wasm.d.ts
➜ pkg git:(master) ✗
在pkg
目錄中*.wasm
就是我們的 WASM 文件。其中還包括了 typescript 的定義*.d.ts
和 js 文件*.js
。另外,它還會生成一個package.json
,接下來,我們將會使用這個文件配合npm
成爲我們 react 的應用依賴。
在 React 應用中使用 WASM
回到我們的 React 應用
- 打開
/react-client/package.json
{
"name": "react-client",
"version": "0.1.0",
"private": true,
"dependencies": {
"@babel/core": "7.12.3",
"@pmmmwh/react-refresh-webpack-plugin": "0.4.3",
"@svgr/webpack": "5.5.0",
"@testing-library/jest-dom": "^5.11.9",
"@testing-library/react": "^11.2.5",
"@testing-library/user-event": "^12.8.1",
"@typescript-eslint/eslint-plugin": "^4.5.0",
"@typescript-eslint/parser": "^4.5.0",
"babel-eslint": "^10.1.0",
"babel-jest": "^26.6.0",
"babel-loader": "8.1.0",
"babel-plugin-named-asset-import": "^0.3.7",
"babel-preset-react-app": "^10.0.0",
"bfj": "^7.0.2",
"camelcase": "^6.1.0",
"case-sensitive-paths-webpack-plugin": "2.3.0",
"css-loader": "4.3.0",
"dotenv": "8.2.0",
"dotenv-expand": "5.1.0",
"eslint": "^7.11.0",
"eslint-config-react-app": "^6.0.0",
"eslint-plugin-flowtype": "^5.2.0",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-jest": "^24.1.0",
"eslint-plugin-jsx-a11y": "^6.3.1",
"eslint-plugin-react": "^7.21.5",
"eslint-plugin-react-hooks": "^4.2.0",
"eslint-plugin-testing-library": "^3.9.2",
"eslint-webpack-plugin": "^2.5.2",
"file-loader": "6.1.1",
"fs-extra": "^9.0.1",
"html-webpack-plugin": "4.5.0",
"identity-obj-proxy": "3.0.0",
"jest": "26.6.0",
"jest-circus": "26.6.0",
"jest-resolve": "26.6.0",
"jest-watch-typeahead": "0.6.1",
"mini-css-extract-plugin": "0.11.3",
"optimize-css-assets-webpack-plugin": "5.0.4",
"pnp-webpack-plugin": "1.6.4",
"postcss-flexbugs-fixes": "4.2.1",
"postcss-loader": "3.0.0",
"postcss-normalize": "8.0.1",
"postcss-preset-env": "6.7.0",
"postcss-safe-parser": "5.0.2",
"prompts": "2.4.0",
"react": "^17.0.1",
"react-app-polyfill": "^2.0.0",
"react-dev-utils": "^11.0.3",
"react-dom": "^17.0.1",
"react-refresh": "^0.8.3",
"resolve": "1.18.1",
"resolve-url-loader": "^3.1.2",
"sass-loader": "^10.0.5",
"semver": "7.3.2",
"style-loader": "1.3.0",
"terser-webpack-plugin": "4.2.3",
"ts-pnp": "1.2.0",
"url-loader": "4.1.1",
"web-vitals": "^1.1.0",
"webpack": "4.44.2",
"webpack-dev-server": "3.11.1",
"webpack-manifest-plugin": "2.2.0",
"workbox-webpack-plugin": "5.1.4"
},
"scripts": {
"start": "node scripts/start.js",
"build": "node scripts/build.js",
"test": "node scripts/test.js"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"jest": {
"roots": [
"<rootDir>/src"
],
"collectCoverageFrom": [
"src/**/*.{js,jsx,ts,tsx}",
"!src/**/*.d.ts"
],
"setupFiles": [
"react-app-polyfill/jsdom"
],
"setupFilesAfterEnv": [
"<rootDir>/src/setupTests.js"
],
"testMatch": [
"<rootDir>/src/**/__tests__/**/*.{js,jsx,ts,tsx}",
"<rootDir>/src/**/*.{spec,test}.{js,jsx,ts,tsx}"
],
"testEnvironment": "jsdom",
"testRunner": "/Users/jim/dev/tmp/react-wasm/react-client/node_modules/jest-circus/runner.js",
"transform": {
"^.+\\.(js|jsx|mjs|cjs|ts|tsx)$": "<rootDir>/config/jest/babelTransform.js",
"^.+\\.css$": "<rootDir>/config/jest/cssTransform.js",
"^(?!.*\\.(js|jsx|mjs|cjs|ts|tsx|css|json)$)": "<rootDir>/config/jest/fileTransform.js"
},
"transformIgnorePatterns": [
"[/\\\\]node_modules[/\\\\].+\\.(js|jsx|mjs|cjs|ts|tsx)$",
"^.+\\.module\\.(css|sass|scss)$"
],
"modulePaths": [],
"moduleNameMapper": {
"^react-native$": "react-native-web",
"^.+\\.module\\.(css|sass|scss)$": "identity-obj-proxy"
},
"moduleFileExtensions": [
"web.js",
"js",
"web.ts",
"ts",
"web.tsx",
"tsx",
"json",
"web.jsx",
"jsx",
"node"
],
"watchPlugins": [
"jest-watch-typeahead/filename",
"jest-watch-typeahead/testname"
],
"resetMocks": true
},
"babel": {
"presets": [
"react-app"
]
}
}
- 在
dependencies
中增加依賴項
"wasm":"file:../wasm/pkg"
結果如下
{
"name": "react-client",
"version": "0.1.0",
"private": true,
"dependencies": {
"@babel/core": "7.12.3",
"@pmmmwh/react-refresh-webpack-plugin": "0.4.3",
"@svgr/webpack": "5.5.0",
"@testing-library/jest-dom": "^5.11.9",
"@testing-library/react": "^11.2.5",
"@testing-library/user-event": "^12.8.1",
"@typescript-eslint/eslint-plugin": "^4.5.0",
"@typescript-eslint/parser": "^4.5.0",
"babel-eslint": "^10.1.0",
"babel-jest": "^26.6.0",
"babel-loader": "8.1.0",
"babel-plugin-named-asset-import": "^0.3.7",
"babel-preset-react-app": "^10.0.0",
"bfj": "^7.0.2",
"camelcase": "^6.1.0",
"case-sensitive-paths-webpack-plugin": "2.3.0",
"css-loader": "4.3.0",
"dotenv": "8.2.0",
"dotenv-expand": "5.1.0",
"eslint": "^7.11.0",
"eslint-config-react-app": "^6.0.0",
"eslint-plugin-flowtype": "^5.2.0",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-jest": "^24.1.0",
"eslint-plugin-jsx-a11y": "^6.3.1",
"eslint-plugin-react": "^7.21.5",
"eslint-plugin-react-hooks": "^4.2.0",
"eslint-plugin-testing-library": "^3.9.2",
"eslint-webpack-plugin": "^2.5.2",
"file-loader": "6.1.1",
"fs-extra": "^9.0.1",
"html-webpack-plugin": "4.5.0",
"identity-obj-proxy": "3.0.0",
"jest": "26.6.0",
"jest-circus": "26.6.0",
"jest-resolve": "26.6.0",
"jest-watch-typeahead": "0.6.1",
"mini-css-extract-plugin": "0.11.3",
"optimize-css-assets-webpack-plugin": "5.0.4",
"pnp-webpack-plugin": "1.6.4",
"postcss-flexbugs-fixes": "4.2.1",
"postcss-loader": "3.0.0",
"postcss-normalize": "8.0.1",
"postcss-preset-env": "6.7.0",
"postcss-safe-parser": "5.0.2",
"prompts": "2.4.0",
"react": "^17.0.1",
"react-app-polyfill": "^2.0.0",
"react-dev-utils": "^11.0.3",
"react-dom": "^17.0.1",
"react-refresh": "^0.8.3",
"resolve": "1.18.1",
"resolve-url-loader": "^3.1.2",
"sass-loader": "^10.0.5",
"semver": "7.3.2",
"style-loader": "1.3.0",
"terser-webpack-plugin": "4.2.3",
"ts-pnp": "1.2.0",
"url-loader": "4.1.1",
"web-vitals": "^1.1.0",
"webpack": "4.44.2",
"webpack-dev-server": "3.11.1",
"webpack-manifest-plugin": "2.2.0",
"workbox-webpack-plugin": "5.1.4",
"wasm":"file:../wasm/pkg"
},
"scripts": {
"start": "node scripts/start.js",
"build": "node scripts/build.js",
"test": "node scripts/test.js"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"jest": {
"roots": [
"<rootDir>/src"
],
"collectCoverageFrom": [
"src/**/*.{js,jsx,ts,tsx}",
"!src/**/*.d.ts"
],
"setupFiles": [
"react-app-polyfill/jsdom"
],
"setupFilesAfterEnv": [
"<rootDir>/src/setupTests.js"
],
"testMatch": [
"<rootDir>/src/**/__tests__/**/*.{js,jsx,ts,tsx}",
"<rootDir>/src/**/*.{spec,test}.{js,jsx,ts,tsx}"
],
"testEnvironment": "jsdom",
"testRunner": "/Users/jim/dev/tmp/react-wasm/react-client/node_modules/jest-circus/runner.js",
"transform": {
"^.+\\.(js|jsx|mjs|cjs|ts|tsx)$": "<rootDir>/config/jest/babelTransform.js",
"^.+\\.css$": "<rootDir>/config/jest/cssTransform.js",
"^(?!.*\\.(js|jsx|mjs|cjs|ts|tsx|css|json)$)": "<rootDir>/config/jest/fileTransform.js"
},
"transformIgnorePatterns": [
"[/\\\\]node_modules[/\\\\].+\\.(js|jsx|mjs|cjs|ts|tsx)$",
"^.+\\.module\\.(css|sass|scss)$"
],
"modulePaths": [],
"moduleNameMapper": {
"^react-native$": "react-native-web",
"^.+\\.module\\.(css|sass|scss)$": "identity-obj-proxy"
},
"moduleFileExtensions": [
"web.js",
"js",
"web.ts",
"ts",
"web.tsx",
"tsx",
"json",
"web.jsx",
"jsx",
"node"
],
"watchPlugins": [
"jest-watch-typeahead/filename",
"jest-watch-typeahead/testname"
],
"resetMocks": true
},
"babel": {
"presets": [
"react-app"
]
}
}
- 如果你要更改依賴的名稱你需要回到
wasm/pkg
下編輯package.json
{
"name": "wasm",
"collaborators": [
"jim <303600370@qq.com>"
],
"version": "0.1.0",
"files": [
"wasm_bg.wasm",
"wasm.js",
"wasm.d.ts"
],
"module": "wasm.js",
"types": "wasm.d.ts",
"sideEffects": false
}
-
安裝
wasm-loader
-
在
react-client
目錄下運行npm install --save-dev wasm-loader
, 結果如下
➜ react-client git:(master) ✗ npm install --save-dev wasm-loader
npm WARN tsutils@3.20.0 requires a peer of typescript@>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta but none is installed. You must install peer dependencies yourself.
+ wasm-loader@1.3.0
added 8 packages from 11 contributors and audited 1962 packages in 12.833s
132 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
- 打開
react-client/config
目錄下的webpack.config.js
文件,在rules
中添加以下內容:
//如果存在這行,則不需要
{ parser: { requireEnsure: false } },
{
test: /\.wasm$/, // only load WASM files (ending in .wasm)
// only files in our src/ folder
include: path.resolve(__dirname, "src"),
use: [{
// load and use the wasm-loader dictionary
loader: require.resolve("wasm-loader"),
options: {}
}],
},
- 找到
file-loader
,如下:
{
loader: require.resolve('file-loader'),
// Exclude `js` files to keep "css" loader working as it injects
// its runtime that would otherwise be processed through "file" loader.
// Also exclude `html` and `json` extensions so they get processed
// by webpacks internal loaders.
exclude: [/\.(js|mjs|jsx|ts|tsx)$/, /\.html$/, /\.json$/],
options: {
name: 'static/media/[name].[hash:8].[ext]',
},
},
- 在
file-loader
中添加/\.wasm$/
{
loader: require.resolve('file-loader'),
// Exclude `js` files to keep "css" loader working as it injects
// its runtime that would otherwise be processed through "file" loader.
// Also exclude `html` and `json` extensions so they get processed
// by webpacks internal loaders.
exclude: [/\.(js|mjs|jsx|ts|tsx)$/, /\.html$/, /\.json$/,/\.wasm$/],
options: {
name: 'static/media/[name].[hash:8].[ext]',
},
},
恭喜你到了這一步,接下來我們要修改App.js
裏的內容。
- 打開
/react-client/src
中的App.js
import logo from './logo.svg';
import './App.css';
function App() {
return (
<div class>
<header class>
<img src={logo} class />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
class
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}
export default App;
- 修改
App.js
, 添加import('wasm').then(module => { console.log(module) })
import logo from './logo.svg';
import './App.css';
function App() {
import('wasm').then(module => {
console.log(module)
})
return (
<div class>
<header class>
<img src={logo} class />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
class
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}
export default App;
- 運行
npm i
保證我們的依賴和配置生效
➜ src git:(master) ✗ npm i
npm WARN tsutils@3.20.0 requires a peer of typescript@>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta but none is installed. You must install peer dependencies yourself.
audited 1963 packages in 7.57s
132 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
- 啓動 react 應用。打開控制檯,看一下輸出
可以看到 wasm 已經已經應用成功,還可以看到我們在 rust 應用中定義的 hello 方法
- 編輯
App.js
, 調用我們的 wasm 中的 hello 方法
import logo from './logo.svg';
import './App.css';
function App() {
import('wasm').then(({hello}) => {
hello();
})
return (
<div class>
<header class>
<img src={logo} class />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
class
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}
export default App;
_* 恭喜你~~~~!!!,我們成功的調用了在 rust 應用中定義的 hello 方法,並把它集成在 react 應用中了_ *
附加:使用 cargo-generate
創建 Rust-Wasm 應用
如果你閱讀到此處還是不能夠理解整個流程中我們做了什麼的話,建議你重新閱讀或者思考一下整個流程。
接下來的內容會需要你對以上內容有一定理解之後閱讀起來會比較輕鬆。接下來的內容,是在上文中的擴展。
- 安裝
cargo-generate
cargo install cargo-generate
如果沒有 openssl 則使用
cargo install cargo-generate --features vendored-openssl
用例:cargo generate --git https://github.com/githubusername/mytemplate.git
- 安裝
wasm-pack
cargo install wasm-pack
- 安裝
wasm-bindgen
cargo install wasm-bindgen-cli --force
- 生成 rust 應用
cargo generate --git https://github.com/rustwasm/wasm-pack-template.git --name my-project
cd my-project
得到結果如下
➜ react-wasm cargo generate --git https://github.com/rustwasm/wasm-pack-template.git --name my-project
cd my-project
🔧 Creating project called `my-project`...
✨ Done! New project created /Users/jim/dev/tmp/react-wasm/my-project
➜ my-project git:(master) ✗
目錄結構
➜ my-project git:(master) ✗ ls
Cargo.toml LICENSE_APACHE LICENSE_MIT README.md src tests
➜ my-project git:(master) ✗
- build
wasm-pack build
- 本地可以使用 packgejson 配置
"wasm-demo": "file:../pkg",
這個工具能夠迅速的幫你生成一個 rust-wasm 應用。
實際上只是一個模板,這個也算一個生產力工具吧,仁者見仁。
更多操作參見 github
cargo-generate
: https://github.com/cargo-generate/cargo-generate.git
wasm-pack-template
: https://github.com/rustwasm/wasm-pack-template.git
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/yjIcSi4s978uhufyk9aKPw