2024年底了,还不快速了解一下Rust在前端领域的发展?

1,760 阅读18分钟

前言

Rust 作为最近几年连续霸榜爆火的语言,虽然也知道其在前端基建领域逐渐得到了广泛应用,但同时又因其学习难度等因素,让很多人望而却步。

所以,在此整理了一下Rust在前端领域的一些基本场景与应用,以及相关框架的一些入门使用,但是并不会包含太多的Rust语法,目的就是为了前端小伙伴儿们能够快速入门了解这门语言,以及其在前端领域是如何发挥作用的。

写作不易,如果这篇文章对您有所帮助,欢迎 关注♥️ + 点赞👍 鼓励一下作者,感恩~

Rust发展历程

2006年,软件开发者Graydon HoareMozilla工作期间,开始了Rust作为一个个人项目。根据他在麻省理工技术评论的一次采访,Rust的灵感来自于Hoare公寓楼里一个坏掉的电梯。电梯操作系统的软件崩溃了,Hoare意识到这类问题通常源于程序如何使用内存的问题

通常,这些类型设备的软件是用CC++编写的,但这些语言需要大量的内存管理,可能导致系统崩溃的错误。因此,有一种说法,在内存不安全的语言中,高达70%的安全漏洞都是由于内存安全问题造成的。因此 Hoare着手研究如何创建一种既紧凑又无内存错误的编程语言

Mozilla 于2009年开始赞助这个项目,并且在2010年首次公开。也在同一年,其编译器源代码开始由原本的 OCaml 语言转移到用 Rust 语言,进行自我编译工作,称作“rustc”,并于2011年实际完成。这个可自我编译的编译器在架构上采用了 LLVM 作为它的后端。

第一个有版本号的Rust编译器于2012年1月发布。Rust 1.0是第一个稳定版本,于2015年5月15日发布。

2021年2月8日,AWS、华为、Google、微软以及 Mozilla 宣布成立Rust基金会,并承诺在两年时间里每年投入不少于 100 万美元的预算,以用于 Rust 项目的开发、维护和推广

根据Rust 最新官方新闻,谷歌日前宣布向 Rust 基金会捐款 100 万美元,这笔资金将用于改善 C++ 与 Rust 互操作性。谷歌当前正在使用 Rust 语言重写在 Linux 核心之外的 Android 关键安全组件,从而进一步减少安全漏洞。而在 Android 13 中,就已经有约 21%的新原生代码使用 Rust 语言开发

Rust 特点

Rust语言作为一种更底层的编程语言,作用类似于c与c++等底层语言,设计时注重安全性并发性性能,并且力求提供高效的内存管理,而不牺牲开发者的生产力,与之对应的就是Javascript,Go,Python等高级语言或者应用语言。

以下是Rust的一些关键特点:

  • 内存安全:无需手动进行垃圾回收,同时,也不需要像Js这种有自动垃圾回收机制,这样可以进一步提高性能。其核心是 使用 所有权(ownership)来管理内存。每个值有一个所有者,且每个值只能有一个所有者。所有权的转移、借用和生命周期等规则确保了内存的自动管理而不依赖垃圾回收。
  • 零成本抽象:Rust 提供的高级抽象(如迭代器、闭包、泛型等)通常不会引入额外的性能开销。编译器会对这些抽象进行优化,确保在最终生成的机器码中没有额外的运行时开销。
  • 并发性:Rust 通过其所有权模型来确保并发编程的安全。Rust 在编译时会捕捉到潜在的并发错误,例如数据竞争(data races)和并发访问的冲突。同时,供了异步编程支持(async/await),可以在不阻塞线程的情况下进行并发操作,从而提升应用程序的响应性和性能。

这里从前端Javascript的角度对比说一下Rust在内存管理这块的特点:

  • C语言:性能高,但是开发者需要手动管理内存,极容易出现内存错误,例如:微软估计,其代码中70%的bug都是由于内存错误引起的。
  • Javascript:有自动垃圾回收(GC)机制,不需要用户手动管理,会在数据不再被引用时自动回收。但是由于引入了垃圾回收器,性能也会变低。
  • Rust:结合了两者的优势,既不需要手动管理内存,同时又可以保证性能,

总结:Rust 是从性能角度来说,是一门接近 C/C++ 的低级语言,但同时又提供了现代语言的高级特性,因此又可以做很多应用层的开发,比如:前端页面,后端服务等。

注意:以上特点描述过程中,可能包含很多Rust中的专业概念,我们可以暂时先不需要理解,后期慢慢学习.

Web Assembly

在认识Rust之前,从前端的角度来说,我们要首先了解Web Assembly,因此他们Rust之所以在前端领域能够发挥这么大的作用,其核心就是依赖 Web Assembly

认识WASM

关于 Web Assembly(WASM),我们需要知道以下几点:

  • 首先,WebAssembly是一门新的编程语言,它于2019年12月5日正式成为与HTML、CSS以及JavaScript 并列的web领域第四类编程语言
  • 其次,WebAssembly是"汇编语言"而不是高级语言,程序员不直接编写WebAssembly代码,而是通过特殊的编译器将高级语言转换成WebAssembly代码
  • 再次,WebAssembly是预处理过后的二进制格式,它实际是一个IR(Intermediate Representation)!类似Java的ByteCode或者.Net的MSIL/CIL。
  • 最后,WebAssembly是web上的语言,这意味着主流的浏览器可以读取并且执行它。

最后简单总结,Web Assembly 作为一个语言比较特殊,不需要用户手动编写,而是通过编写更高级语言,例如:rust,然后通过“特殊的编译器”生成WebAssembly二进制代码,最终WebAssembly代码再被一个嵌入在浏览器里的"特殊的虚拟机"执行。这就是WebAssembly的全部工作过程。

为什么需要WebAssembly?

在web领域,我们已经有了JavaScript这样利器,但美中不足的是JavaScript的性能不佳,即使可以通过第二章里提到的各种编译优化来解决一部分问题,但在类似图形图像处理、3D游戏、AR、VR这些高性能应用的场景下,我们似乎任然需要一个更好的选择。 那就是 WebAssembly。

快”是相对的,目前我们可以认为在运行速度上:原生C/C++代码 > WebAssembly > asm.js > 原生JavaScript

其中,有几点要了解:

  • asm.js 为什么比原生Javascript快呢?asm.js的实现去掉大部分的自动GC机制,然后改成了强类型语言,编译器能够更大程度地进行优化。
  • WebAssembly与JavaScript运行性能详细对比:整体上我认为可以描述为“很快,但是不够快”。也就是说,我们期望它比JavaScript快非常多,快个10倍或者8倍,但实际上只能快一点点,大概也就是不到2倍左右

在浏览器端运行 WebAssembly代码

我们通过一段简单的代码,可以快速体验一下,如何在浏览器端直接运行WebAssembly代码。

  1. 打开任意的浏览器,例如Chrome。

  2. 按F12,启动开发者工具。

  3. 找到Console页签,复制这一段代码,回车运行。

    WebAssembly.compile(new Uint8Array(`
      00 61 73 6d  01 00 00 00  01 0c 02 60  02 7f 7f 01
      7f 60 01 7f  01 7f 03 03  02 00 01 07  10 02 03 61
      64 64 00 00  06 73 71 75  61 72 65 00  01 0a 13 02
      08 00 20 00  20 01 6a 0f  0b 08 00 20  00 20 00 6c
      0f 0b`.trim().split(/[\s\r\n]+/g).map(str => parseInt(str, 16))
    )).then(module => {
      const instance = new WebAssembly.Instance(module)
      const { add, square } = instance.exportsconsole.log('2 + 4 =', add(2, 4))
      console.log('3^2 =', square(3))
      console.log('(2 + 5)^2 =', square(add(2 + 5)))
    ​
    })
    

    这里我们是通过直接手写二进制机器码的方式生成了一段wasm代码,并使用了WebAssembly.compile接口来进行编译,最后调用了wasm实现的add和square函数。如果顺利的话,你的浏览器会编译这段WebAssembly代码并调用执行,输出对应的计算结果,具体如下图所示:

    image-20241114190129932

Web端应用场景

最后,WebAssembly在服务端也会很多的应用场景,具体可以参考上面的文档。

以上内容参考自文档:zhuanlan.zhihu.com/p/620767652,如需进一步了解,该文档中对于 WebAssembly 会有更详细的介绍。

Rust vs Javascript

由于前端对于Javascript及其生态是最熟悉的,因此,这里我们通过对比的形式,可以快速理解Rust中常见工具的作用及应用场景。

Javascript/NodejsRust
官网Javascript官网rust官网
类型系统动态弱类型语言静态强类型语言
包管理工具Npm,YarnCargo
包管理仓库Npm registryCrates.io
构建工具Webpack/ViteCargo:Rust内置构建工具
依赖管理package.json/package-lock.jsonCargo.toml/Cargo.lock
编译器Js没有传统意义的编译器,类似Ts中的tscrustc:Rust内置编译器
版本管理工具nvm:Nodejs版本管理工具rustup:Rust内置版本工具
  • 在实际开发中,我们只需要使用cargo即可,

    • cargo new 目录:初始化rust项目
    • cargo run:运行rust代码
    • cargo build:编译生成目标文件。
    • cargo install: 安装rust依赖。
    • cargo uninstall: 卸载rust依赖。

Rust 与 WebAssembly

上面我们提到,WebAssembly 不需要我们手动编写,实际开发中,就需要一门源语言,我们只需要编写源语言,然后借助相应的编译器将其转换成WebAssembly即可。

而Rust就是一门非常适合的源语言,Rust 生态天然支持 WebAssembly,并且有专门的生态去跟踪和优化WebAssembly

那在实际开发中,如何快速使用Rust进行开发,并且编译生成WebAssembly呢?这里介绍两个工具:

  • rust-webpack:通过 Webpack 来打包 Rust 编译的 WebAssembly 文件,更侧重于将 Rust 集成到现有的 Webpack 构建流程中,适用于已经使用 Webpack 的项目。
  • wasm-pack:更专注于从 Rust 到 WebAssembly 的编译过程,并提供便捷的 JavaScript API 和 NPM 发布功能,适用于 Rust 开发者构建 WebAssembly 模块并与前端 JavaScript 进行交互。

Wasm-Pack脚手架的使用可以参考文档:rustwasm.wasmdev.cn/docs/wasm-p…

Rust 应用场景

前端构建工具

前端构建工具有许多,而且层出不穷,各自有不同的特点、优势以及应用场景。

按照类型,我们主要从 编译工具打包工具 两个方面去分析对比一下:

  • 编译工具:这类工具主要专注于将源代码转成目标代码,比如:处理Javascript的兼容性和语法转换。
  • 打包工具:这些工具不仅处理代码转换,还负责打包和优化项目资源。

编译工具

编译工具传统方案基于 Rust 实现
Javascript编译器Babel:基于Javascript实现Swc
Css预编译器Sass/Less:基于Dart实现Sass-rs
Postcsspostcss-rs:比 Postcss 快 20x 倍
Stylus
CSS-in-JS
代码格式化Prettierdprint:比 Prettier 快 30x 倍

打包工具

传统方案基于 Rust 实现
JS编译器和打包工具RollupRolldown
Esbuild(go语言实现)
ParcelParcel2
综合构建工具Vite
WebpackTurbopack
构建工具全家桶Rome : 前端构建全家桶
biome:Rome的继任者
  • Parcel: 特色主打零配置并且开箱即用,Parcel2 使用rust进行了重写,性能进一步提升。
  • Vite 在生产环境中使用 Rollup 进行打包构建,开发环境中,使用 Esbuild 进行快速构建和热更新代码等。这样会导致开发与生产环境构建行为差异,以及源代码被不同的工具重复解析,导致大量可以避免的开销。
  • Rolldown:是由Vite团队实现,Rust编写,目标是是为Vite设计,提供超级快的构建速度,从而替换Rollup与Esbuild。
  • Turbopack: 由 Webpack 的创建者 Tobias Koppers 和 Next.js 团队使用 Rust 编写,开发的一个前端模块化的工具,按作者构想 Turbopack 的目标是取代 Webpack。官方宣称 TurboPack 的速度比 Vite 快 10 倍,比 Webpack 快 700 倍。
  • Rome: 是一个新的 JavaScript/TypeScript 工具链,旨在统一和简化前端开发中的多个任务。它的设计目标是成为一个全面的工具集,整合 构建工具代码格式化代码检查linting打包转译 等功能,并且这些功能全部用Rust重写,而不是集成现有的插件。
  • Rome已于23年9月份,facebook宣布已停止维护,后续衍生了一个新的产品,Biome,要做的事情和Rome类似。

前端页面开发

基于 Javascript 实现基于 Rust 实现
React / VueYew: 整个 Web 应用都基于 Rust 开发, Leptos
传统构建方案:wasm-pack:直接将你的 Rust 代码打包成 npm 包 wasm-bindgen:促进 WebAssembly 模块和 JavaScript 之间的高级交互,通常与 wasm-pack 配合使用 cargo-web:集成 Rust WebAssembly 编译和前端开发支持的工具
推荐构建方案Trunk:一个专为 Rust 和 WebAssembly 项目设计的构建工具
  • 使用Rust进行前端开发的核心是通过Rust编译成WASM在浏览器端等运行,因此,实际开发语言也是使用Rust,不像其他使用Rust实现的构建工具,底层实现是Rust,工具的使用者依然是使用JS,TS等前端语言。
  • 传统构建方案:在没有Trunk之前,我们通常是借助:wasm-pack,`wasm-bindgen,等工具来完成将Rust代码 编译为 WebAssembly,然后借助carg-web完成前端静态资源的打包优化,以及构建本地开发环境等。
  • Trunk:一个专为 Rust 和 WebAssembly 项目设计的构建工具,它简化了 WebAssembly 项目的构建和打包过程,自动化了将 Rust 代码编译为 WebAssembly、将静态资源(如 HTML、CSS、图片等)打包和优化,并提供开发者友好的工作流。

桌面应用开发

基于 Nodejs 实现基于 Rust 实现
桌面实现方案ElectronTauri
编辑器VscodeZed
  • Electron和Tauri底层是用了不同的语言,但是对于框架的使用者而言,依然是是用JS,TS等前端语言。
  • Tauri 是目前最流行的 Electron 替代方案,通过使用 Rust 和 Webview2 成功解决了 Electron 的包体积大和内存占用高的问题,因为它不需要 Chromium 浏览器,而是使用轻量级的 Webview 来显示 Web 内容。因此,Tauri非常适合那些需要轻量、高效、跨平台的桌面应用程序,尤其适用于对应用体积和性能有较高要求的开发者。
  • Atom 团队也是看到了 Tauri 的成功,才决定基于 Rust 去做 Zed 编辑器

服务器端开发

基于 c++ 实现基于 Rust 实现
底层语言NodejsDeno
服务端框架ExpressjsRocket Axum
Node拓展用 C++ 开发的 Node.js 扩展Napi-rs:Rust 和 N-API 开发高性能 Node.js 拓展

其他场景

  • 区块链

    • 由于其高性能、内存安全和并发性,Rust 在区块链开发中变得非常流行。Rust 是构建 PolkadotSubstrate 等区块链协议的首选语言。
    • Rust 可以用于编写区块链的核心引擎、共识算法、智能合约等部分。
  • 游戏开发

    • Rust 在游戏开发中的应用逐渐增多,尤其是在性能要求极高的底层开发部分。例如,游戏引擎 Amethyst 就是用 Rust 编写的。
  • 高性能计算(HPC)

    • 由于 Rust 可以直接操作底层硬件,提供精细的内存控制,它也适用于高性能计算领域,例如金融建模、科学计算、模拟等。

总结:

从上面我们可以看到Rust应用场景非常广泛,下到操作系统,再到命令行工具,再到web开发,再到服务器端开发,似乎无所不能,其实总结起来主要两点:

  • Rust 本质上是类似 C与C++ 等底层语言,可以做很多c和c++的工作,并且实现起来更简单更安全。
  • 同时Rust 又可以像Go 等相关高级语言一样,支持高并发,做很多web与服务器端的工作。
  • 同时又可以借助WASM,做很多浏览器端的开发。

Rust - helloworld

首先,我们通过一个helloworld例子,感受一下rust的基本使用。

  1. 安装rust,配置环境

    curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
    
  1. 初始化一个rust项目

    cargo new helloworld
    

    image-20241104143743358

  2. 使用cargo build编译项目,生成一个target目录,如下:

    image-20241104144108794

    默认通过cargo build编译生成的文件会包含调试信息,除此之外,我们可以通过cargo build -- release去生成文件体积更小,性能更好的二进制。

  3. 执行main.rs文件,输出 Hello world!

    ./target/debug/helloworld
    

    也可以直接使用命令:

    cargo run  // 本质上也是运行./target/debug/helloworld 这个二进制文件
    

    就会输出Hello world!

Trunk - helloworld

我们可以借助Yew,Trunk等工具,实现使用rust进行web页面的开发。依然是通过demo案例来体会。

  1. 配置环境

    // 1. 安装rust
    // 2. 安装Trunk:类似于webpack,只不过它是基于rust创建wasm应用程序的构建工具, 更多细节可以参考官网https://trunkrs.dev/
    cargo install --locked trunk 
    
  1. 创建一个rust项目

    cargo new trunk-helloworld
    
  2. 在根目录下创建 index.html,index.scss 等,也可以创建其他资源文件。

    // index.html
    <html>
      <head>
        <link data-trunk rel="scss" href="./index.scss" />
      </head>
      <body></body>
    </html>
    
    // index.scss
    html {
      body {
        background-color: green;
      }
    }
    

    注意:Trunk构建时内部默认支持 dart-sass, 因此我们才可以在根目录直接使用scss文件。

4 . 执行trunk build,会在根目录下生成dist文件,里面包含相关打包生成的前端文件,如下:

image-20241114172605073

我们可以看到在 index.html文件中,通过<script type="module"> 引入了相关.wasm文件。 这也是rust进行前端开发的核心思路:将rust代码编译成wasm文件,然后再通过<script type="module">在html中引入wasm模块。

  1. 执行trunk serve,开启本地服务,然后就可以通过localhost:8080 访问页面啦

    image-20241114172946737

Yew - helloworld

Trunk的作用是 将rust代码编译成wasm 的过程进行了简化,但是具体如何用rust代码写前端页面呢?这就要靠**Ye w 框架了,可以把类比于Vue React等前端框架,它也提供了组件化的开发模型,支持声明式 UI,响应式编程,并允许开发者使用 Rust 的类型系统和性能优势来构建浏览器应用。**

  1. 初始化 rust 项目

    cargo new yew-helloworld
    
  2. 安装 yew 依赖

    cargo add yew --features "csr"
    

    yew不会默认指定特性,我们做的是 web 端开发,所以指定开启csr。其他的还包括 ssr - 服务端渲染;hydration - 混合开发,支持客户端、服务端渲染。

  3. 在根目录下创建 index.html,index.scss 等,也可以创建其他资源文件。

    // index.html
    <html>
      <head>
        <link data-trunk rel="scss" href="./index.scss" />
      </head>
      <body></body>
    </html>
    // index.scss
    html {
      body {
        background-color: green;
      }
    }
    
  4. 修改 src/main.rs 文件

    use yew::prelude::*;
    ​
    #[function_component(App)]
    fn app() -> Html {
        html! {
            <h1>{"hello, trunk/yew!"}</h1>
        }
    }
    ​
    fn main() {
        yew::Renderer::<App>::new().render();
    }
    
  5. 执行trunk serve --open 开启本地服务,通过localhost:8080 即可访问,效果如下:

    image-20241114182118981

常见问题

  1. cargo install 如果遇到超时或者443问题,一般是由于默认rust镜像仓库是在国外,比较慢,需要修改成国内的仓库地址。

    image-20241113152244121

    具体解决方式:cd ~/.cargo 目录下,新建config文件,配置如下内容:

    [source.crates-io]
    registry = "https://github.com/rust-lang/crates.io-index"
    replace-with = 'ustc'
    [source.ustc]
    registry = "https://mirrors.ustc.edu.cn/crates.io-index"
    #registry = "https://mirrors.tuna.tsinghua.edu.cn/git/crates.io-index.git"
    [http]
    check-revoke = false
    

参考文档

总结

通过这篇文章,相信大家对Rust,以及Rust在前端领域的应用有了一个初步的体会与认识:

  • Rust依靠其高性能的优势,在前端基建领域正逐渐形成全面的替换,我们大家以前常用的构建工具,在Rust领域都有其相应的对标工具,不过目前传统构建工具其生态丰富,应用量依然巨大。
  • Rust借助WASM,可以实现直接用Rust去开发前端页面,但是传统Vue,React 开发方式依然占据主导地位,Rust更多是搭配Wasm,实现一些性能要求比较高的前端页面。
  • Rust在服务器端,桌面端等其他领域都有广泛应用。