Loading...
墨滴

超级英雄吉姆

2021/03/03  阅读:29  主题:默认主题

rust-wasm

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常用命令

如果你对RustReact没有相关的知识储备,请先参照官方文档。

  • Rust: https://www.rust-lang.org/

  • React: https://reactjs.org/

环境准备:

注: 教程的环境为 mac 系统。

我们需要npmcargo。用来构建 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 className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <a
          className="App-link"
          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 className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <a
          className="App-link"
          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 className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
    </div>
  );
}

export default App;

*恭喜你~~~~!!!,我们成功的调用了在 rust 应用中定义的 hello 方法,并把它集成在 react 应用中了*

附加:使用 cargo-generate 创建 Rust-Wasm 应用

如果你阅读到此处还是不能够理解整个流程中我们做了什么的话,建议你重新阅读或者思考一下整个流程。

接下来的内容会需要你对以上内容有一定理解之后阅读起来会比较轻松。接下来的内容,是在上文中的扩展。

  1. 安装 cargo-generate
cargo install cargo-generate

如果没有 openssl 则使用

cargo install cargo-generate --features vendored-openssl

用例:cargo generate --git https://github.com/githubusername/mytemplate.git

  1. 安装wasm-pack
cargo install wasm-pack
  1. 安装 wasm-bindgen
cargo install wasm-bindgen-cli --force
  1. 生成 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) ✗

  1. build
wasm-pack build
  1. 本地可以使用 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

超级英雄吉姆

2021/03/03  阅读:29  主题:默认主题

作者介绍

超级英雄吉姆