Vite 优化、踩坑汇总 + Webpack 迁移 Vite 实战

31 阅读5分钟

一、缓存 .vite 目录:依赖预构建异常处理

1.1 .vite 缓存是什么

预构建产物存放在 node_modules/.vite(可配置 cacheDir 换位置):

node_modules/
└── .vite/
    └── deps/          # 依赖预构建产物(esbuild 打包后的 ESM)
        ├── lodash.js
        └── package.json   # 记录依赖版本,用于判断是否需要重新预构建

作用:依赖未变化时启动直接复用缓存,跳过预构建,冷启动更快。

1.2 预构建异常的三大处理手段

问题处理
依赖升级/新增后行为异常删掉 node_modules/.vite 后重启,强制重新预构建
某个依赖预构建报错optimizeDeps.exclude: ["bad-package"] 排除该包
已知依赖想提前预构建optimizeDeps.include: ["lodash-es"] 预声明,首屏更快
// vite.config.ts
export default defineConfig({
  optimizeDeps: {
    include: ["lodash-es", "axios"],   // 启动时主动预构建,避免首屏等待
    exclude: ["plugin-that-fails"],    // 跳过有问题的依赖
  },
});

快速命令:rm -rf node_modules/.vite && npm run dev 是解决"预构建缓存异常"的第一板斧。


二、大型项目优化手段

2.1 开发期卡顿

手段配置
预声明依赖optimizeDeps.include 提前预构建
限制 sourcemap开发期用 "eval" 或关闭,降低转换开销
缓存目录放固态盘cacheDir: "node_modules/.vite"(默认已在该位置)
关闭无关插件生产专用插件用 apply: "build" 限制,避免开发期空转

2.2 构建包体积过大

export default defineConfig({
  build: {
    rollupOptions: {
      output: {
        manualChunks: {
          vendor: ["vue", "vue-router", "pinia"],      // 框架单独分包,长缓存
          echarts: ["echarts"],                        // 大库独立,按需加载
        },
      },
    },
    // 产物 gzip 压缩(配合 vite-plugin-compression 或部署层 Nginx gzip)
  },
});
优化点做法效果
路由懒加载路由组件用 () => import()首屏只加载当前页代码
第三方库分包manualChunks依赖不动则缓存命中,二次加载极快
压缩产物构建层 gzip/brotli 插件 或 部署层压缩传输体积降 60%~80%
移除调试代码define: { "process.env.NODE_ENV": '"production"' } + 插件移除 console减小体积、避免泄漏
图片压缩静态资源走 CDN 或构建期压缩显著降体积
分析体积rollup-plugin-visualizer 生成可视化报告定位体积大户

三、高频踩坑集合

3.1 静态资源路径

现象原因解决
打包后图片/字体 404部署在子路径但 base 未设置base: "/app/" 或相对 "./"
public 下文件引用不到用 import 引用了 public 文件public 文件用绝对路径 /xxx.png,不经 import
动态拼接路径不生效Vite 静态分析无法识别运行时拼接的资源用 new URL("./img/" + name, import.meta.url).href 或放入 public

3.2 环境变量打包失效

现象原因解决
打包后变量为 undefined变量没加 VITE_ 前缀改名 + 重启
改了 .env 没反应dev-server 不监听 .env 变更重启 npm run dev
动态取变量失败import.meta.env[key] 不被静态替换显式写死:import.meta.env.VITE_XX
引入 process.env 报错Vite 不注入 Node 环境变量用 import.meta.env 或 define 注入
// 兼容写法:把 process.env 指向 Vite 环境
export default defineConfig({
  define: {
    "process.env.NODE_ENV": JSON.stringify(process.env.NODE_ENV || "development"),
  },
});

3.3 externals 处理(排除外部依赖)

场景:依赖由 CDN 提供、不打进产物:

export default defineConfig({
  build: {
    rollupOptions: {
      external: ["vue", "echarts"],          // 不打包这些依赖
      output: {
        globals: { vue: "Vue", echarts: "echarts" },   // 运行时从全局变量取
      },
    },
  },
});
<!-- index.html 通过 CDN 引入,产物不再包含 -->
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>

库模式(build.lib)开发时 external 更常用;应用项目一般交给分包 + CDN 预加载处理。


四、Webpack 项目迁移 Vite 完整步骤

4.1 步骤总览

flowchart LR
    A[备份原项目] --> B[安装 Vite 依赖]
    B --> C[创建 index.html 于根目录]
    C --> D[编写 vite.config.ts]
    D --> E[迁移静态资源与别名]
    E --> F[迁移 Loader/插件到对应方案]
    F --> G[改造环境变量与路径]
    G --> H[npm run dev 逐个验证]

4.2 分步操作

第 1 步:备份并安装

cp -r my-app my-app-backup   # 备份
cd my-app
npm install -D vite @vitejs/plugin-vue   # 按框架选择插件

第 2 步:创建根目录 index.html

<!-- 项目根目录 index.html(Webpack 里由插件生成,Vite 需要原生文件) -->
<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <title>迁移项目</title>
  </head>
  <body>
    <div id="app"></div>
    <script type="module" src="/src/main.ts"></script>   <!-- 入口用模块方式引入 -->
  </body>
</html>

第 3 步:删除 Webpack 相关文件

rm webpack.config.js webpack.common.js webpack.dev.js webpack.prod.js

第 4 步:编写 vite.config.ts(可以参考vite.config 核心配置实战 附带 - 掘金)

第 5 步:迁移资源与别名

# public 目录
mkdir public && mv public/xxx.png public/

# 静态资源(webpack 的 file-loader/url-loader 处理的文件)
mkdir src/assets && mv src/static/* src/assets/

第 6 步:迁移环境变量

# 旧的 .env 中所有变量加 VITE_ 前缀(或改用 import.meta.env)
# 源码中 process.env.XXX → import.meta.env.VITE_XXX

第 7 步:逐页验证

npm run dev      # 开发环境跑通
npm run build    # 生产构建通过

五、Webpack 配置 → Vite 对应方案映射表

Webpack 配置Vite 对应方案
entry(多入口)build.rollupOptions.input(多页面)
output.path / filenamebuild.outDir / build.rollupOptions.output
output.cleanbuild.emptyOutDir(默认 true)
resolve.aliasresolve.alias(语法基本一致)
resolve.extensionsresolve.extensions
HtmlWebpackPlugin根目录原生 index.html
css-loader + style-loader内置 CSS 支持(自动处理)
sass-loader / less-loadercss.preprocessorOptions(仅需装 sass/less 本体)
postcss-loader + autoprefixerpostcss.config.js(Vite 自动识别)
file-loader / url-loader内置 asset 处理(assetsInclude 扩展)
DefinePlugindefine
clean-webpack-pluginbuild.emptyOutDir
mini-css-extract-pluginbuild.cssCodeSplit(默认开启拆分)
terser-webpack-pluginbuild.minify(默认 esbuild,可换 terser)
devServer.proxyserver.proxy
webpack-dev-servervite(内置 dev server + HMR)
ProvidePlugin(自动加载 $ 等)define + 手动 import,或 unplugin-auto-import

六、迁移避坑清单

坑说明与对策
环境变量全丢process.env → import.meta.env,补 VITE_ 前缀,逐个 grep 替换
动态 require业务代码里 require() 在 ESM 下报错,改成 import 或动态 import()
__dirname / __filename 不可用用 import.meta.url + fileURLToPath 替代
路径别名找不到vite 配置 alias 的同时同步修改 tsconfig paths,否则 IDE/TS 报错
CSS 全局变量失效预处理器变量要在 css.preprocessorOptions 注入,组件里不能直接用
老浏览器白屏加 @vitejs/plugin-legacy
图片等资源 404检查 base 与资源放置位置(public vs src/assets)
首屏慢依赖预构建 optimizeDeps.include + 路由懒加载 + 分包
个别依赖预构建崩溃optimizeDeps.exclude 排除后,改用动态 import 或 CDN external

七、总结

  • 缓存:.vite/deps 是预构建产物,异常时删除重建、optimizeDeps.include/exclude 精准控制;
  • 优化:分包 + 懒加载 + 压缩三板斧,rollup-plugin-visualizer 定位体积大户;
  • 踩坑:路径(base/public)、环境变量(VITE_ 前缀 + 重启)、externals 三大高频区;
  • 迁移:index.html 原生入口 → 配置映射表逐项替换 → 环境变量改造 → dev/build 双重验证;
  • 核心心法:Vite 是"约定优于配置"的 ESM 优先工具链,迁移时把"插件思维"换成"内置能力 + 轻量插件"。