Skip to content

深入理解 Vite:依赖预构建、动态导入与 Tree-shaking 机制

Published:
6 min read

简介

Vite 在开发环境(Dev)和生产环境(Build)采用不同的构建策略。开发时利用现代浏览器的原生 ESM 能力配合 esbuild 进行预构建,生产时则使用 Rollup 进行打包。本文深入解析「裸模块」解析、预构建流程,并重点探讨**动态导入(Dynamic Import)**在可选依赖场景下,开发与生产环境在解析、静态分析及 Tree-shaking 上的显著差异。

详细内容

1. 依赖解析与预构建机制(开发环境)

浏览器原生并不支持 import { someMethod } from 'my-dep' 这种写法(针对 my-dep 的识别)。Vite 必须介入处理,这个过程分为预构建交互阶段

1.1 启动阶段:预构建 (Pre-bundling)

Vite 服务启动时,会通过 esbuild 扫描源码和 package.json

  1. 发现依赖:例如检测到 vueaxios
  2. 格式转换与打包:将这些可能是 CJS 或 UMD 规范的包转换为 ESM 格式。
  3. 处理嵌套依赖:如果三方库(如 lib)内部导入了 lodash-es,esbuild 在预构建 lib 时,会直接解析并重写其内部对 lodash-es 的引用路径。
  4. 缓存:产物存放在 node_modules/.vite/deps/ 下。

1.2 交互阶段:路径重写 (Path Rewriting)

当浏览器请求源码时(如 src/App.vue):

  1. 拦截:Vite Server 收到请求,解析文件内容。
  2. 重写:将 import { ref } from 'vue' 重写为 import { ref } from '/node_modules/.vite/deps/vue.js?v=xxx'
  3. 响应:浏览器收到修改后的代码,发起对预构建产物的请求。

2. 动态导入与 Tree-shaking 的深度辨析

误区提示:很多人认为「没有导入就没有分析」,或者「动态导入完全是运行时行为」。实际上,构建工具(无论是 esbuild 还是 Rollup)在打包阶段都会进行静态分析

2.1 场景复现

假设存在一个库 my-lib,它通过动态导入引用了一个可选对等依赖 lodash-es

// my-lib/index.js
export { loadOptionalDep } from './dynamic-dep.js';
export const hello = 'world';

// my-lib/dynamic-dep.js
console.log("Side Effect: I am running"); // 副作用代码
export const loadOptionalDep = async () => {
  // 动态导入可选依赖
  const _ = await import('lodash-es');
  return _;
};

在项目中只使用 hello

// src/main.js
import { hello } from 'my-lib';
console.log(hello);

2.2 开发环境 (Dev) 行为

vite dev 模式下:

2.3 生产构建 (Build) 行为

vite build 模式下(使用 Rollup):

代码示例

以下代码展示了如何配置可选依赖,以及 Vite 如何处理它。

package.json (Library)

{
  "name": "my-lib",
  "peerDependencies": {
    "lodash-es": "^4.0.0"
  },
  "peerDependenciesMeta": {
    "lodash-es": {
      "optional": true
    }
  }
}

src/main.js (Application)

import { hello } from 'my-lib';
// 在 Build 时,loadOptionalDep 及其引用的 lodash-es 会被 Tree-shaking 移除
// 在 Dev 时,dynamic-dep.js 会被加载,控制台会打印副作用日志
console.log(hello);

延伸阅读

New posts, shipping stories, and nerdy links straight to your inbox.

2× per month, pure signal, zero fluff.


Edit on GitHub