preface

In the next generation of packaging tools, ESBuild, I show you what an “esbuild” is and how to use it to implement a bundle packaging. Today, on this special day (1024), I carried out the core logic of “Vite” package implementation, respectively for illustration and code analysis, with only one goal:

Quick reading of “Vite” packing process in 5 minutes!

(Beginning of the text ~)

1 What happened to the NPM Run vite build process?

When we need to package a “Vite” based project, we need to run the NPM run vite build command. In fact, it corresponds to the runBuild method in the source code:

// vite/src/node/cli.ts
async function runBuild(options: UserConfig) {
  try {
    await require('./build').build(options)
    process.exit(0)
 } catch (err) {  console.error(chalk.red(`[vite] Build errored out.`))  console.error(err)  process.exit(1)  } } Copy the code

As you can see, here we call the build() method in./build/index.ts to do the packing:

// vite/src/node/build/index.ts
async function build(options: BuildConfig) :Promise<Result> {
.}
Copy the code

And in conclusion,build()The implementation of the method would look like this (sequence diagram) :

2. Analyze the implementation process of build() method line by line

Here, we break down the implementation details of the build() method line by line from a code perspective:

1. Remove the original outDir directory (dist by default).

await fs.emptyDir(outDir)
Copy the code

BuildHtmlPlugin/index.html/buildHtmlPlugin/index.html/HtmlWebpackPlugin/Webpack/HtmlWebpackPlugin/index.html

const { htmlPlugin, renderIndex } = await createBuildHtmlPlugin(
  root,
  indexPath,
  publicBasePath,
  assetsDir,
 assetsInlineLimit,  resolver,  shouldPreload ) Copy the code

3. Create baseRollupPlugin, which returns an array of plugins, including initialization of the default plugin and user-defined plugins, such as buildResolvePlugin, esBuildPlugin, vuePlugin, and so on.

const basePlugins = await createBaseRollupPlugins(root, resolver, options)
Copy the code

The plugins here are actually plugins for the rollupInputOptions option in Rollup. So, if you need a custom plugin to implement some functionality, you can refer to the “Rollup” website.

Env, VITE_ will be exposed as import.meta.env.

Object.keys(env).forEach((key) = > {
  if (key.startsWith(`VITE_`)) {
    userEnvReplacements[`import.meta.env.${key}`] = JSON.stringify(env[key])
    userClientEnv[key] = env[key]
  }
}) Copy the code

5. “vite” uses “Rollup” as a “Node”, so rollup.rollup() is called to generate the bundle. Also, the baseRollupPlugin, buildHtmlPlugin, and some basic packaging options created above are applied.

const rollup = require('rollup').rollup as typeof Rollup
const bundle = awaitrollup({... })Copy the code

6. Call bundle.generate to generate output (object), which contains the contents of each chunk, such as file name and file content. Finally, the whole packaging process is completed by traversing the output and calling the FS module to generate the corresponding chunk file.

const { output } = await bundle.generate({
  format: 'es'.  sourcemap,
  entryFileNames: `[name].[hash].js`.  chunkFileNames: `[name].[hash].js`.. rollupOutputOptions})  if (write) {  const cwd = process.cwd()  const writeFile = async (  filepath: string,  content: string | Uint8Array. type: WriteType ) = > {. }   await fs.ensureDir(outDir)   for (const chunk of output) {  if (chunk.type === 'chunk') {  // write chunk  const filepath = path.join(resolvedAssetsPath, chunk.fileName)  let code = chunk.code  if (chunk.map) {  code += `\n//# sourceMappingURL=${path.basename(filepath)}.map`  }  await writeFile(filepath, code, WriteType.JS)  if (chunk.map) {  await writeFile(  filepath + '.map'. chunk.map.toString(),  WriteType.SOURCE_MAP  )  }  } else if (emitAssets) {  if(! chunk.source)continue  // write asset  const filepath = path.join(resolvedAssetsPath, chunk.fileName)  await writeFile(  filepath,  chunk.source,  chunk.fileName.endsWith('.css')? WriteType.CSS : WriteType.ASSET )  }  }  if (indexHtml && emitIndex) {  await writeFile(  path.join(outDir, 'index.html'),  indexHtml,  WriteType.HTML  )  } Copy the code

It should be noted that we did not analyze the packaging logic corresponding to SSR here, so students who are interested can know by themselves.

Write in the last

The core of the “vite” packaging implementation is the build() method, and through a brief analysis of the process, I think you should build a basic understanding of the “Vite” packaging implementation. You will also know a thing or two about customizing plugins, because they are really Rollup plugins. Finally, if there is any improper expression in the article, welcome to Issue ~

Review previous articles

The next generation of packaging tools, esbuild

Deep reading Vue3 source | component creation process

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

❤️ 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 follow my wechat public number: Code Center.