Vite 构建流程详解:从命令到产物

Jan 23 · 60min

本文档详细阐述 Vite 项目执行 npm run build 命令后的完整构建流程,结合插件钩子机制深入剖析每个阶段的工作原理。

目录


1. 构建流程概览

当执行 npm run build 命令时,Vite 会启动生产环境构建流程,整个过程可以分为以下几个主要阶段:

命令执行

配置解析阶段 (config, configResolved)

构建初始化 (options, buildStart)

模块处理阶段 (resolveId, load, transform, moduleParsed)

模块处理完成 (buildEnd)

代码生成阶段 (renderStart, renderChunk, augmentChunkHash)

资源输出阶段 (generateBundle, writeBundle)

构建完成 (closeBundle)

1.1 钩子分类

Vite 插件钩子可以分为三大类:

通用钩子(Universal Hooks)

  • 继承自 Rollup,在开发和构建模式下都会调用
  • 包括:options, buildStart, resolveId, load, transform, buildEnd, closeBundle

Vite 特有钩子(Vite-Specific Hooks)

  • Vite 独有的钩子,用于处理特定场景
  • 包括:config, configResolved, configureServer, transformIndexHtml, handleHotUpdate

输出生成钩子(Output Generation Hooks)

  • 在 Rollup 输出阶段调用
  • 包括:renderStart, renderChunk, generateBundle, writeBundle

2. 构建前置阶段

2.1 config 钩子

执行时机: 最早执行,在配置文件被解析之前

作用: 修改 Vite 配置,可以返回部分配置对象与现有配置合并

执行顺序: 按插件注册顺序依次执行

// 插件示例
export default function myPlugin() {
  return {
    name: 'my-plugin',
    config(config, { command, mode }) {
      // command: 'build' | 'serve'
      // mode: 'development' | 'production' | 自定义模式

      if (command === 'build') {
        return {
          build: {
            rollupOptions: {
              // 修改 Rollup 配置
            }
          }
        }
      }
    }
  }
}

本项目应用:

  • 各插件在此阶段注入自己的配置
  • 例如 auto-import 插件配置自动导入规则
  • compression 插件配置压缩选项

2.2 configResolved 钩子

执行时机: 在 Vite 配置确认后,构建开始前

作用: 获取最终解析后的配置,不能再修改配置,通常用于读取配置信息

export default function myPlugin() {
  let config;

  return {
    name: 'my-plugin',
    configResolved(resolvedConfig) {
      // 保存配置供后续钩子使用
      config = resolvedConfig;

      console.log('构建模式:', config.command);
      console.log('是否生产环境:', config.isProduction);
      console.log('输出目录:', config.build.outDir);
    }
  }
}

本项目应用:

  • sourcemap-output-filter 插件在此阶段读取配置
  • 确定是否需要过滤 sourcemap 文件

3. 构建核心阶段

3.1 options 钩子

执行时机: 构建开始时,在 buildStart 之前

作用: 替换或操作传递给 Rollup 的选项对象

export default function myPlugin() {
  return {
    name: 'my-plugin',
    options(options) {
      // 可以修改 Rollup 的 input 选项
      return {
        ...options,
        // 自定义配置
      }
    }
  }
}

3.2 buildStart 钩子

执行时机: 每次构建开始时调用

作用: 访问 Rollup 选项,执行初始化操作

特点: 并行执行(parallel)

export default function myPlugin() {
  return {
    name: 'my-plugin',
    buildStart(options) {
      console.log('构建开始');
      console.log('入口文件:', options.input);

      // 可以在这里做一些初始化工作
      // 例如:清理缓存、创建临时目录等
    }
  }
}

本项目应用:

  • Vue 插件在此阶段初始化编译器
  • 各插件准备构建所需的资源

3.3 resolveId 钩子

执行时机: 每次解析模块导入时调用

作用: 自定义模块解析逻辑,可以拦截导入并返回自定义的模块 ID

特点:

  • 首个执行(first)
  • 可以返回 null 让其他解析器处理
export default function myPlugin() {
  return {
    name: 'my-plugin',
    resolveId(source, importer, options) {
      // source: 导入的模块路径
      // importer: 导入该模块的文件路径
      // options: 解析选项

      if (source === 'virtual-module') {
        // 返回虚拟模块 ID
        return '\0virtual-module';
      }

      // 返回 null 让其他插件处理
      return null;
    }
  }
}

本项目应用:

  • 处理路径别名(@, ~, components 等)
  • auto-import 插件解析自动导入的组件和 API

3.4 load 钩子

执行时机:resolveId 之后,加载模块内容时调用

作用: 自定义模块加载逻辑,可以返回模块的源代码

特点: 首个执行(first)

export default function myPlugin() {
  return {
    name: 'my-plugin',
    load(id) {
      // id: 模块的完整路径

      if (id === '\0virtual-module') {
        // 返回虚拟模块的代码
        return 'export default "This is a virtual module"';
      }

      // 返回 null 让其他插件或默认加载器处理
      return null;
    }
  }
}

本项目应用:

  • Vue 插件加载 .vue 文件
  • 处理特殊文件类型(如 JSON、图片等)

3.5 transform 钩子

执行时机:load 之后,对每个加载的模块进行转换

作用: 转换模块代码,这是最常用的钩子之一

特点: 顺序执行(sequential)

export default function myPlugin() {
  return {
    name: 'my-plugin',
    transform(code, id) {
      // code: 模块的源代码
      // id: 模块的完整路径

      if (id.endsWith('.vue')) {
        // 转换 Vue 文件
        const transformedCode = someTransform(code);

        return {
          code: transformedCode,
          map: null, // sourcemap
        };
      }

      return null;
    }
  }
}

本项目应用:

  • Vue 插件编译 .vue 单文件组件
  • setup-extend 插件处理 Vue 组件的 name 属性
  • esbuild 转换 TypeScript/JSX
  • 移除 console 和 debugger(生产环境)

3.6 moduleParsed 钩子

执行时机: 模块被完全解析后调用

作用: 获取模块的 AST 和依赖信息

特点:

  • 仅在构建阶段调用(开发模式不调用,性能考虑)
  • 并行执行(parallel)
export default function myPlugin() {
  return {
    name: 'my-plugin',
    moduleParsed(moduleInfo) {
      console.log('模块 ID:', moduleInfo.id);
      console.log('模块依赖:', moduleInfo.importedIds);
      console.log('模块导出:', moduleInfo.exports);
      console.log('是否入口:', moduleInfo.isEntry);
    }
  }
}

本项目应用:

  • 分析模块依赖关系
  • 为代码分割提供依赖信息

4. 构建输出阶段

4.1 renderStart 钩子

执行时机: 在 Rollup 开始生成输出文件之前

作用: 在输出生成开始时执行操作

特点: 并行执行(parallel)

export default function myPlugin() {
  return {
    name: 'my-plugin',
    renderStart(outputOptions, inputOptions) {
      console.log('开始生成输出文件');
      console.log('输出格式:', outputOptions.format);
      console.log('输出目录:', outputOptions.dir);
    }
  }
}

4.2 renderChunk 钩子

执行时机: 在每个 chunk 渲染后调用

作用: 转换单个 chunk 的代码,可以修改代码或添加 sourcemap

特点: 顺序执行(sequential)

export default function myPlugin() {
  return {
    name: 'my-plugin',
    renderChunk(code, chunk, options) {
      // code: chunk 的代码
      // chunk: chunk 信息(文件名、模块列表等)
      // options: 输出选项

      console.log('处理 chunk:', chunk.fileName);
      console.log('chunk 包含的模块:', Object.keys(chunk.modules));

      // 可以修改代码
      const modifiedCode = code.replace(/console\.log/g, '');

      return {
        code: modifiedCode,
        map: null,
      };
    }
  }
}

本项目应用:

  • esbuild 压缩代码
  • 移除注释和 console

4.3 augmentChunkHash 钩子

执行时机: 在生成 chunk 哈希之前

作用: 为 chunk 添加额外的哈希输入,影响最终的文件名

export default function myPlugin() {
  return {
    name: 'my-plugin',
    augmentChunkHash(chunkInfo) {
      // 返回字符串会被添加到哈希计算中
      if (chunkInfo.name === 'main') {
        return 'custom-hash-input';
      }
    }
  }
}

4.4 generateBundle 钩子

执行时机: 在 bundle 生成完成后,文件写入磁盘之前

作用: 修改、添加或删除输出文件,这是修改最终输出的最后机会

特点: 顺序执行(sequential)

export default function myPlugin() {
  return {
    name: 'my-plugin',
    generateBundle(options, bundle) {
      // bundle: 包含所有输出文件的对象

      for (const fileName in bundle) {
        const file = bundle[fileName];

        if (file.type === 'chunk') {
          console.log('Chunk 文件:', fileName);
          console.log('Chunk 大小:', file.code.length);
        } else if (file.type === 'asset') {
          console.log('资源文件:', fileName);
        }
      }

      // 可以添加新文件
      this.emitFile({
        type: 'asset',
        fileName: 'custom-file.txt',
        source: 'Custom content',
      });

      // 可以删除文件
      delete bundle['unwanted-file.js'];
    }
  }
}

本项目应用:

  • sourcemap-output-filter 插件在此阶段过滤 sourcemap 文件
  • compression 插件生成 gzip/brotli 压缩文件
  • visualizer 插件生成打包分析报告

4.5 writeBundle 钩子

执行时机: 在文件写入磁盘之后

作用: 执行清理工作或后续操作,此时文件已经写入

特点: 并行执行(parallel)

export default function myPlugin() {
  return {
    name: 'my-plugin',
    writeBundle(options, bundle) {
      console.log('文件已写入磁盘');
      console.log('输出目录:', options.dir);

      // 可以执行后续操作
      // 例如:上传到 CDN、发送通知等
    }
  }
}

本项目应用:

  • 可用于上传 sourcemap 到 Sentry
  • 生成构建报告
  • 清理临时文件

5. 构建后处理阶段

5.1 buildEnd 钩子

执行时机: 构建结束时调用(无论成功或失败)

作用: 清理资源,记录构建信息

特点: 并行执行(parallel)

export default function myPlugin() {
  return {
    name: 'my-plugin',
    buildEnd(error) {
      if (error) {
        console.error('构建失败:', error);
      } else {
        console.log('构建成功完成');
      }

      // 清理临时资源
    }
  }
}

5.2 closeBundle 钩子

执行时机: 最后执行的钩子,在所有操作完成后

作用: 最终的清理工作

特点: 并行执行(parallel)

export default function myPlugin() {
  return {
    name: 'my-plugin',
    closeBundle() {
      console.log('构建流程完全结束');
      // 最终清理工作
    }
  }
}

6. 本项目构建流程实例

基于当前项目配置,完整的构建流程如下:

6.1 配置解析阶段

1. 执行 vite.config.ts 导出的函数
   - mode: 'production'
   - command: 'build'
   - 加载环境变量 (loadEnv)

2. 各插件的 config 钩子执行
   - @vitejs/plugin-vue
   - unplugin-auto-import
   - unplugin-vue-components
   - vite-plugin-compression
   - rollup-plugin-visualizer (如果启用)

3. configResolved 钩子执行
   - 各插件读取最终配置
   - 确认构建选项和路径配置

6.2 构建初始化阶段

1. options 钩子执行
   - 修改 Rollup 配置选项

2. buildStart 钩子执行
   - Vue 插件初始化编译器
   - 各插件准备构建资源

6.3 模块处理阶段

对于每个模块(从入口文件 index.html 开始):

1. resolveId 钩子
   - 解析路径别名 (@, ~, components, styles, utils)
   - auto-import 插件解析自动导入的 API
   - 解析 node_modules 中的依赖

2. load 钩子
   - Vue 插件加载 .vue 文件
   - 加载 .js/.ts/.jsx/.tsx 文件
   - 加载静态资源(图片、字体等)

3. transform 钩子
   - Vue 插件编译 .vue 单文件组件
   - esbuild 转换 TypeScript/JSX
   - 生产环境:移除 console 和 debugger
   - SCSS/Less 预处理器处理样式

4. moduleParsed 钩子
   - 分析模块依赖关系
   - 构建依赖图谱

6.4 代码分割阶段

根据 manualChunks 配置进行代码分割:

1. vendor-vue: vue, vue-router, pinia, vue-demi
2. vendor-ui: element-plus, @element-plus/icons-vue
3. vendor-charts: echarts
4. vendor-utils: lodash-es, dayjs, axios
5. 业务代码按路由自动分割

代码分割优势:
- 将第三方库分离为独立 chunk
- 利用浏览器缓存,减少重复下载
- 减少主包体积,加快首屏加载

6.5 输出生成阶段

1. renderStart 钩子
   - 开始生成输出文件

2. renderChunk 钩子(对每个 chunk)
   - esbuild 压缩代码
   - 移除注释(legalComments: 'none')
   - 生成 hidden sourcemap

3. augmentChunkHash 钩子
   - 计算 chunk 哈希值
   - 生成带哈希的文件名

4. generateBundle 钩子
   - compression 插件生成压缩文件
     * 生成 .gz 文件
     * 生成 .br 文件
   - visualizer 生成打包分析报告(如果启用)

5. writeBundle 钩子
   - 文件写入 dist 目录

6.6 构建完成阶段

注意:buildEnd 在模块处理阶段结束后、输出生成阶段之前执行

1. closeBundle 钩子
   - 最终清理工作
   - 可用于上传 sourcemap 到 Sentry
   - 构建流程完全结束

6.7 最终产物

dist/
├── assets/
│   ├── index-[hash].js          # 入口文件
│   ├── index-[hash].js.map      # 入口 sourcemap
│   ├── vendor-vue-[hash].js     # Vue 相关依赖
│   ├── vendor-ui-[hash].js      # UI 组件库
│   ├── vendor-charts-[hash].js  # 图表库
│   ├── vendor-utils-[hash].js   # 工具库
│   ├── [route]-[hash].js        # 路由分割的业务代码
│   ├── [route]-[hash].js.map    # 业务代码 sourcemap
│   ├── *.css                    # 样式文件
│   ├── *.gz                     # Gzip 压缩文件
│   └── *.br                     # Brotli 压缩文件
├── index.html                   # 入口 HTML
└── stats.html                   # 打包分析报告(可选)

7. 插件执行顺序详解

7.1 插件解析顺序

Vite 按以下顺序解析和执行插件:

1. Alias 解析插件

2. enforce: 'pre' 的用户插件

3. Vite 核心插件

4. 普通用户插件(无 enforce 值)

5. Vite 构建插件

6. enforce: 'post' 的用户插件

7. Vite 后构建插件(压缩、manifest、报告等)

7.2 典型项目插件执行顺序

基于常规 Vue + Vite 项目配置,插件的实际执行顺序:

构建阶段插件顺序:

1. @vitejs/plugin-vue
   - 处理 .vue 文件
   - 编译单文件组件

2. unplugin-auto-import
   - 自动导入 Vue API (ref, computed, watch 等)
   - 自动导入 Vue Router API
   - 自动导入 Pinia API

3. unplugin-vue-components
   - 自动导入组件
   - 集成 UI 组件库 Resolver

4. vite-plugin-compression
   - enforce: 'post' (后置执行)
   - 在 generateBundle 阶段生成压缩文件

5. rollup-plugin-visualizer (可选)
   - 在 generateBundle 阶段生成分析报告

7.3 钩子执行特性

不同钩子有不同的执行特性:

顺序执行(Sequential)

  • 按插件顺序依次执行
  • 前一个插件执行完才执行下一个
  • 适用于需要链式处理的场景
  • 钩子:transform, renderChunk, generateBundle

并行执行(Parallel)

  • 所有插件的钩子同时执行
  • 提高执行效率
  • 适用于独立操作
  • 钩子:buildStart, buildEnd, renderStart, writeBundle, closeBundle

首个执行(First)

  • 按顺序执行,直到某个插件返回非 null 值
  • 后续插件不再执行
  • 适用于解析和加载场景
  • 钩子:resolveId, load

7.4 条件执行插件

插件可以通过 apply 选项指定执行环境:

export default function myPlugin() {
  return {
    name: 'my-plugin',
    apply: 'build', // 仅在构建时执行
    // apply: 'serve', // 仅在开发时执行
    // apply: (config, { command }) => command === 'build', // 自定义条件
  }
}

典型应用:

  • compression 插件仅在构建时执行
  • vite-plugin-inspect 插件仅在开发时执行
  • HMR 相关插件仅在开发时执行

8. 性能优化要点

8.1 构建性能优化

基于构建流程,以下是关键的性能优化点:

1. 依赖预构建(optimizeDeps)

optimizeDeps: {
  esbuildOptions: {
    target: 'esnext', // 使用现代语法,减少转换
  }
}

2. 代码分割(manualChunks)

  • 将第三方库分离为独立 chunk
  • 利用浏览器缓存
  • 减少主包体积

3. Sourcemap 优化

  • 使用 hidden sourcemap
  • 仅为业务代码生成 sourcemap
  • 减少构建时间和产物体积

4. 压缩优化

  • 使用 esbuild 压缩(比 terser 快)
  • 移除 console 和 debugger
  • 移除注释

8.2 产物优化

1. 资源压缩

// Gzip 和 Brotli 压缩
vite-plugin-compression

2. 文件哈希

  • 自动为文件名添加哈希
  • 支持长期缓存策略

3. Tree Shaking

  • Rollup 自动移除未使用的代码
  • 使用 ES Module 语法

4. CSS 优化

  • 自动提取 CSS
  • CSS 代码分割
  • 移除未使用的样式

9. 调试技巧

9.1 查看构建详情

# 查看详细构建日志
npm run build -- --debug

# 生成打包分析报告
VISUALIZER=true npm run build

9.2 插件调试

在插件中添加日志输出:

export default function myPlugin() {
  return {
    name: 'my-plugin',
    configResolved(config) {
      console.log('[my-plugin] 配置已解析');
    },
    buildStart() {
      console.log('[my-plugin] 构建开始');
    },
    transform(code, id) {
      if (id.includes('target-file')) {
        console.log('[my-plugin] 转换文件:', id);
      }
      return null;
    },
    generateBundle(options, bundle) {
      console.log('[my-plugin] 生成的文件数量:', Object.keys(bundle).length);
    }
  }
}

9.3 常见问题排查

1. 模块解析失败

  • 检查 resolveId 钩子
  • 确认路径别名配置
  • 查看 resolve.alias 设置

2. 代码转换错误

  • 检查 transform 钩子
  • 确认文件类型处理顺序
  • 查看 sourcemap 是否正确

3. 产物异常

  • 检查 generateBundle 钩子
  • 确认文件是否被意外删除或修改
  • 查看插件执行顺序

10. 总结

10.1 完整构建流程时序图

npm run build

┌─────────────────────────────────────────┐
│  1. 配置解析阶段                         │
│  - config 钩子                          │
│  - configResolved 钩子                  │
└─────────────────────────────────────────┘

┌─────────────────────────────────────────┐
│  2. 构建初始化                           │
│  - options 钩子                         │
│  - buildStart 钩子                      │
└─────────────────────────────────────────┘

┌─────────────────────────────────────────┐
│  3. 模块处理(循环处理每个模块)          │
│  - resolveId 钩子 (解析模块路径)         │
│  - load 钩子 (加载模块内容)              │
│  - transform 钩子 (转换模块代码)         │
│  - moduleParsed 钩子 (解析完成)         │
└─────────────────────────────────────────┘

┌─────────────────────────────────────────┐
│  4. 模块处理完成                         │
│  - buildEnd 钩子 (构建阶段结束)          │
└─────────────────────────────────────────┘

┌─────────────────────────────────────────┐
│  5. 输出生成                             │
│  - renderStart 钩子                     │
│  - renderChunk 钩子 (处理每个 chunk)    │
│  - augmentChunkHash 钩子 (计算哈希)     │
│  - generateBundle 钩子 (生成产物)       │
│  - writeBundle 钩子 (写入磁盘)          │
└─────────────────────────────────────────┘

┌─────────────────────────────────────────┐
│  6. 构建完成                             │
│  - closeBundle 钩子                     │
└─────────────────────────────────────────┘

构建完成,产物输出到 dist 目录

10.2 关键要点

1. 钩子执行顺序

  • 配置钩子最先执行(config → configResolved)
  • 模块处理钩子循环执行(resolveId → load → transform → moduleParsed)
  • buildEnd 在模块处理完成后执行
  • 输出钩子最后执行(renderStart → renderChunk → generateBundle → writeBundle → closeBundle)

2. 插件顺序很重要

  • 使用 enforce: 'pre' 提前执行
  • 使用 enforce: 'post' 延后执行
  • 默认按注册顺序执行

3. 性能优化关键点

  • 合理配置代码分割
  • 使用 esbuild 进行快速转换和压缩
  • 优化 sourcemap 生成策略
  • 启用资源压缩(gzip/brotli)

4. 调试建议

  • 在关键钩子添加日志
  • 使用 visualizer 分析打包结果
  • 检查插件执行顺序
  • 确认文件转换流程

10.3 典型项目构建特点

基于常规 Vue + Vite 项目配置,构建流程具有以下特点:

1. 模块化的插件管理

  • 插件配置集中在 vite.config.ts
  • 根据构建模式动态加载插件
  • 便于维护和扩展

2. 精细化的代码分割

  • 多个 vendor chunk,按功能分类
  • 减少重复打包
  • 优化缓存策略

3. 智能的 Sourcemap 处理

  • 可配置仅为业务代码生成 sourcemap
  • 使用 hidden 模式保护源码
  • 可选上传到错误监控平台

4. 完善的压缩策略

  • esbuild 快速压缩
  • 生成 gzip 和 brotli 双格式
  • 移除 console 和注释

11. 参考资源

11.1 官方文档

11.2 相关插件文档


12. 附录

12.1 钩子快速参考表

钩子名称执行阶段执行特性主要用途
config配置解析前Sequential修改配置
configResolved配置解析后Parallel读取配置
options构建开始前Sequential修改 Rollup 选项
buildStart构建开始Parallel初始化操作
resolveId模块解析First自定义模块解析
load模块加载First自定义模块加载
transform代码转换Sequential转换模块代码
moduleParsed模块解析完成Parallel分析模块信息
renderStart输出开始Parallel输出前准备
renderChunkChunk 渲染Sequential转换 chunk 代码
augmentChunkHash哈希计算Sequential影响文件哈希
generateBundle生成产物Sequential修改输出文件
writeBundle写入磁盘后Parallel后续操作
buildEnd构建结束Parallel清理资源
closeBundle完全结束Parallel最终清理

12.2 插件开发模板

export default function myVitePlugin(options = {}) {
  // 插件内部状态
  let config;

  return {
    // 插件名称(必需)
    name: 'my-vite-plugin',

    // 应用模式:'build' | 'serve' | (config, env) => boolean
    apply: 'build',

    // 执行顺序:'pre' | 'post'
    enforce: 'post',

    // 配置解析前
    config(config, { command, mode }) {
      return {
        // 返回部分配置进行合并
      };
    },

    // 配置解析后
    configResolved(resolvedConfig) {
      config = resolvedConfig;
    },

    // 构建开始
    buildStart(options) {
      // 初始化操作
    },

    // 模块解析
    resolveId(source, importer, options) {
      // 返回模块 ID 或 null
      return null;
    },

    // 模块加载
    load(id) {
      // 返回模块代码或 null
      return null;
    },

    // 代码转换
    transform(code, id) {
      // 返回转换后的代码
      return {
        code,
        map: null,
      };
    },

    // 输出生成
    generateBundle(options, bundle) {
      // 修改、添加或删除输出文件
    },

    // 构建结束
    buildEnd(error) {
      // 清理资源
    },
  };
}

12.3 常见场景示例

场景 1:添加版本号到文件头部

export default function addVersionPlugin(version) {
  return {
    name: 'add-version',
    renderChunk(code, chunk) {
      if (chunk.isEntry) {
        return {
          code: `/* Version: ${version} */\n${code}`,
          map: null,
        };
      }
    }
  };
}

场景 2:过滤特定文件

export default function filterFilesPlugin(pattern) {
  return {
    name: 'filter-files',
    generateBundle(options, bundle) {
      for (const fileName in bundle) {
        if (pattern.test(fileName)) {
          delete bundle[fileName];
        }
      }
    }
  };
}

场景 3:生成构建报告

export default function buildReportPlugin() {
  return {
    name: 'build-report',
    generateBundle(options, bundle) {
      const report = {
        chunks: [],
        assets: [],
        totalSize: 0,
      };

      for (const fileName in bundle) {
        const file = bundle[fileName];
        const size = file.type === 'chunk'
          ? file.code.length
          : file.source.length;

        report.totalSize += size;

        if (file.type === 'chunk') {
          report.chunks.push({ fileName, size });
        } else {
          report.assets.push({ fileName, size });
        }
      }

      this.emitFile({
        type: 'asset',
        fileName: 'build-report.json',
        source: JSON.stringify(report, null, 2),
      });
    }
  };
}

结语

本文档详细阐述了 Vite 项目从执行 npm run build 命令到生成最终产物的完整构建流程。通过深入理解插件钩子机制和执行顺序,可以更好地:

  1. 优化构建性能 - 了解每个阶段的工作原理,针对性地进行优化
  2. 开发自定义插件 - 掌握插件开发的核心概念和最佳实践
  3. 排查构建问题 - 快速定位问题所在的构建阶段和插件
  4. 提升代码质量 - 利用构建流程实现代码检查、优化和转换

希望这份文档能帮助你更深入地理解 Vite 的构建机制,并在实际项目中灵活运用。


文档版本: 1.0 最后更新: 2026-01-23 适用 Vite 版本: 5.x+

CC BY-NC-SA 4.0 2024-PRESENT © hujiacheng