美文网首页
Rust Web 开发指北

Rust Web 开发指北

作者: zhoukeke | 来源:发表于2022-12-05 16:23 被阅读0次

    欢迎点击 Rust Web 开发指北 进行阅读或评论。

    尝试使用 rust 开发一个简单的 web 页面。使用 yew 框架,在 Chrome 运行 WebAssembly,并能在 IE 11 上降级到 JS 运行。

    环境准备

    • rust、rustup、cargo
    • cago-generate, more detail
      • $ cargo install cargo-generate
    • wasm-pack, more detail
      • $curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
    • wasm2js, more detail
      • $ brew install binaryen
      • 速度不行的话,自行切换至 中科大 或 清北 的镜像,推荐中科大

    初始化

    参考 Rust and WebAssembly 的 HelloWorld 样例,使用以下命令进行初始化:

    $ cargo generate --git https://github.com/rustwasm/wasm-pack-template

    输入名称:hello-rust-wasm

    初始化完成后,目录结构如下:

    .
    ├── Cargo.toml
    ├── LICENSE_APACHE
    ├── LICENSE_MIT
    ├── README.md
    ├── src
    │   ├── lib.rs
    │   └── utils.rs
    └── tests
        └── web.rs
    
    

    编辑页面

    由于 rust 初始化时,是按模块初始化的,所以主要代码写在 lib.rs中(正常初始化为入口为 main.rs),再由外部 JS 引入之后,启动执行。
    为了更贴近实际开发,我们使用 yew 框架进行开发,整体代码参考如下:

    • 添加 yew 依赖
    
    [dependencies]
    
    yew = { version = "0.20.0", features = ["csr"] }
    
    • 页面内容
    mod utils;
    
    use wasm_bindgen::prelude::*;
    use yew::prelude::*;
    
    #[wasm_bindgen]
    extern {
        fn alert(s: &str);
    
        #[wasm_bindgen(js_namespace = console)]
        fn log(s: &str);
    }
    
    #[function_component]
    fn App() -> Html {
    
        html! {
            <div>
                <h1>{"Hello Rust"}</h1>
            </div>
        }
    }
    
    #[wasm_bindgen]
    pub fn start() {
        log("Hello Rust!");
        yew::Renderer::<App>::new().render();
    }
    
    • 测试构建,成功之后,会于根路径产生 ./pkg/*.js./pkg/*.wasm
     $ wasm-pack build
    [INFO]: 🎯  Checking for the Wasm target...
    [INFO]: 🌀  Compiling to Wasm...
    [INFO]: ⬇️  Installing wasm-bindgen...
    [INFO]: found wasm-opt at "/opt/homebrew/bin/wasm-opt"
    [INFO]: Optimizing wasm binaries with `wasm-opt`...
    [INFO]: Optional fields missing from Cargo.toml: xxx
    [INFO]: ✨   Done in 1.46s
    [INFO]: 📦   Your wasm pkg is ready to publish at xxx
    $ tree ./pkg
    ./pkg
    ├── README.md
    ├── hello_rust_wasm.d.ts
    ├── hello_rust_wasm.js
    ├── hello_rust_wasm_bg.js
    ├── hello_rust_wasm_bg.wasm
    ├── hello_rust_wasm_bg.wasm.d.ts
    └── package.json
    
    0 directories, 7 files
    

    渲染页面

    参考 Rust and WebAssembly ,使用以下命令在项目下初始化 web 应用。

    #  初始化
    $ npm init wasm-app www
    
    $ cd www
    
    # 使用上层我们刚刚构建的 pkg 产物作为我们的业务依赖
    # ⚠️ 此处阿里内部同学不要使用 tnpm 等,必须使用 npm,否则指向会有问题
    $ npm install hello-rust-wasm@file:../pkg -S
    

    修改 wwww/index.js文件

    import * as wasm from "hello-rust-wasm";
    
    wasm.start();
    

    启动测试并预览:

    $ npm start
    $ open http://localhost:8080
    
    image

    WASM 兼容 IE11

    参考 wasm2js,对于不支持 WebAssembly 的浏览器,可以通过 wasm2js 工具将 WebAssembly 编译到 JS 进行执行。

    # 临时编译文件
    $ wasm2js ./pkg/hello_rust_wasm_bg.wasm -o ./pkg/fallback-temp.wasm.js
    $ cp ./pkg/hello_rust_wasm_bg.js ./pkg/fallback-temp.js
    
    # 修改入口和引用
    $ sed 's/hello_rust_wasm_bg/fallback/g' pkg/fallback-temp.wasm.js > pkg/fallback.wasm.js
    $ sed 's/hello_rust_wasm_bg.wasm/fallback.wasm.js/' pkg/fallback-temp.js > pkg/fallback.js
    
    # 于是,可以得到 fallback 在 IE11 的降级逻辑代码
    $ tree ./pkg
    ./pkg
    ├── README.md
    ├── fallback-temp.js
    ├── fallback-temp.wasm.js
    ├── fallback.js
    ├── fallback.wasm.js
    ....
    └── package.json
    

    渲染兼容 IE 11

    添加依赖

    $ cd www
    $ npm i @babel/core @babel/preset-env babel-loader@8 -D
    $ npm i core-js text-encoding -S
    

    添加 fallback.js

    import * as wasm from "hello-rust-wasm/fallback.js";
    
    wasm.start();
    

    添加 polyfill.js,也可以先使用 https://polyfill.io/v3/url-builder/ 来做简单的 polyfill 测试。

    import "core-js/modules/es.promise.js";
    import "core-js/modules/es.array.fill.js";
    import "core-js/modules/es.math.imul.js";
    import "core-js/modules/es.math.clz32.js";
    import TextEncodingPolyfill from 'text-encoding';
    
    if (typeof window['TextEncoder'] !== 'function') {
      window['TextEncoder'] = TextEncodingPolyfill.TextEncoder;
      window['TextDecoder'] = TextEncodingPolyfill.TextDecoder;
    }
    

    修改 HTML 模板,添加 polyfill 依赖,并使其适配 fallback 的逻辑

    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="utf-8">
        <title>Hello wasm-pack!</title>
      </head>
      <body>
        <script src="./polyfill.js"></script>
        <noscript>This page contains webassembly and javascript content, please enable javascript in your browser.</noscript>
        <script>
          if (typeof WebAssembly === 'object' && !/wasm=0/.test(location.href)) {
            document.write('<script src="./bootstrap.js"><\/script>');
          } else {
            document.write('<script src="./fallback.js"><\/script>');
          }
        </script>
      </body>
    </html>
    

    修改 webpack 打包逻辑

    const CopyWebpackPlugin = require('copy-webpack-plugin');
    const path = require('path');
    
    module.exports = {
      entry: {
        bootstrap: './bootstrap.js',
        fallback: './fallback.js',
        polyfill: './polyfill.js',
      },
      output: {
        path: path.resolve(__dirname, 'dist'),
      },
      module: {
        rules: [
          {
            test: /\.m?js$/,
            use: {
              loader: 'babel-loader',
              options: {
                presets: [
                  [
                    '@babel/preset-env',
                    {
                      targets: { chrome: '50', ie: '11' },
                    },
                  ],
                ],
              },
            },
          },
        ],
      },
      plugins: [new CopyWebpackPlugin(['index.html'])]
    };
    
    

    为了方便上述的命令一次性执行,可以添加一个 build.sh文件

    #!/bin/bash
    
    # build WebAssembly
    rm -rf ./pkg
    wasm-pack build --release
    
    # temp files
    wasm2js ./pkg/hello_rust_wasm_bg.wasm -o ./pkg/fallback-temp.wasm.js
    cp ./pkg/hello_rust_wasm_bg.js ./pkg/fallback-temp.js
    
    sed 's/hello_rust_wasm_bg/fallback/g' pkg/fallback-temp.wasm.js > pkg/fallback.wasm.js
    sed 's/hello_rust_wasm_bg.wasm/fallback.wasm.js/' pkg/fallback-temp.js > pkg/fallback.js
    
    # build web app
    cd www
    rm -rf ./dist
    npm run build
    

    最终效果

    在线预览地址:https://unpkg.com/hello-rust-wasm@0.2.0/dist/index.html

    Chrome 下使用 wasm 运行(当然,你可以判断一下环境,来优化一下 polyfill 的加载)

    image

    IE 11 下降级到 JS 运行

    image

    小结

    WebAssembly 可以在业务场景下进行小规模试验,目前初步具备整体的生态工具链,包括 rust 打包、WebAssembly 打包、以及 wasm2js 的降级兼容处理等等。

    Rust 作为前端领域最具未来投资价值的语言,将前端的上限做了极大的提升。也希望通过本文,能引起更多前端同学的关注和尝试,引导前端做更多的 Rust 实践。通过实践,一定需要通过实践(落地一个业务场景)来更加强力地驱动 rust 的落地(包括但不限于 操作系统、WebApp、WAVM for non-Browser、WebContainer for Desktop-App、WebVM for Serverless 等等),并实现自身更广阔的职业发展空间。

    参考

    相关文章

      网友评论

          本文标题:Rust Web 开发指北

          本文链接:https://www.haomeiwen.com/subject/yslifdtx.html