How Vite achieved it by standing on the shoulders of giants

The so-called giants refer to the two build engines—Esbuild and Rollup—that are deeply used at the bottom of Vite. How important are these two build engines to Vite? In Vite's architecture, what roles do these two play? Next, let's disassemble Vite's dual-engine architecture and analyze the functions of Esbuild and Rollup in Vite.

1. Vite Architecture

Many people only use Esbuild in the development stage and Rollup in the production environment for Vite's dual-engine architecture. As everyone knows, the real architecture of Vite is far from that simple. The following is a Vite architecture diagram.

image.png

For Vite's dual-engine architecture, you can get a glimpse of it from the figure.

2. Esbuild

It must be admitted that Esbuild is indeed a powerful assistant for Vite's high performance. In many key construction stages, Vite has achieved excellent performance. If these stages are completed using traditional packagers/compilers, the development experience will be greatly reduced. So, what role does Esbuild play in Vite's build system?

2.1 Depend on pre-build

First, Esbuild will provide Bundle packaging tools during the dependency pre-build phase of the development phase.

image.png

Generally speaking, the size of node_modules dependencies can be hundreds of MB or even GB, which will far exceed the source code of the project. I believe everyone has a deep understanding. If these dependencies are directly used in Vite, there will be a series of problems. We have analyzed these problems in detail in the section of relying on pre-build. The main problems are the compatibility of the ESM format and the problem of massive requests, so I won’t repeat them here. All in all, for third-party dependencies, they need to be packaged and converted to ESM format before the application starts.

Vite 1.x uses Rollup to do this, but the performance of Esbuild is terrible. Vite 2.x decisively uses Esbuild to complete the pre-build of third-party dependencies. As for how strong the performance is, you can refer to Its performance comparison chart with traditional packaging tools.

image.png

Of course, Esbuild also has some disadvantages as a packaging tool.

  • Code that downgrades to ES5 is not supported. This means that the code will not work in low-end browsers.
  • Syntax such as const enum is not supported. This means that using these syntaxes alone will directly throw an error in esbuild.
  • It does not provide an interface for manipulating packaged products, and the ability to flexibly process packaged products like Rollup (such as renderChunk hooks) is completely absent in Esbuild.
  • Custom Code Splitting strategies are not supported. Both traditional Webpack and Rollup provide APIs for custom unpacking strategies, but Esbuild does not provide them, which reduces the flexibility of unpacking optimization.

Although Esbuild, as an emerging star project in the community, has so many limitations, it still does not prevent Vite from using it in the development stage to successfully start the project and obtain extreme performance improvements. Of course, the production environment is in consideration of stability. The more mature Rollup is used as a dependency packaging tool.

2.2 Single file compilation

In the dependency pre-build phase, Esbuild exists as a Bundler. For TS(X)/JS(X) single-file compilation, Vite also uses Esbuild for syntax translation, that is, uses Esbuild as a Transformer. You can find it in the Vite Plugin Pipeline section in the architecture diagram.

image.png
In other words, the ability of Esbuild to translate TS or JSX is provided by the Vite plug-in, and this Vite plug-in will be executed in both the development environment and the production environment. Therefore, we can draw the following conclusions.

Vite has already used Esbuild's Transformer capability in the production environment. Nevertheless, for low-end browser scenarios, Vite can still be syntax and Polyfill safe.

This part of the ability is used to replace the original functions of Babel or TSC, because both Babel and TSC have performance problems. The general perception of these two tools is: slow, too slow.

When Vite uses Esbuild to compile a single file, the improvement can be said to be quite large. Let's take a huge pure code file of more than 50 MB as an example to compare the compilation performance of Esbuild, Babel, TSC, and SWC.

image.png

It can be seen that although Esbuild Transformer can bring huge performance improvements, it also has its own limitations. The biggest limitation lies in the type checking problem in TS. This is because Esbuild does not implement the type system of TS, and only erases type-related codes when compiling TS (or TSX) files, and is temporarily unable to implement type checking.

Therefore, in the quick start section, I want everyone to pay attention to the construction script of the initialization project. Before the vite build, the tsc command will be executed first, that is, the TS official compiler is used to perform type checking.

Of course, to solve the type problem, I recommend you to use the TS editor plug-in. Problems can be exposed and resolved early in the development stage, without waiting until the project is about to be packaged and launched.

2.3 Code Compression

Since version 2.6, Vite has used Esbuild by default to compress code in the production environment, including JS code and CSS code. The figure below demonstrates that the Esbuild compressor is integrated into Rollup's packaging process in the form of a plug-in in the production environment.

image.png

So why does Vite use Esbuild as the default compression tool in the production environment? Because the compression efficiency is too high. The traditional way is to use Terser, a JS-developed compressor, to implement it as a Plugin in Webpack or Rollup to complete the work of compression and obfuscation after code packaging. But Terser is actually very slow, mainly for two reasons.

  • Compression involves a lot of AST operations, and in the traditional construction process, AST cannot be shared among various tools. For example, Terser cannot share the same AST with Babel, resulting in many repeated parsing processes.
  • JS itself is an interpretive + JIT (just-in-time compilation) language, and its performance is far inferior to that of a native language like Golang for compressing such CPU-intensive work.

Therefore, Esbuild, which shares AST from beginning to end and Minifier written in native language, can outperform traditional tools dozens of times in terms of performance. As an example, we can look at the compression performance test project of the actual large library (echarts) below:

image.png

To compress a library with a size of 3.2 MB, Terser takes 8798 ms, while Esbuild only takes 361 ms. The compression efficiency is 20 to 30 times higher than that of Terser, and the volume of the product is almost not degraded, so Vite decisively built it as the default Compression scheme.

In general, Vite uses Esbuild as its own performance weapon, and makes full use of Esbuild's capabilities in various vertical directions (Bundler, Transformer, Minifier), which provides a favorable guarantee for Vite's high performance.

3. Rollup

Rollup is no less important than Esbuild in Vite. It is not only the core tool used by Vite for production environment packaging, but also directly determines the design of Vite's plug-in mechanism. So, what exactly does Vite do based on Rollup?

3.1 Production Environment Bundle

Although ESM has been natively supported by many browsers, it is not enough to make the production environment completely no-bundle, and there will be network performance problems. In order to achieve excellent product performance in the production environment, Vite chooses to use Rollup packaging in the production environment by default, and expands and optimizes Rollup based on its mature packaging capabilities, mainly including three aspects:

  • CSS code splitting. If some CSS codes are introduced into an asynchronous module, Vite will automatically extract these CSS codes and generate separate files to improve the cache reuse rate of online products.
  • Automatic preloading. Vite will automatically generate preload tags for the dependencies of the entry chunk, such as:
<head>
  <!-- 省略其它内容 -->
  <!-- 入口 chunk -->
  <script type="module" crossorigin src="/assets/index.250e0340.js"></script>
  <!--  自动预加载入口 chunk 所依赖的 chunk-->
  <link rel="modulepreload" href="/assets/vendor.293dca09.js">
</head>

This proper preloading method will allow the browser to download resources in advance and optimize page performance.

  • Asynchronous Chunk loading optimization. In the asynchronously imported Chunk, there are usually some common modules, such as the existing two asynchronously imported Chunks: A and B, and both have a common dependency C, as shown in the following figure:

image.png

Under normal circumstances, after Rollup is packaged, it will first request A, and then the browser decides to request and load C during the process of loading A. However, after Vite optimizes, it will automatically preload C when requesting A. By optimizing Rollup product dependencies The loading method saves unnecessary network overhead.

3.2 Compatible plug-in mechanism

Regardless of the development stage or the production environment, Vite is rooted in Rollup's plug-in mechanism and ecology, as shown in the architecture diagram below.

image.png

In the development stage, Vite borrowed the idea of ​​WMR and implemented a Plugin Container to simulate Rollup to schedule the execution logic of each Vite plugin. The Vite plugin writing method is fully compatible with Rollup, so all Vite plugins are passed to the Vite plugin in the production environment. There is no problem entering Rollup.

Conversely, the Rollup plugin may not be fully compatible with Vite. However, there are still many Rollup plugins that can be directly reused in Vite. You can view all Vite-compatible Rollup plugins through this site: vite-rollup-plugins.patak.dev/ .

Uncle Wolf mentioned several major categories of modern front-end frameworks in "On the Advancement of Front-Ends Based on Framework Positioning" . Vite belongs to the type that people have their own advantages, because similar tools have Snowpack before, and after Vite was born, it was completed as a no- The Dev Server capabilities of bundle building tools (such as HMR) are indeed better than existing tools. But more importantly, Vite has an inherent advantage over Snowpack in terms of community ecology.

Snowpack has developed a plug-in mechanism, which is similar to Rollup's Hook mechanism. It can be seen that it borrows from Rollup's plug-in mechanism, but it is not compatible with any existing packaging tools. If you need to package, you can only call the API of other packaging tools, and it does not provide packaging capabilities.

Vite's approach is rooted in Rollup's ecology from beginning to end, designing a plug-in mechanism that is very consistent with Rollup, and Rollup, as a very mature packaging solution, has been iterated for more than six years since its birth. The volume has reached hundreds of millions of times, and the product quality and stability have undergone large-scale verification. To some extent, this kind of thinking rooted in existing mature tools can also dispel or reduce the inner doubts of users, which is more conducive to the promotion and development of tools.

Four. Summary

First of all, Esbuild is a performance tool for building. Vite uses its Bundler function to pre-build dependencies, uses its Transformer ability to translate TS and JSX files, and uses its compression ability to compress JS and CSS codes.

Next, I introduced the relationship between Vite and Rollup. In Vite, both the plug-in mechanism and the underlying packaging method are implemented based on Rollup. It can be said that Vite is a scenario-based in-depth extension of Rollup, extending Rollup from the traditional JS library packaging scenario to complete Web application packaging. , and then combined with the core competitiveness of no-bundle in the development stage, it created its own unique technology brand.

Therefore, you can see the importance of dual engines for Vite. If you want to learn and apply Vite in depth, it is very necessary to master the basic usage and plug-in development of Esbuild and Rollup. In the following explanations, we will enter into the learning of the twin engines together.

Guess you like

Origin blog.csdn.net/xiangzhihong8/article/details/130664124