9

Rust Is is at The Future of JavaScript Infrastructure This article describes the fact that Rust is popular JS infrastructure circle: Webpack , Babel , terser , prettier , ESLint these pop up only a few years ago The tools already have Rust alternatives, and the performance has been improved by 10 to 100 times.

The iterative wave of front-end infrastructure has never stopped. When these tools cover Gulp, js-beautify, tslint and other tools, the new generation of construction tools based on Rust has quietly suspended the coffin cover on webpack, babel, prettier, and terser. , Eslint on their heads, I don't know when they will be covered.

Original've got a good Chinese translation , it is worth mentioning that some of the original English nouns corresponding to specific Chinese interpretation, recorded as follows:

  • Programming-Level Low: lower programmer level programming.
  • ergonomics: ergonomics ergonomics.
  • opinionated: self-righteous, stubborn out of the box.
  • critical adoption: critical adoption technology selection critical point.

intensive reading

This article will not introduce how to use Rust, but will focus on some basic usages of the Rust toolchain mentioned in the original text. If you are interested, you can immediately replace the existing tool library!

swc

swc is a series of tools such as compilation, packaging, compression, etc. developed based on Rust, and it is widely used in more and higher-level JS infrastructure, which greatly promotes the influence of Rust in JS infrastructure, so it is the first introduction.

swc provides a series of atomic capabilities, covering build and runtime:

@swc/cli

@swc/cli can build js and ts files at the same time:

const a = 1
npm i -D @swc/cli
npx swc ./main.ts

# output:
# Successfully compiled 1 file with swc.
# var a = 1;

The specific function is similar to that of babel, which allows the browser to support advanced syntax or ts, but @swc/cli is at least 20 times faster than babel. You can do custom configuration .swcrc file.

@swc/core

You can use @swc/core make higher-level build tools, so it is the developer-call version @swc/cli The basic API comes from the official website developer documentation:

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)
  });

In fact, the cli call is changed to a node call.

@swc/wasm-web

@swc/wasm-web can call the swc of the wsm version when the browser is running to get better performance. The following is an official example:

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>
  );
}

This example can do things similar to babel when the browser is running, and it can be used for runtime compilation whether it is a low-code platform or an online coding platform.

@swc/jest

@swc/jest provides a Rust version of jest implementation to make jest run faster. The usage is also very simple, first install:

npm i @swc/jest

Then in the jest.config.js configuration file, point the ts file compile to @swc/jest :

module.exports = {
  transform: {
    "^.+\\.(t|j)sx?$": ["@swc/jest"],
  },
};

swc-loader

swc-loader is a loader plugin for webpack, instead of babel-loader :

module: {
  rules: [
    {
      test: /\.m?js$/,
      exclude: /(node_modules)/,
      use: {
        // `.swcrc` can be used to configure swc
        loader: "swc-loader"
      }
    }
  ];
}

swcpack

Enhance the function of multi-file bundle into one file, basically it can be considered as a swc version of webpack, of course, the performance will be further improved swc-loader

Up to now, this feature is still in the testing stage, as long as @swc/cli installed, it can be used. npx spack spack.config.js then executing 0619b34d1a8b86, which is the same as using webpack.

Deno

Deno 's linter, code formatter, and document generator are built with swc, so they also belong to the Rust camp.

Deno is a new js/ts runtime, so we always like to compare with node. quickjs is the same, these three are a kind of js language runner, as a developer, the demand is always better performance, compatibility and ecology, the three are almost indispensable, so although they cannot be completely replaced at the moment Nodejs, but it is very fragrant as a high-performance alternative. You can some cross-end and cross-platform parsers based on them. For example, 1619b34d1a8bd9 kraken is a high-performance web rendering engine based on quickjs + flutter, which is a web browser. Alternative, as a cross-terminal solution.

esbuild

esbuild is a new generation of JS infrastructure that has been widely used earlier and is a JS packaging and compression tool. Although it is written in Go, its performance is comparable to Rust, and it can be viewed together with the Rust trend.

esbuild currently has two functions: compilation and compression, which can theoretically replace babel and terser respectively.

Basic usage of the compilation function:

require('esbuild').transformSync('let x: number = 1', {
  loader: 'ts',
})

// 'let x = 1;\n'

Basic usage of compression function:

require('esbuild').transformSync('fn = obj => { return obj.x }', {
  minify: true,
})

// 'fn=n=>n.x;\n'

The compression function is relatively stable and suitable for use in the production environment, and the compilation function should consider too many places compatible with webpack. It can be used in the production environment after it is mature and stable. In fact, many new projects have already used esbuild in the production environment. Compile function now.

The compilation function is @swc , but because Rust supports compiling to wsm, @swc provides web runtime compilation capabilities, and esbuild has not yet seen this feature.

Rome

Rome is a Nodejs-based front-end infrastructure family bucket made by the Babel author, including but not limited to Babel, ESLint, webpack, Prettier, Jest. Currently plans to use Rust to refactor . Although it has not yet been implemented, we can consider Rome as a member of Rust.

rome is a family bucket API, so you only need yarn add rome to complete all environmental preparations.

  • rome bundle packaged project.
  • rome compile compiles a single file.
  • rome develop debugging project.
  • rome parse parses the file abstract syntax tree.
  • rome analyzeDependencies analysis dependent.

Rome also merged file formatting and Lint into rome check command, and provided friendly UI terminal prompt .

In fact, I am not very optimistic about Rome, because it is too burdensome. There are too many trivial things such as testing, compiling, Lint, formatting, compression, and packaging. It may be better to give each piece to the community. This is not even now. In the restructuring, the whole body is affected by one move.

NAPI-RS

NAPI-RS provides a high-performance connection layer from Rust to Node, which can compile Rust code into a Node callable file. The following is an example of the official website:

#[js_function(1)]
fn fibonacci(ctx: CallContext) -> Result<JsNumber> {
  let n = ctx.get::<JsNumber>(0)?.try_into()?;
  ctx.env.create_int64(fibonacci_native(n))
}

A Fibonacci sequence function is written above, which is implemented fibonacci_native In order for this method to be called by Node, first install the CLI: npm i @napi-rs/cli .

Due to the troublesome environment, we need to use this scaffolding to initialize a workbench, we write Rust in it, and then use a fixed script to publish the npm package. Executing napi new create a project, we found that the entry file must be a js, after all, it has to be referenced by node, which myLib like this (I created a 0619b34d1a8e10 package):

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')

So loadBinding is the entry point. At the same time, there are three system environment packages under the project folder, which can be called by different system environments:

  • @cool/core-darwin-x64 macOS x64 platform.
  • @cool/core-win32-x64 Windows x64 platform.
  • @cool/core-linux-arm64-gnu Linux aarch64 platform.

@node-rs/helper package is to guide node to execute the pre-compiled binary file. The loadBinding function will try to load the binary package recognized by the current platform.

After src/lib.rs the code of the above Fibonacci sequence, execute npm run build compile. Note that you need to install the rust development environment before compiling. You rustup.rs Then release the current project as a node package as a whole.

After publishing, you can reference it in the node code:

import { fibonacci } from 'myLib'

function hello() {
  let result = fibonacci(10000)
  console.log(result)
  return result
}

As a bridge between Rust and Node, NAPI-RS solves the problem of Rust gradually replacing the existing JS toolchain.

Rust + WebAssembly

Rust + WebAssembly shows that Rust has the ability to compile to wsm. Although the code performance after compilation will become slightly slower, it is still much faster than js. At the same time, due to the portability of wsm, Rust has also become portable.

In fact, it is not surprising that Rust supports compilation to WebAssembly, because one of the original positioning of WebAssembly is to be a target compilation product of other languages, and then it supports cross-platform, so it can well complete the mission of dissemination.

WebAssembly is a stack-based virtual machine ( stack machine ), so it has first-class cross-platform capabilities.

If you want to compile Rust to wsm, in addition to installing the Rust development environment, you must also install wasm-pack .

After installation, you only need to execute wasm-pack build to compile. For more usage, please API document .

dprint

dprint, is prepared rust js / ts formatting tools, and provides dprint, node- version can be used as node packets by npm installation, from source can be seen, use NAPI the RS- accomplish.

dprint-node can be used directly in Node:

const dprint = require('dprint-node');
dprint.format(filePath, code, options);

parameter file .

Parcel

Parcel strictly speaking the previous generation of JS infrastructure. It appeared after Webpack and before the Rust trend. However, since it has with SWC in , it can be regarded as keeping up with the fashion for the time being.

Summarize

The front-end family bucket already has a complete set of Rust implementations, but the compilation accuracy of stock projects needs a lot of verification, and we still need time to wait for the maturity of these libraries.

But there is no doubt that the Rust language has relatively complete support for JS infrastructure, and the rest is only the problem of the logic coverage of the tool layer, which can be solved over time. The huge performance improvement brought by the logic rewritten in the Rust language will inject great vitality into the community. As the original text said, the front-end community can introduce the Rust language for the huge performance improvement, even if this may lead to the threshold of contribution to the community improve.

The discussion address is: "Rust is the future of JS infrastructure" · Issue #371 · dt-fe/weekly

If you want to participate in the discussion, please click here , a new theme every week, weekend or Monday. Front-end intensive reading-to help you filter reliable content.

Follow front-end intensive reading WeChat public

Copyright notice: Freely reprinted-non-commercial-non-derivative-keep the signature ( Creative Commons 3.0 License )

黄子毅
7k 声望9.5k 粉丝