跳过正文
  1. 文章/

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

·6807 字·14 分钟·
hujiacheng
作者
hujiacheng
Front-end Developer / Strive To Become Better
目录

本文档详细阐述 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+

相关文章