Rust Is The Future of JavaScript Infrastructure 这篇文章讲述了 Rust 正在 JS 基建圈风行的事实:Webpack、Babel、Terser、Prettier、ESLint 这些前些年才流行起来的工具都已有了 Rust 代替计划,且性能有着 10~100 倍的晋升。
前端基建的迭代浪潮从未停歇,当下面这些工具给 Gulp、js-beautify、tslint 等工具盖上棺材盖时,基于 Rust 的新一代构建工具曾经轻轻将棺材盖悬挂在 webpack、babel、prettier、terser、eslint 它们头上,不晓得哪天就会盖上。
原文曾经有了不错的 中文翻译,值得一提的是,原文一些英文名词对应着特定中文解释,记录如下:
- low-level programming:
低级编程底层编程。 - ergonomics:
人体工程学人机工程学。 - opinionated:
自以为是,执著的开箱即用的。 - critical adoption:
批判性采纳技术选型临界点。
精读
本文不会介绍 Rust 如何应用,而会重点介绍原文提到的 Rust 工具链的一些根本用法,如果你感兴趣,能够立即替换现有的工具库!
swc
swc 是基于 Rust 开发的一系列编译、打包、压缩等工具,并且被广泛应用于更多更下层的 JS 基建,大大推动了 Rust 在 JS 基建的影响力,所以要第一个介绍。
swc 提供了一系列原子能力,涵盖构建与运行时:
@swc/cli
@swc/cli
能够同时构建 js 与 ts 文件:
const a = 1
npm i -D @swc/cli
npx swc ./main.ts
# output:
# Successfully compiled 1 file with swc.
# var a = 1;
具体性能与 babel 相似,都能够让浏览器反对先进语法或者 ts,只是 @swc/cli
比 babel 快了至多 20 倍。能够通过 .swcrc
文件做 自定义配置。
@swc/core
你能够利用 @swc/core
制作更下层的构建工具,所以它是 @swc/cli
的开发者调用版本。根本 API 来自官网开发者文档:
const swc = require("@swc/core");
swc
.transform("source code", {
// Some options cannot be specified in .swcrc
filename: "input.js",
sourceMaps: true,
// Input files are treated as module by default.
isModule: false,
// All options below can be configured via .swcrc
jsc: {
parser: {syntax: "ecmascript",},
transform: {},},
})
.then((output) => {
output.code; // transformed code
output.map; // source map (in string)
});
其实就是把 cli 调用改成了 node 调用。
@swc/wasm-web
@swc/wasm-web
能够在浏览器运行时调用 wsm 版的 swc,以失去更好的性能。上面是官网的例子:
import {useEffect, useState} from "react";
import initSwc, {transformSync} from "@swc/wasm-web";
export default function App() {const [initialized, setInitialized] = useState(false);
useEffect(() => {async function importAndRunSwcOnMount() {await initSwc();
setInitialized(true);
}
importAndRunSwcOnMount();}, []);
function compile() {if (!initialized) {return;}
const result = transformSync(`console.log('hello')`, {});
console.log(result);
}
return (
<div className="App">
<button onClick={compile}>Compile</button>
</div>
);
}
这个例子能够在浏览器运行时做相似 babel 的事件,无论是低代码平台还是在线 coding 平台都能够用它做运行时编译。
@swc/jest
@swc/jest
提供了 Rust 版本的 jest 实现,让 jest 跑得更快。应用形式也很简略,首先装置:
npm i @swc/jest
而后在 jest.config.js
配置文件中,将 ts 文件 compile 指向 @swc/jest
即可:
module.exports = {
transform: {"^.+\\.(t|j)sx?$": ["@swc/jest"],
},
};
swc-loader
swc-loader
是针对 webpack 的 loader 插件,代替 babel-loader
:
module: {
rules: [
{
test: /\.m?js$/,
exclude: /(node_modules)/,
use: {
// `.swcrc` can be used to configure swc
loader: "swc-loader"
}
}
];
}
swcpack
加强了多文件 bundle 成一个文件的性能,根本能够认为是 swc 版本的 webpack,当然性能也会比 swc-loader
计划有进一步晋升。
截至目前,该性能还在测试阶段,只有装置了 @swc/cli
就可应用,通过创立 spack.config.js
后执行 npx spack
即可运行,和 webpack 的应用形式一样。
Deno
Deno 的 linter、code formatter、文档生成器采纳 swc 构建,因而也算属于 Rust 营垒。
Deno 是一种新的 js/ts 运行时,所以咱们总喜爱与 node 进行类比。quickjs 也一样,这三个都是一种对 js 语言的运行器,作为开发者,需要永远是更好的性能、兼容性与生态,三者简直缺一不可,所以当下尽管不能齐全代替 Nodejs,但作为高性能代替计划是很香的,能够基于他们做一些跨端跨平台的解析器,比方 kraken 就是基于 quickjs + flutter 实现的一种高性能 web 渲染引擎,是 web 浏览器的代替计划,作为一种跨端计划。
esbuild
esbuild 是较早被宽泛应用的新一代 JS 基建,是 JS 打包与压缩工具。尽管采纳 Go 编写,但性能与 Rust 并驾齐驱,能够与 Rust 风潮放在一起看。
esbuild 目前有两个性能:编译和压缩,实践上别离可代替 babel 与 terser。
编译性能的根本用法:
require('esbuild').transformSync('let x: number = 1', {loader: 'ts',})
// 'let x = 1;\n'
压缩性能的根本用法:
require('esbuild').transformSync('fn = obj => { return obj.x}', {minify: true,})
// 'fn=n=>n.x;\n'
压缩性能比较稳定,适宜用在生产环境,而编译性能要思考兼容 webpack 的中央太多,在成熟稳固后才思考能在生产环境应用,目前其实曾经有不少新我的项目曾经在生产环境应用 esbuild 的编译性能了。
编译性能与 @swc
相似,但因为 Rust 反对编译到 wsm,所以 @swc
提供了 web 运行时编译能力,而 esbuild 目前还没有看到这种个性。
Rome
Rome 是 Babel 作者做的基于 Nodejs 的前端基建全家桶,蕴含但不限于 Babel, ESLint, webpack, Prettier, Jest。目前 打算应用 Rust 重构,尽管还没有实现,但咱们权且能够把 Rome 当作 Rust 的一员。
rome
是个全家桶 API,所以你只须要 yarn add rome
就实现了所有环境筹备工作。
rome bundle
打包我的项目。rome compile
编译单个文件。rome develop
调试我的项目。rome parse
解析文件形象语法树。rome analyzeDependencies
剖析依赖。
Rome 还将文件格式化与 Lint 合并为了 rome check
命令,并提供了敌对 UI 终端提醒。
其实我并不太看好 Rome,因为它累赘太重了,测试、编译、Lint、格式化、压缩、打包的琐碎事件太多,把每一块交给社区可能会做得更好,这不当初还在重构中,牵一发而动全身。
NAPI-RS
NAPI-RS 提供了高性能的 Rust 到 Node 的连接层,能够将 Rust 代码编译后成为 Node 可调用文件。上面是官网的例子:
#[js_function(1)]
fn fibonacci(ctx: CallContext) -> Result<JsNumber> {let n = ctx.get::<JsNumber>(0)?.try_into()?;
ctx.env.create_int64(fibonacci_native(n))
}
下面写了一个斐波那契数列函数,间接调用了 fibonacci_native
函数实现。为了让这个办法被 Node 调用,首先装置 CLI:npm i @napi-rs/cli
。
因为环境比拟麻烦,因而须要利用这个脚手架初始化一个工作台,咱们在外面写 Rust,而后再利用固定的脚本公布 npm 包。执行 napi new
创立一个我的项目,咱们发现入口文件必定是个 js,毕竟要被 node 援用,大略长这样(我创立了一个 myLib
包):
const {loadBinding} = require('@node-rs/helper')
/**
* __dirname means load native addon from current dir
* 'myLib' is the name of native addon
* the second arguments was decided by `napi.name` field in `package.json`
* the third arguments was decided by `name` field in `package.json`
* `loadBinding` helper will load `myLib.[PLATFORM].node` from `__dirname` first
* If failed to load addon, it will fallback to load from `myLib-[PLATFORM]`
*/
module.exports = loadBinding(__dirname, 'myLib', 'myLib')
所以 loadBinding 才是入口,同时我的项目文件夹下存在三个零碎环境包,别离供不同零碎环境调用:
@cool/core-darwin-x64
macOS x64 平台。@cool/core-win32-x64
Windows x64 平台。@cool/core-linux-arm64-gnu
Linux aarch64 平台。
@node-rs/helper
这个包的作用是疏导 node 执行预编译的二进制文件,loadBinding
函数会尝试加载以后平台辨认的二进制包。
将 src/lib.rs
的代码改成下面斐波那契数列的代码后,执行 npm run build
编译。留神在编译前须要装置 rust 开发环境,只有一行脚本即可装置,具体看 rustup.rs。而后把以后我的项目整体当作 node 包公布即可。
公布后,就能够在 node 代码中援用啦:
import {fibonacci} from 'myLib'
function hello() {let result = fibonacci(10000)
console.log(result)
return result
}
NAPI-RS 作为 Rust 与 Node 的桥梁,很好的解决了 Rust 渐进式替换现有 JS 工具链的问题。
Rust + WebAssembly
Rust + WebAssembly 阐明 Rust 具备编译到 wsm 的能力,尽管编译后代码性能会变得稍慢,但还是比 js 快很多,同时因为 wsm 的可移植性,让 Rust 也变得可移植了。
其实 Rust 反对编译到 WebAssembly 也不奇怪,因为原本 WebAssembly 的定位之一就是作为其余语言的指标编译产物,而后它自身反对跨平台,这样它就很好的实现了流传的使命。
WebAssembly 是一个基于栈的虚拟机 (stack machine),所以跨平台能力一流。
想要将 Rust 编译为 wsm,除了装置 Rust 开发环境外,还要装置 wasm-pack。
装置后编译只需执行 wasm-pack build
即可。更多用法能够查看 API 文档。
dprint
dprint 是用 rust 编写的 js/ts 格式化工具,并提供了 dprint-node 版本,能够间接作为 node 包,通过 npm 装置应用,从 源码 能够看到,应用 NAPI-RS 实现。
dprint-node
能够间接在 Node 中应用:
const dprint = require('dprint-node');
dprint.format(filePath, code, options);
参数文档。
Parcel
Parcel 严格来说算是上一代 JS 基建,它呈现在 Webpack 之后,Rust 风潮之前。不过因为它曾经采纳 SWC 重写,所以权且算是跟上了时尚。
总结
前端全家桶曾经有了一整套 Rust 实现,只是对于存量我的项目的编译准确性须要大量验证,咱们还须要工夫期待这些库的成熟度。
但毫无疑问的是,Rust 语言对 JS 基建反对曾经较为齐备了,剩下的只是工具层逻辑覆盖率的问题,都能够随工夫而解决。而用 Rust 语言重写后的逻辑带来的巨幅性能晋升将为社区注入微小生机,就像原文说的,前端社区能够为了微小性能晋升而引入 Rust 语言,即使这可能导致为社区奉献门槛的进步。
探讨地址是:精读《Rust 是 JS 基建的将来》· Issue #371 · dt-fe/weekly
如果你想参加探讨,请 点击这里,每周都有新的主题,周末或周一公布。前端精读 – 帮你筛选靠谱的内容。
关注 前端精读微信公众号
<img width=200 src=”https://img.alicdn.com/tfs/TB165W0MCzqK1RjSZFLXXcn2XXa-258-258.jpg”>
版权申明:自在转载 - 非商用 - 非衍生 - 放弃署名(创意共享 3.0 许可证)