电竞比分网-中国电竞赛事及体育赛事平台

分享

WebAssembly 入門

 新用戶0118F7lQ 2021-03-25

Wasm 是什么?

MDN 官方文檔[1]是這樣給出定義

WebAssembly(為了書寫方便,簡稱 Wasm)是一種新的編碼方式,可以在現(xiàn)代的網(wǎng)絡(luò)瀏覽器中運行 - 它是一種低級的類匯編語言,具有緊湊的二進制格式,可以接近原生的性能運行,并為諸如 C / C 等語言提供一個編譯目標,以便它們可以在 Web 上運行。它也被設(shè)計為可以與 JavaScript 共存,允許兩者一起工作。

對于網(wǎng)絡(luò)平臺而言,WebAssembly 具有巨大的意義——它提供了一條途徑,以使得以各種語言編寫的代碼都可以以接近原生的速度在 Web 中運行。在這種情況下,以前無法以此方式運行的客戶端軟件都將可以運行在 Web 中。

WebAssembly 被設(shè)計為可以和 JavaScript 一起協(xié)同工作——通過使用 WebAssembly 的 JavaScript API,你可以把 WebAssembly 模塊加載到一個 JavaScript 應(yīng)用中并且在兩者之間共享功能。這允許你在同一個應(yīng)用中利用 WebAssembly 的性能和威力以及 JavaScript 的表達力和靈活性,即使你可能并不知道如何編寫 WebAssembly 代碼。


在學(xué)習(xí)于航老師的《WebAssembly 入門課》開篇詞中,老師是這樣總結(jié)的“WebAssembly 是基于棧式虛擬機的虛擬二進制指令集(V-ISA),它被設(shè)計為高級編程語言的可移植編譯目標”。

帶著好奇心,開啟我們的 Wasm 學(xué)習(xí)之路,創(chuàng)建屬于自己的第一個 Wasm 應(yīng)用。

環(huán)境安裝

Rust[2]

一門賦予每個人
構(gòu)建可靠且高效軟件能力的語言。

  • 安裝
# macOS
curl --proto '=https' --tlsv1.2 -sSf https://sh. | sh

# 其他安裝方式
# https://forge./infra/other-installation-methods.html
  • 命令
# 版本更新
rustup update

# 查看版本
cargo --version

# 構(gòu)建項目
cargo build

# 運行項目
cargo run

# 測試項目
cargo test

# 為項目構(gòu)建文檔
cargo doc

# 將庫發(fā)布到 crates.io
cargo publish
# nightly rust
rustup toolchain install nightly

rustup toolchain list

rustup override set nightly

Node.js[3]

Node.js 是基于 Chrome 的 V8 JavaScript 引擎構(gòu)建的 JavaScript 運行時

wasm-pack[4]

用于構(gòu)建和使用您希望與 JavaScript,瀏覽器或 Node.js 互操作的Rust生成的 WebAssembly。

  • 安裝
# macOS
curl https://rustwasm./wasm-pack/installer/init.sh -sSf | sh

# 其他安裝方式
# https://rustwasm./wasm-pack/installer
  • 命令
# 創(chuàng)建
# https://rustwasm./docs/wasm-pack/commands/new.html
wasm-pack new <name> --template <template> --mode <normal|noinstall|force>

# 構(gòu)建
# https://rustwasm./docs/wasm-pack/commands/build.html
wasm-pack build
  [--out-dir <out>]
  [--out-name <name>]
  [--<dev|profiling|release>]
  [--target <bundler|nodejs|web|no-modules>]
  [--scope <scope>]
  [mode <normal|no-install>]

# 測試
# https://rustwasm./docs/wasm-pack/commands/test.html
wasm-pack test

# 發(fā)包
# https://rustwasm./docs/wasm-pack/commands/pack-and-publish.html
# npm pack
wasm-pack pack
# npm publish
wasm-pack publish

Vite[5]

下一代前端工具

vite-plugin-rsw[6]:vite 插件集成 wasm-pack,實現(xiàn)熱更新以及構(gòu)建
# vite項目中安裝
npm i -D vite-plugin-rsw
# or
yarn add -D vite-plugin-rsw

快速開始

  • 在原有vite項目中使用,只需安裝配置vite-plugin-rsw插件即可。
  • 新項目可以使用vite提供的@vitejs/app初始化項目,然后安裝配置vite-plugin-rsw。
  • 新項目推薦使用我的腳手架create-xc-app,會定期更新維護相關(guān)版本依賴。

create-xc-app[7]

?? 在幾秒鐘內(nèi)創(chuàng)建一個項目!維護了多種基于 vite,deno 等的前端項目模板。

npx create-xc-app my-wasm-app --template wasm-react

創(chuàng)建 Wasm 包

# 兩種方式
# name如果以@開頭創(chuàng)建npm組織包
# 會被轉(zhuǎn)成中劃線連接,需要手動修改文件夾名稱
wasm-pack new <name>
# or
# name可以是npm組織
# 例:cargo new --lib @rsw/hello
# 需要手動配置Cargo.toml
cargo new --lib <name>

圖片

項目結(jié)構(gòu)

# 推薦目錄結(jié)構(gòu)
[my-wasm-app] # 項目根路徑
|- [rust-crate] # npm包`rust-crate`
|    |- [pkg] # 生成wasm包的目錄
|    |- [src] # rust源代碼
|    | # 了解更多: https://doc./cargo/reference/cargo-targets.html
|    |- [target] # 項目依賴,類似于npm的`node_modules`
|    | # 了解更多: https://doc./cargo/reference/manifest.html
|    |- Cargo.toml # rust包管理清單
|    `- ...
|- [@rsw] # npm 組織包
|     |- [hello] # @rsw/crate, 目錄結(jié)構(gòu)同`rust-crate`
|     `- ...
|- [node_modules] # 前端的項目包依賴
|- [src] # 前端源代碼(可以是vue, react, 或其他)
# 了解更多: https://v/learn/the-package-json-guide
|- package.json # `npm`或`yarn`包管理清單
# 了解更多: https://v/config
|- vite.config.ts # vite配置文件
# 了解更多: https://www./docs/handbook/tsconfig-json.html
|- tsconfig.json # vite配置文件
` ...

乍一看,可能會覺得目錄有點復(fù)雜,其實它就是一個標準的基于vite前端項目,然后,在根路徑下添加我們需要構(gòu)建的 wasm 包(一個 rust crate 會對應(yīng)生成一個 wasm 包,可單獨發(fā)布到 npm 上)

項目配置

Step1: vite.config.ts

// 以react項目為例
import reactRefresh from '@vitejs/plugin-react-refresh';
import { defineConfig } from 'vite';
import ViteRsw from 'vite-plugin-rsw';

export default defineConfig({
  plugins: [
    reactRefresh(),
    // 更多配置:https://github.com/lencx/vite-plugin-rsw
    ViteRsw({
      // 包含生產(chǎn)和開發(fā)模式
      mode'release',
      crates: [
        // 包名稱,支持npm組織
        '@rsw/chasm'
      ]
    }),
  ],
})

Step2: rust-crate/Cargo.toml

# ...

[lib]
# https://doc./reference/linkage.html
crate-type = ['cdylib']
wasm-opt = false

# https://doc./cargo/reference/profiles.html
# dev | release | test | bench
[profile.release]
lto = true
opt-level = 's'

# https://doc./cargo/guide/dependencies.html
# 指定依賴項:https://doc./cargo/reference/specifying-dependencies.html
# 依賴包及版本管理,與npm的`package.json`類似
[dependencies]
wasm-bindgen = '0.2.69'

Step3: rust-crate/src/lib.rs

use wasm_bindgen::prelude::*;

// Import the `window.alert` function from the Web.
#[wasm_bindgen]
extern 'C' {
    fn alert(s: &str);
}

// Export a `greet` function from Rust to JavaScript, that alerts a hello message.
#[wasm_bindgen]
pub fn greet(name: &str) {
    alert(&format!('Hello, {}!', name));
}

Step4: src/App.tsx

import React, { useEffect } from 'react';
import init, { greet } from 'wasm-test';

import logo from './logo.svg';
import './App.css';

function App({
  useEffect(() => {
    // wasm初始化,在調(diào)用`wasm-test`包方法時
    // 必須先保證已經(jīng)進行過初始化,否則會報錯
    // 如果存在多個wasm包,則必須對每一個wasm包進行初始化
    init();
  }, [])

  return (
    <div className='App'>
      <header className='App-header'>
        <img src={logo} className='App-logo' alt='logo' />
        <p>Hello WebAssembly!</p>
        <p>Vite   Rust   React</p>
        <p>
          {/* 調(diào)用greet方法 */}
          <button onClick={() => greet('wasm')}>hi wasm</button>
        </p>
        <p>Edit <code>App.tsx</code> and save to test HMR updates.</p>
      </header>
    </div>

  )
}

export default App

完整代碼示例

源碼: https://github.com/lencx/learn-wasm

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多