简述Vite与Webpack原理

一、核心对比:Vite 与 Webpack 本质差异

Webpack:先全量打包再启动服务 ,项目越大冷启动越慢; Vite:基于浏览器原生 ES Module + esbuild 预构建,启动时不打包全部代码,按需加载,启动秒开。

二、开发环境(vite dev)核心原理(最重点)

1. 利用浏览器原生 ES Module 能力

浏览器支持直接识别 import/export,只要文件路径正确,就能直接发起请求加载模块。 Vite 开发服务器不做全量打包,而是作为中间服务拦截浏览器的模块请求,实时转换后返回。

2. esbuild 预构建依赖(解决第三方包问题)

问题:

第三方库大多是 CommonJS 格式(require/module.exports),浏览器不识别 CJS,无法直接 ESM 加载;且大量零散文件会产生过多网络请求。

处理流程:
  1. 启动时用 Go 编写的高速工具 esbuild,一次性把所有 node_modules 依赖打包成单个 ESM 文件
  2. 输出到 node_modules/.vite/deps 缓存目录;
  3. 浏览器后续导入依赖,直接请求预构建好的单文件,减少请求数量、同时转 CJS → ESM。

esbuild 性能远快于 JS 写的打包工具,预构建速度极快。

3. 源码按需实时转换(单文件编译)

业务源码(Vue/TS/JSX/SCSS)不会提前打包,浏览器请求哪个文件,Vite 才实时转换对应文件:

  1. 浏览器请求 src/App.vue
  2. Vite 服务拦截请求,调用插件(@vitejs/plugin-vue)单文件编译;
    • Vue:拆分为 template、script、style,分别转成 JS/CSS;
    • TS/JSX:esbuild 实时转成浏览器可识别 JS;
    • 样式:预处理器转 CSS,内联或单独返回;
  3. 转换完成后把编译结果返回浏览器,浏览器执行。

4. 极速热更新 HMR

  1. 不刷新整页,只精准更新修改的模块;
  2. 基于依赖图,只重新编译变更文件,不牵连其他模块;
  3. 通过 WebSocket 推送变更,保留组件状态,更新毫秒级。

5. 路径重写

  • 识别 @/xxx 别名,自动映射为真实文件路径;
  • 处理静态资源、JSON、图片等资源导入,返回正确资源 URL。

三、生产环境(vite build)构建原理

开发模式只适合本地调试,生产环境需要打包合并文件,Vite 此时切换为 Rollup 做打包:

  1. Rollup 基于 ESM 静态分析,Tree-Shaking 能力优秀,自动剔除未使用代码;
  2. 分块打包:
    • 第三方依赖单独分包(vendor),利用浏览器缓存;
    • 页面 / 组件代码按路由动态分割,实现按需加载;
  3. 内置资源处理:压缩 JS/CSS、图片转 base64 / 输出文件、CSS 提取、代码混淆;
  4. 输出标准静态资源,可直接部署到 CDN。

四、整体流程总结

开发环境流程

  1. 启动服务 → esbuild 预构建第三方依赖(CJS 转 ESM,缓存);
  2. 打开页面,浏览器请求入口 index.html
  3. HTML 里的 import 触发模块请求;
  4. Vite 服务按需单文件编译源码,实时返回转换后的 ESM;
  5. 文件修改 → HMR 精准局部更新。

生产构建流程

执行 vite build → 使用 Rollup 完整打包、Tree-Shaking、资源压缩、代码分割 → 输出 dist 静态目录。

五、核心优势底层原因

  1. 启动快:抛弃全量打包,只预构建依赖,业务代码按需加载;
  2. 更新快:HMR 只编译变更模块,无冗余打包;
  3. 构建快:预构建用 Go 写的 esbuild,生产打包 Rollup 高效 Tree-Shaking;
  4. 原生标准:依托浏览器 ESM 规范,不用复杂模块兼容层。

六、补充短板

  1. 开发环境依赖浏览器 ESM,旧浏览器不兼容(生产打包后无问题);
  2. 极多依赖的大型项目,首次预构建依赖耗时会小幅上升;
  3. 生产打包依赖 Rollup,相比 esbuild 纯打包速度略慢。

七、Webpack 核心定位

基于 JS 实现的静态模块打包工具 ,不依赖浏览器原生 ESM,统一把所有资源(JS/TS/Vue/CSS/ 图片 / 字体)解析为模块,打包成浏览器可识别的 JS 文件。 核心逻辑:先全量打包,再启动开发服务

八、五大核心概念(底层基础)

  1. Entry 入口 打包起点,从入口文件递归遍历所有导入依赖,构建完整依赖图。
  2. Output 输出 定义打包后文件输出路径、文件名。
  3. Loader 加载器 Webpack 仅能识别 JS/JSON,其他文件靠 Loader 转换:
  • babel-loader:TS/JSX 转 ES5
  • vue-loader:解析 Vue 单文件组件
  • css-loader/style-loader:处理样式
  • file-loader:图片、字体资源处理
  1. Plugin 插件 在打包全生命周期钩子执行扩展逻辑: HtmlWebpackPluginMiniCssExtractPluginCleanWebpackPlugin 等。
  2. Mode 模式 development /production,自动开启压缩、Tree-Shaking 等优化。

九、开发环境 webpack-dev-server 原理

  1. 启动流程 执行 npm run dev → Webpack 一次性全量编译所有模块,生成内存打包产物; 启动本地服务,读取内存中的 bundle 返回浏览器。

项目越大,初始打包耗时越长,冷启动慢。

  1. 模块处理逻辑 全部代码提前打包进一个 / 多个 bundle,浏览器只请求打包后的文件,无按需编译。

  2. 热更新 HMR 文件变更后,重新执行部分打包流程,生成更新补丁,替换模块; 需要重新走编译流程,大型项目更新卡顿明显。

  3. 模块兼容处理 内部实现一套自定义模块运行时(webpack runtime),统一兼容 ESM / CommonJS / AMD,不依赖浏览器原生模块能力。

十、生产环境 webpack build 原理

  1. 完整遍历依赖图,递归打包所有资源;
  2. 执行 Tree-Shaking(仅 production 模式)删除未引用代码;
  3. 代码分割 splitChunks:拆分业务代码、第三方依赖、runtime 代码;
  4. Loader 编译资源 + Plugin 压缩、提取 CSS、生成 HTML、清理目录;
  5. 输出磁盘 dist 文件夹。

十一、完整打包流程

  1. 读取 webpack.config.js 配置;
  2. 从 entry 入口开始,递归解析所有 import/require,构建依赖图 Dependency Graph
  3. 对每个模块匹配对应 Loader 转换为标准 JS;
  4. 调用插件各生命周期钩子处理资源;
  5. 合并模块、注入 runtime 运行时代码;
  6. 输出打包后的 bundle 文件到 output 目录。

十二、Webpack vs Vite 核心对比

表格

维度 Webpack Vite
开发启动 全量打包后启动,大项目冷启动极慢 仅预构建依赖,业务代码浏览器按需加载,秒开
模块标准 自研 runtime,兼容所有模块规范,不依赖浏览器 ESM 开发环境依托浏览器原生 ESM
编译工具 全部 Loader 基于 JS,转换速度慢 预构建用 Go 语言 esbuild,编译速度数十倍提升
HMR 更新 修改文件后重新打包部分模块,大型项目卡顿 精准单文件编译,毫秒级更新
生产打包 Webpack 自身打包,Tree-Shaking 较弱 基于 Rollup 打包,Tree-Shaking 更完善
依赖处理 启动时全部打包依赖 启动一次性预构建依赖并缓存,后续复用

十三、Webpack 核心缺点(Vite 解决的痛点)

  1. 冷启动慢:无论是否用到,全部代码提前打包;
  2. 更新慢:文件改动需要重新走打包流程;
  3. JS 实现转换工具,TS/JSX 编译性能远不如 esbuild;
  4. 庞大的打包产物,开发时所有模块一次性加载。

十四、一句话总结

Webpack 是全量预打包 模型,先把整个项目所有资源编译合并,再提供给浏览器; Vite 是按需加载模型,利用浏览器原生 ESM,仅提前处理第三方依赖,业务代码浏览器请求时才实时编译。