当前位置:嗨网首页>书籍在线阅读

08-wasm-bindgen

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

15.4.1 wasm-bindgen

wasm-bindgen是由GitHub上的rust-wasm团队开发的一款软件包。它支持Rust代码调用 JavaScript 代码,反之亦然。基于该软件包,已经构建了很多其他更高级的程序库,例如web-sys和js-sys软件包。

JavaScript本身就是欧洲计算机制造商协会(European Computer Manufacturers Association,ECMA)标准定义的内容,但相关标准没有规定它在Web上的工作方式。JavaScript可以支持多种宿主,Web恰好是其中之一。web-sys软件包允许访问Web上的所有JavaScript API,即DOM API,例如Window、Navigator及EventListener等。js-sys软件包提供ECMA标准规范中指定的所有基本的JavaScript对象,即函数、对象及数字等。

由于WebAssembly仅支持数字类型,因此wasm-bindgen软件包生成适配元素以便用户能够在JavaScript中使用原生的Rust类型。例如,Rust中的结构体表示为JavaScript端的对象,而Promise对象可以在Rust端作为Future访问。它通过在函数定义上使用#[wasm-bindgen]属性来完成所有这些操作。

为了探索wasm-bindgen以及它如何与JavaScript交互,我们将构建一些实用的程序。接下来将构建一个在线markdown编辑器应用程序,它允许用户编写markdown并预览经过渲染后的HTML页面。不过在正式开始之前,需要安装为我们生成适配元素的wasm-bindgen-cli工具,从而允许我们方便地使用其中公开的Rust函数。我们可以通过运行如下命令安装它:

cargo install wasm-bindgen-cli

接下来,让我们通过运行cargo new livemd命令创建一个项目,相关的Cargo.toml文件内容如下所示:

[package]
name = "livemd"
version = "0.1.0"
authors = ["Rahul Sharma <[email protected]>"]
edition = "2018"
[lib]
crate-type = ["cdylib"]
[dependencies]
wasm-bindgen = "0.2.29"
comrak = "0.4.0"

我们将软件包命名为livemd,程序库是cdylib类型,并且公开了一个C语言接口,因为WebAssembly接收一个目标宽泛的动态C程序库接口,大多数语言都可以编译到该接口。接下来将在我们的项目根目录下创建一个run.sh脚本,以便构建和运行我们的项目,并在每次使用cargo-watch检测到代码发生任何更改时重新运行它。以下是run.sh文件的内容:

#!/bin/sh
set -ex
cargo build --target wasm32-unknown-unknown
wasm-bindgen target/wasm32-unknown-unknown/debug/livemd.wasm --out-dir app
cd app
yarn install
yarn run serve

接下来是lib.rs中的markdown转换代码的实现,完整内容如下所示:

// livemd/src/lib.rs
use wasm_bindgen::prelude::*;
use comrak::{markdown_to_html, ComrakOptions};
#[wasm_bindgen]
pub fn parse(source: &str) -> String {
    markdown_to_html(source, &ComrakOptions::default())
}

我们的livemd软件包公开了一个名为parse的函数,它从网页上的textarea标签中获取markdown文本(尚未创建),并通过调用comrak软件包中的markdown_to_html函数返回经过编译的HTML字符串。如你所见,parse函数采用了#[wasm_bindgen]属性进行注释。此属性为各种底层转换生成代码,并且需要将此函数公开给JavaScript。使用此方法,我们不必关心parse函数接收何种类型的字符串。JavaScript中的字符串与Rust中的字符串有所不同。#[wasm_bindgen]属性负责处理这种差异,以及在接收&str 类型字符串之前从JavaScript端转换字符串的底层细节。在撰写本书时,有些类型是wasm-bindgen无法转换的,例如引用或带有生命周期注释的类型定义。

然后我们需要为该软件包生成wasm文件。但在此之前,我们先对应用程序进行一些设置。在同一目录下,我们将创建一个名为app/的目录,并通过运行yarn init命令来初始化项目:

171.png yarn init会创建我们的package.json文件。除了普通的字段之外,我们还会指定脚本(scripts)和开发依赖项(dev-dependencies):

{
  "name": "livemd",
  "version": "1.0.0",
  "description": "A live markdown editor",
  "main": "index.js",
  "license": "MIT",
  "scripts": {
    "build": "webpack",
    "serve": "webpack-dev-server"
  },
  "devDependencies": {
    "html-webpack-plugin": "^3.2.0",
    "webpack": "^4.28.3",
    "webpack-cli": "^3.2.0",
    "webpack-dev-server": "^3.1.0"
  }
}

我们将使用webpack来启动开发环境下的Web服务器。webpack是一个模块捆绑器。它会接收多个JavaScript源文件,并将它们打包到一个文件中,从而缩小其体积以便在Web上使用。要让webpack能够捆绑JavaScript和wasm生成的代码,我们将在名为web.pack. config.js的文件中创建一个webpack配置文件:

// livemd/app/webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
    entry: './index.js',
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'index.js',
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: "index.html"
        })
    ],
    mode: 'development'
};

接下来在同一app/目录中,我们将创建3个文件。

  • index.html——这包含应用程序的UI:
<!--livemd/app/index.html-->
<!DOCTYPE html>
<html>
<head>
    <title>Livemd: Realtime markdown editor</title>
    <link
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap
.min.css" rel="stylesheet">
    <link href="https://fonts.googleapis.com/css?family=Aleo"
rel="stylesheet">
    <link href="styles.css" rel="stylesheet">
</head>
<body class="container-fluid">
    <section class="row">
        <textarea class="col-md-6 container" id="editor">_Write
your text here.._</textarea>
        <div class="col-md-6 container" id="preview"></div>
    </section>
    <script src="index.js" async defer></script>
</body>
</html>

我们已经声明了一个带有编辑器ID的HTML元素