用rust构建前端工具链

fagaJanuary 23, 2023About 3 min

用rust构建前端工具链

rustgo这些语言来写一些前端的工具链其实已经火了有一段时间了, 像esbuild, swc, lightingcss, turbo等等, 因此我于去年十月份开始嘴上说要学rust, 并于今年一月份学完rust基础语法...其实一直没有什么动力学rust, 主要是因为没啥灵感, 学了也不知道做啥, 我一直也不太喜欢重复造轮子, 但自身也很少有灵光乍现的时候, 所以也一直就卡在那里。 虽然我没咋学rust, 但好在平常有关注rust的生态, 也算是做了一些积累。

灵感来源

灵感最开始来自于一条推特, 应该是bun的作者发了一个截图, 是在命令行打印了bun的代码量相关信息的, 接着就找到了loc, 不过loc貌似不咋更新了, 接着就找到了类似的项目tokeiopen in new window, 这既是一个二进制项目也是一个库项目, 因此我们可以通过它暴露出来的函数, 再结合napi-rs, 就可以为node提供使用tokeiapi, 这就是napi-tokeiopen in new window准备做的事情了。

napi-rs

在用rust写前端工具链的时候, napi-rsopen in new window想必是绕不开的话题了, 所以这里先简单讲讲napi-rs

napi-rs是一个rust版的Node-APIopen in new window, 它提供了一些api(具体来说是宏), 让我们能够用rust来写js。

以下是官网首页的例子:

// lib.rs
use napi_derive::napi;
 
#[napi]
fn fibonacci(n: u32) -> u32 {
  match n {
    1 | 2 => 1,
    _ => fibonacci(n - 1) + fibonacci(n - 2),
  }
}

通过napi-rs, 可以生成一个js文件index.js以及相应的.d.ts

// main.mjs
import { fibonacci } from './index.js'
 
// output: 5
console.log(fibonacci(5))

并且是esm, cjs兼容的

// main.cjs
const { fibonacci } = require('./index')
 
// output: 5
console.log(fibonacci(5))

上面介绍的如何定义一个函数, 当然还能定义数组, 对象, 字符串等等。

接下来看一下napi-rs生成的js文件 大概的思路就是根据不同的操作系统, 不同的CPU架构引用不同的二进制模块就是里面的.node文件。在你发布由napi-rs创建的包的时候, 同时也会发布不同操作系统不同CPU架构的二进制模块, 你可以在package.json中的optionalDependencies字段看到

代码实现

napi-tokei只是一个对tokei的简单封装, 因此只需要很少的代码量就可以完成。

#![deny(clippy::all)]
use napi_derive::napi;
use tokei::{Config, Languages};

// js Object
#[napi(object)]
pub struct Langs {
  pub lang: String,
  pub lines: u32,
  pub code: u32,
  pub comments: u32,
  pub blanks: u32,
}

// export function tokei(include: Array<string>, exclude: Array<string>): Array<Langs>
#[napi]
pub fn tokei(include: Vec<String>, exclude: Vec<&str>) -> Vec<Langs> {
  let config = Config::default();
  let mut languages = Languages::new();
  languages.get_statistics(&include, &exclude, &config);
  let mut vec: Vec<Langs> = vec![];

  for item in languages.into_iter() {
    let lang = Langs {
      lang: item.0.to_string(),
      lines: (item.1.lines() as u32),
      code: (item.1.code as u32),
      comments: (item.1.comments as u32),
      blanks: (item.1.blanks as u32),
    };
    vec.push(lang)
  }
  vec
}
Last update:
Contributors: faga
Comments
  • Latest
  • Oldest
  • Hottest
Powered by Waline v2.13.0