preface

For those of you who are interested in the underlying implementation of “Vite”, I think you should know that it uses “esbuild” to convert.ts, JSX, and.js code. Of course, the use of “esbuild” before “Vite” was “Snowpack”. However, compared to the huge community that “Vite” has, Snowpack is obviously getting less attention.

The core of “Vite” is the browser-native ES Module. However, compared with traditional packaging tools and development tools, it has made many changes, the adoption of “esbuild” to support.ts, JSX,.js code transformation is one of them.

What is esbuild, and how to use it?

1 What is esbuild

Esbuild is a “JavaScript” Bundler packaging and compression tool that packages “JavaScript” and “TypeScript” code to run on the web.

Features currently supported by “EsBuild” :

  • loader
  • The compression
  • packaging
  • Tree shaking
  • The Source map generated
  • Port JSX and newer JS syntax to ES6
  • .

Here, we have listed a few common concerns, as for the rest, interested students can refer to the official documents to understand.

Features not currently supported for “JavaScript” syntax conversions are:

  • Top-level await
  • async await
  • BigInt
  • Hashbang syntax

Note that syntax that does not support conversion is “output as is”.

2 Compare existing packaging tools

The authors of esBuild “benchmarked” against similar tools currently available. The end result:

For these benchmarks, EsBuild was at least 100 times faster than the other JavaScript packagers I tested.

100 times, almost flying… The reason why “esbuild” is fast is explained in two aspects:

2.1 Official Explanation

  • It is written in the “Go” language, which compiles to native code.
  • Parsing, generating final files, and generating source maps are all completely parallel.
  • Without expensive data conversion, all operations can be done in a few steps.
  • The library is the first rule when writing code to improve compilation speed and avoid unnecessary memory allocation as much as possible.

2.2 Linguistic interpretation

  • At present, similar tools, the underlying implementation is based on “JavaScript”, which is limited to itself is an interpreted language, does not make full use of the CPU.
  • “Chrome V8” engine although the “JavaScript” operation has been optimized, the introduction of “JIT” mechanism, but part of the code implementation of machine code and “ESbuild” all implementation of machine code form, performance gap cannot be made up.

Of course, the language level is only a point in the official explanation of the expansion, other explanations have time to analyze the source code implementation after the explanation.

3 EsBuild API details

Although “esbuild” has long been open source and used, but the official documentation is only a brief introduction to how to use, and the API introduction is not enough, readers are advised to read the source code definition.

Esbuild provides four functions: Transform, Build, buildSync, and Service. Let’s take a look at them from a source definition perspective.

3.1 the transform

The transform can be used to transform.js,.tsx, ts, etc., and then output the.js file as the old syntax, which provides two arguments:

  • The first argument (mandatory, string) refers to the code to be converted (module content).
  • The second argument (optional) refers to the options required for the transformation, such as the source file pathsourcefile, need to loadloader, includingloaderDefinition:
type Loader = 'js' | 'jsx' | 'ts' | 'tsx' | 'css' | 'json' | 'text' | 'base64' | 'file' | 'dataurl' | 'binary';
Copy the code

The Transform returns a Promise, and the TransformResult is an object that contains the transformed old JS code, the sourceMap mapping, and a warning:

interface TransformResult {
  js: string;
  jsSourceMap: string;
  warnings: Message[];
}
Copy the code

3.2 build

Build implements the transform capability, which translates code, and it also compresses the transformed code and generates.js files to the specified output directory. Build provides only one argument (object) to specify the import file, output file, loader, and other options to convert:

interface BuildOptions extends CommonOptions {
bundle? :boolean;
splitting? :boolean;
outfile? :string;
metafile? :string;
outdir? :string; platform? : Platform;color? :boolean; external? :string[]; loader? : { [ext:string]: Loader }; resolveExtensions? :string[]; mainFields? :string[]; write? :boolean; tsconfig? :string; outExtension? : { [ext:string] :string };  entryPoints? :string[]; stdin? : StdinOptions;} Copy the code

The build call outputs BuildResult, which contains the generated outputFiles and warnings:

interface BuildResult {
  warnings: Message[];
outputFiles? : OutputFile[];}
Copy the code

Note, however, that outputFiles only output if write is false, which is a Uint8Array.

3.3 buildSync

BuidSync, as the name suggests, is a synchronous build compared to build, i.e. with build we need to implement synchronous calls with async await, while with buildSync we can implement synchronous calls directly.

3.4 the Service

The Service was created to solve the problem of creating a child to complete each call to the API. If there are multiple calls to the API, there will be a performance waste, which is explained in the documentation.

Therefore, using a Service to convert or package code creates a long-term child process for sharing, avoiding performance waste. In “Vite”, Service is used to convert.ts,.js,.jsx code.

The Service definition:

interface Service {
  build(options: BuildOptions): Promise<BuildResult>;
transform(input: string, options? : TransformOptions):Promise<TransformResult>;
  stop(): void;
}
Copy the code

As you can see, the essence of a Service encapsulates the build, Transform, and stop functions, but instead of calling them individually, the underlying implementation of a Service is a “persistent, shareable” child process.

In practice, however, instead of using Service directly, we create an instance of Service using startService:

const {
  startService,
  build,
} = require("esbuild")
const service = await startService()
 try {  const res = await service.build({  entryPoints: ["./src/main.js"]. write: false  })  console.log(res) } finally {  service.stop() } Copy the code

Also, be aware that when you use stop, it terminates the child process, which means that any Promise that is pending at this point will also be terminated.

Implement a small and beautiful Bundler package

After a brief introduction to “esbuild”, let’s implement a small and beautiful Bunder package:

1. Initialize the project and install “esbuild” :

mkdir esbuild-bundler; cd esbuild-bundler; npm init -y; npm i esbuild
Copy the code

2. Directory Structure:

| - SRC| - main. Js # project entry documents| -- - index. Js # bundler implementation core fileCopy the code

3. The index. Js:

(async() = > {  const {
    startService,
    build,
  } = require("esbuild")
 const service = await startService()   try {  const res = await service.build({  entryPoints: ["./src/main.js"]. outfile: './dist/main.js'. minify: true. bundle: true. })  } finally {  service.stop()  } }) ()Copy the code

4. Run the Node Index to experience a lightning-fast Bundler package!

Write in the last

Presumably after reading this article, you should establish a basic understanding of “esbuild”. And, the source code is only based on the “Go” implementation of the underlying ability, and the real underlying implementation or have to see “Go” is how to achieve, because of the departure from the well-known front-end, so do not introduce. So, in the next article, I will explain how to use esbuild to implement.ts, JSX,.js parsing in the source code design of “Vite”, and how we can customize plugin to implement some code conversion. Finally, if there is any improper expression in the article, you are welcome to make an Issue.

Review previous articles

Deep reading Vue3 source | component creation process

What depth interpretation Vue3 source | built-in component teleport “lot”?

Depth interpretation Vue3 source | the compile and runtime patch process

❤️ Love triple punch

Through reading, if you think you have something to gain, you can love the triple punch!!

Ask the person at the front — Wu Liu (” wechat public account: Code Center “)