准备
此篇文章我们主要使用 Rust 来编写我们的 WebAssembly 工具库然后在 React 应用进行使用。所以需要准备好下列的环境
- Rust 开发环境(rustup、rustc、cargo 这些)
- 前端开发环境(node、npm 这些)
- wasm-pack
(cargo install wasm-pack)
开始
开始前我们先要准备一个前端应用,这里我们使用 create-react-app
来创建一个 React 项目。
如果没有安装 create-react-app
,先用 pnpm (npm / yarn 也行)全局安装一下
npm install -g create-react-app
创建项目
使用 typescript 模板来创建项目,以获得更好的类型提示。
create-react-app react-wasm --template typescript
进入到刚创建好的项目目录中
cd react-wasm
创建好 react 项目之后,我们接下来使用 wasm-pack 创建一个 wasm 工具库
wasm-pack new wasm-lib
创建完成后我们的目录结构是像下面这样子的,
src
目录主要编写前端应用代码
wasm-lib/src
目录主要编写 rust wasm 代码
wasm-lib/src/lib.rs
目录下,这里就是我们可以进行编写供前端调用的 WebAssembly 函数。这里默认写好了一个 greet 函数,然后里面调用了 alert 弹框。接下来我们就去看看如何在前端中进行使用这个函数。
mod utils;
use wasm_bindgen::prelude::*;
// 当 `wee_alloc` 特性开启的时候, 使用 `wee_alloc` 作为全局分配器
#[cfg(feature = "wee_alloc")]
#[global_allocator]
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
#[wasm_bindgen]
extern "C" {
fn alert(s: &str);
}
#[wasm_bindgen]
pub fn greet() {
alert("Hello, wasm-lib!");
}
打包 wasm
在 package.json 文件中添加这一行代码,然后我们就可以进行打包了。
项目根目录中运行
npm run build:wasm
如果在 build 的过程卡住了,或者报错了。可以先暂时把代码优化给关闭掉
在 wasm-lib 目录下的 Cargo.toml
配置文件中关掉 wasm-opt
打包完成后就能看到项目根目录中出现了一个 pkg 文件夹,这里面就是我们打包后的产物,前端可以进行调用我们用 Rust 编写的函数。
前端调用
我们有两种方式去调用 pkg 目录下的 wasm 函数:
一种是将 pkg 作为一个 npm 包发布
cd wasm-lib
# 该命令可以把这个库作为 npm 包发布到 npm 中,然后我们前端就正常的方式 npm install 就可以使用了
wasm-pack publish
另一种是先在本地进行引用,根目录下安装
npm install ./pkg
然后 package.json 的依赖中增加了我们的本地库:
{
"name": "react-wasm",
"version": "0.1.0",
"private": true,
"dependencies": {
"@testing-library/jest-dom": "^5.16.4",
"@testing-library/react": "^13.3.0",
"@testing-library/user-event": "^13.5.0",
"@types/jest": "^27.5.1",
"@types/node": "^16.11.36",
"@types/react": "^18.0.9",
"@types/react-dom": "^18.0.5",
"react": "^18.1.0",
"react-dom": "^18.1.0",
"react-scripts": "5.0.1",
"typescript": "^4.7.2",
"wasm-lib": "file:pkg", // ++++++++++++++++++++++++++++
"web-vitals": "^2.1.4"
},
// ...
}
接下来就去我们的 App.tsx 中调用 greet 方法:
import React, { useEffect } from "react";
import init, { greet } from "wasm-lib";
import logo from "./logo.svg";
import "./App.css";
function App() {
// +++++++++++++++++
useEffect(() => {
init().then(() => {
greet();
});
}, []);
return (
<div className="App">
...
</div>
);
}
export default App;
然后开始运行我们的 react 应用
npm run start
打开 localhost:3000 端口,可以看到我们调用 alert 方法成功咯~
使用 console.log
首先我们要安装一下 web-sys 这个包,在 Cargo.toml 中加入
[dependencies]
wasm-bindgen = "0.2.63"
web-sys = { version = "0.3.57", features = ['console'] } # ++++++++
在这里我们开启了 console 这个 feature, web-sys 还支持很多 feature,比如可以操作 DOM,调用前端原生 fetch API , 操作 Canvas , WebGL 等等等。
Rust:
mod utils;
use web_sys::console;
use wasm_bindgen::prelude::*;
#[cfg(feature = "wee_alloc")]
#[global_allocator]
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
#[wasm_bindgen]
pub fn test_log(val: JsValue) {
console::log_2(&"从JS端接受到数据".into(), &val);
}
JS:
import React, { useEffect } from "react";
import init, { test_log } from "wasm-lib";
import logo from "./logo.svg";
import "./App.css";
function App() {
useEffect(() => {
init().then(() => {
test_log({ a: 1, b: 2, c: 3 });
});
}, []);
return (
<div className="App">
...
</div>
);
}
export default App;
打印结果:
总结
像一些复杂的计算,我们可以使用 WebAssembly 来进行操作,比如上一篇。 WebAssembly 目前论开发效率来说个人感觉是不如原生 JS 的,稍微有点繁琐,目前感觉它的应用场景更多是在复杂性的计算领域,比如写游戏、音视频解析、加密解密、图片解析等这种需要复杂计算的。这里只是提供一个基础的小demo,让大家对这个东西有一个感性的了解,更深入的东西就得后面用到的时候再去了解了。
最后这里放上 官方参考文档
代办报建
本公司承接江浙沪报建代办施工许可证。
联系人:张经理,18321657689(微信同号)。
16条评论
我就搞不明白了,看帖回帖能死人么,居然只有我这么认真的在回帖!https://sdceda.com/lao/258385010/
楼上的很有激情啊!http://s5no.0168333.com
观点鲜明,立场坚定,作者态度明确。http://iu8gce.rgmmrzo.cn
刚看见一个妹子,很漂亮!http://odns.ja2c.com
楼上的心情不错啊!http://p6m6ct.zhengzhou-wutaishan.com
网站做得不错http://qpm2.ahtonch.com
好好学习楼主的帖子!http://j62r7.szoulanshi.com
网站做得不错http://37cskh.rq5.net
以后要跟楼主好好学习学习!http://9jc.dlz1.com
很有品味!http://piw5.d6pt.com
好好学习楼主的帖子!http://y90.yy0.com.cn
我只看看不说话。。。http://1ic2.hubcezkw.com
看帖不回帖的人就是耍流氓,我回复了!http://nthui.momei365.com
楼主就是我的榜样哦http://hiaqyx.tno-yotaka37upc.com
楼主很有激情啊!https://www.telegramuc.com/
关注一下!https://www.skypeis.com/
发表评论