preface

In 5 minutes, you can quickly read the vite packaging process. In the source code analysis article, we introduce the transformation of vite packaging code through esbuild. Esbuild does not support IE11. As a result, there are often issues on Vite GitHub asking how to support IE11, such as the following issue:


Under this issue, several Vite contributors explained several solutions to support IE11:

Undefin: I haven’t tested this, it seems you need to add Babel /polyfill and umD in rollupOptions.

Add the following code to your viet.config. js, note that you install core-js, @babel/core, @babel/preset-env, @babel/ Runtime.

import babel  from '@rollup/plugin-babel';

export default {
  rollupInputOptions: {
    plugins: [
 babel({  presets: [[  "@babel/preset-env". {  "corejs": 2. "useBuiltIns": "usage". "targets": {  "ie": "11"  }  }  ]]  }) ]. } } Copy the code

Aleclarson: I made a plugin called Viet-plugin-Legacy to simply support the old legacy. Please wait for #874 merge!

In fact, compared with the solution of these two giants, the general idea is the same, are around Babel to achieve code transformation, patch operation. However, if it’s true, it’s the viet-plugin-legacy of aleclarson. Also, the PR mentioned above has now been merged, which means we can use the Viet-plugin-Legacy plug-in!

It is important to note that the main implementation of Viet-plugin-Legacy is based on the configureBuild Hook, which came in vite 1.0.0-RC.8 and later.

So, back to today, I’m going to give you a look inside configureBuild

1 configureBuild Hook

The configureBuild Hook will be called before the build function does anything. When the build configuration is initialized, it is deeply copied, making it easier for the configureBuild Hook to check and mutate (without having to check all the undefined bits). Rollup’s input options are exposed to configureBuild by default, allowing vite plugins to better manipulate the build process and meaning more powerful Vite plugins are possible.

The general process of vite packaging is as follows:


The configureBuild Hook is called at the end of the packaging “build file to disk” phase.

2 Use configureBuild Hook to customize a plug-in

First, let’s look at an example plug-in that uses configureBuild Hook:

Define the plugin myplugin.ts:

export default() :Plugin= > ({
  configureBuild(viteConfig) {
.
    return async build => {
. }  } }) Copy the code

Here we define an arrow function that returns configureBuild function, aka configureBuild Hook, which is called at the start of the package and passes in two parameters config and builds (I’ll cover them later). The configureBuild call returns an async function that is called at the end of the package.

Configuration vite. Config. Ts:

import myPlugin from "./myPlugin"
import type { UserConfig } from "vite"

const config: UserConfig = {
  plugins: [
 myPlugin()  ] }  export default config Copy the code

In two steps, we have completed a simple example of using the configuredHook Plugin. Now that you know how to define a Plugin that uses configureBuild hooks, you may have some questions about what the Build and config parameters of configureBuild are and how to apply them.

ConfigureBuild Hook~ configureBuild Hook~

3 Learn about configureBuild Hooks from the source code

The configureBuild Hook is called at the beginning of the Build build method and an array of builds will be created to store the bundles that will result from each configuredBuild Hook action. Bundles generated by Vite default will also be placed in builds.

// src/node/build/index build()
const builds: Build[] = []
Copy the code

Note that the configuredBuild Hook does not have to return the bundle, or it may not.

The options of the config are then deeply copied to the user and filled with default values. This is to ensure that the following logic can proceed normally and does not need to deal with the logic that does not have an option. This is similar to the default value added in webPack 4.

const config = prepareConfig(options)
Copy the code

The implementation of deep copying and filling in the default values is simple. First, the klona NPM module performs a deep copy of the options of config, and then sets the default values by destructing the assignment.

import klona from "klona/json";

function prepareConfig(config: Partial<BuildConfig>) :BuildConfig {
  const {
    alias = {},
 assetsDir = '_assets'. assetsInclude = isStaticAsset,  assetsInlineLimit = 4096.. } = klona(config)   return { . config, alias,  assetsDir,  assetsInclude,  assetsInlineLimit,  base, . } } Copy the code

Next, we get the configuredBuild from config, which is an array because there may be multiple plugins that use the configureBuild Hook. The configureBuild array is then iterated through using the Map method and each configureBuild Hook is called to expose the user’s Config and builds to it.

const postBuildHooks = toArray(config.configureBuild)
    .map((configureBuild) = > configureBuild(config, builds))
    .filter(Boolean) as PostBuildHook[]
Copy the code

As you can see, vite only exposes the Array of Builds to the configureBuild Hook and we can optionally manipulate builds.

Although the configBuild Hook is intended to give the user more control over the bundle packaging process, it does not mean that it has the highest Priority. Bundles generated by the Vite default package will still be processed before it and the default bundles will be placed at the beginning of builds array.

const rollup = require('rollup').rollup as typeof Rollup
// The generated bundle is packaged by default
constbundle = rollup({... });
builds.unshift({
 id: "index". bundle }); Copy the code

Now that the builds array is built, the next thing to do is iterate over it and write to the bundle (output to disk). Since Vite uses Rollup to package the file, bundle.write is called to export the file to disk.

for (const build of builds) {
  const bundle = await build.bundle;
  const { output } = await bundle[write ? 'write' : 'generate'] ({    dir: resolvedAssetsPath,
    format: 'es'. sourcemap,  entryFileNames: `[name].[hash].js`. chunkFileNames: `[name].[hash].js`. assetFileNames: `[name].[hash].[ext]`.. config.rollupOutputOptions });  build.html = await renderIndex(output);  build.assets = output  await postBuildHooks.reduce(  (queue, hook) = > queue.then((a)= > hook(build as any)),  Promise.resolve();  ) } Copy the code

By default, write is true, which means bundle.write is called to write the code to disk, which is why our packaged results are exported to the dist directory. At the end of each iteration vite calls postBuildHooks to use the function (usually a Promise) that was returned in the initial call to configureBuild Hook. Because postBuildHooks is a Promise array, the reduce method is used to guarantee the order in which hooks are called.

Also, I’m sure you’ve noticed that when we set write to false, bundle.generate is called and only code and sourcemap are output. If so, ConfigureBuild Hook (configureBuild Hook) In addition, we can also do some code conversion operations in the Hook, such as transform() using bleed-core, which makes it easy to implement IE11 support.

Write in the last

As introduced by configureBuild Hook, it will bring more powerful plug-ins to Vite. For example, in configureBuild Hook, we can modify in index. HTML to load the shim file address provided by polyfill. IO to achieve compatibility with older browsers. This is also the idea behind aleclarson’s vite-plugin-legacy. Finally, if there are any mistakes or improper expressions in the article, please make an Issue.

Review previous articles

Who doesn’t want to write clean code? 7 Tips to Make Your colleagues love your Code

5 minutes will take you to quickly understand the vite packaging process, source code analysis

The next generation of packaging tools, esbuild

❤️ Love triple punch

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

I am Wu Liu, like innovation, tamping source Code, focus on Vue3 source Code, Vite source Code, front-end engineering and other technical fields to share, welcome to pay attention to my “wechat public number: Code Center”.