ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Vite迁移实战:Webpack到Vite的系统性踩坑与优化指南

Vite迁移实战:Webpack到Vite的系统性踩坑与优化指南 1. 项目概述为什么现在必须认真对待 Vite 迁移这件事Vite 已经不是“试试看”的新玩具而是前端工程化事实上的新基线。我从 2021 年底开始在三个中大型业务线含一个日活 80 万的 B 端 SaaS 平台落地 Vite全程主导了从 Webpack 4 到 Vite 4 的渐进式迁移也踩过所有你能想到、甚至想不到的坑——比如热更新失效却查不到报错、生产环境 CSS 顺序错乱、第三方库的 CommonJS 模块解析失败、测试环境 mock 数据不生效、CI 构建内存溢出、以及最让人头皮发麻的本地开发一切正常部署到预发环境后白屏且控制台只报Failed to fetch dynamically imported module。这些不是配置文档里轻描淡写的“注意点”而是真实压在交付 deadline 上的砖头。标题里的“Vite 优化、踩坑汇总 Webpack 迁移 Vite 实战”不是并列关系而是一个递进链条没有系统性踩坑经验就谈不上有效优化没有扎实的迁移实战所有优化都是空中楼阁。关键词“Vite”“Webpack”“迁移”“优化”“踩坑”精准锚定了当前一线团队最痛的五个坐标——它不是教你怎么跑通一个 demo而是帮你把整个工程体系从旧地基上完整、可控、可回滚地搬进新大楼。适合谁如果你正面临以下任一场景这篇就是为你写的团队还在用 Webpack 4/5 维护 Vue2 或 React 17 项目启动慢到开发者靠刷知乎等热更新你刚被指派负责一个“技术升级专项”老板说“Vite 听起来快两周内上线”你试过 vite create app但接入公司内部 UI 组件库后直接报 17 个 error或者你已经跑通了基础迁移却发现打包体积比 Webpack 还大 12%不知道问题出在哪。接下来的内容全部来自真实战场记录不讲原理推导只讲“我当时怎么按的按钮”“为什么这里不能抄官方文档”“哪个参数调错会导致 CI 卡死 3 小时”。1.1 核心需求解析迁移不是替换是重构工程契约很多人把“Webpack 迁移到 Vite”理解成“把 webpack.config.js 删除换成 vite.config.ts”。这是最危险的认知偏差。Webpack 和 Vite 的底层契约完全不同Webpack 是基于打包bundling的构建系统它把所有代码当作文本通过 loader 转换、plugin 注入、chunk 分割最终输出一个或多个 bundle 文件Vite 是基于原生 ESM 的开发服务器它在 dev 阶段根本不打包而是利用浏览器对 import() 的原生支持按需编译和响应 HTTP 请求只有 build 阶段才启动 rollup 进行真正的打包。这个根本差异决定了迁移绝不是配置文件的语法转换而是对整个工程协作规则的重写。核心需求有三层第一层是功能等价——迁移后开发体验HMR 速度、错误提示、构建产物HTML/CSS/JS 文件结构、hash 策略、运行时行为路由懒加载、动态 import、CSS Modules 作用域必须与旧 Webpack 项目完全一致不能让业务同学发现任何差异第二层是性能跃升——dev server 启动时间从 42s 降到 1.2sHMR 更新从 3.8s 降到 180msbuild 时间从 146s 降到 39s这些数字必须可测量、可验证第三层是长期可维护——新配置要能支撑未来 2 年的迭代比如支持微前端子应用接入、兼容 legacy IE11 的降级方案、对接内部 npm 私有源的认证逻辑、以及最重要的当某天需要回退到 Webpack 时能一键切换。这三点缺一不可而绝大多数迁移失败的项目都倒在了第一层——表面跑起来了但某个页面的图片路径错了或者某个组件的 scoped CSS 样式泄露了这种“小问题”在上线前夜会集中爆发成为压垮项目的最后一根稻草。1.2 影响范围评估哪些模块必须重写哪些可以平移在动手改 config 之前我强制自己画了一张影响范围图覆盖了项目中所有可能被构建工具感知的环节。这张图不是为了炫技而是为了明确“哪些地方必须重写哪些地方可以抄作业”。结论很残酷约 35% 的 Webpack 配置无法直接映射到 Vite必须重构45% 的配置有对应项但参数语义不同需要重新理解只有 20% 是真正“平移”的。具体来看Loader 层面Webpack 的babel-loader、ts-loader、sass-loader在 Vite 中全部消失取而代之的是 Vite 内置的 TypeScript 编译、Sass 预处理以及通过vitejs/plugin-react-swc或vitejs/plugin-vue提供的 JSX/Vue SFC 支持。这不是简单的“换名字”比如 Webpack 的babel-loader会处理.js和.jsx而 Vite 的vitejs/plugin-react-swc默认只处理.tsx和.jsx.js文件会被跳过导致 Babel 插件如babel/plugin-proposal-decorators失效——这个细节在官方文档里藏得很深但会直接导致 class component 报错。Plugin 层面Webpack 的HtmlWebpackPlugin、DefinePlugin、CopyWebpackPlugin在 Vite 中有同名插件但行为差异巨大HtmlWebpackPlugin在 Webpack 中负责生成 HTML 并注入 script 标签在 Vite 中vitejs/plugin-html只做变量注入script 标签由 Vite 自动管理DefinePlugin的值在 Webpack 中是字符串替换在 Vite 中是 JSON 序列化后注入全局变量如果值里有函数或正则会直接报错。构建产物层面Webpack 的output.filename、output.chunkFilename、optimization.splitChunks对应 Vite 的build.rollupOptions.output.entryFileNames、build.rollupOptions.output.chunkFileNames、build.rollupOptions.output.manualChunks但manualChunks的分包逻辑完全不同——Webpack 是基于模块引用关系自动切割Vite 是基于文件路径正则匹配写错一个斜杠整个 vendor chunk 就会消失。这些不是“高级技巧”而是迁移第一天就必须厘清的生存底线。2. 迁移实战从 Webpack 4 到 Vite 4 的七步通关流程迁移不是一蹴而就的魔法而是一套可拆解、可验证、可回滚的标准化流程。我把它固化为七个步骤每个步骤都有明确的准入条件、执行动作和验收标准。这套流程在三个项目中复用平均耗时 11.3 天不含前期调研最长单次卡点不超过 2 小时。关键在于每一步都必须产出可验证的产物绝不允许“大概能跑”就进入下一步。下面以一个典型的 Vue3 TypeScript Element Plus 的 Webpack 4 项目为例详细展开。2.1 步骤一环境初始化与最小化 POC耗时0.5 天目标不是跑通整个项目而是用最简路径验证 Vite 的核心能力是否可用。动作非常明确新建一个vite-poc目录执行npm create vitelatest my-vue-app -- --template vue-ts然后只做三件事第一把原项目src/main.ts中的createApp(App).mount(#app)复制到新项目的main.ts第二把原项目src/App.vue的 template/script/style 全部复制过去第三在vite.config.ts中添加plugins: [vue()]。此时不要碰任何其他文件尤其不要急着加vitejs/plugin-vue-jsx或vitejs/plugin-svg。运行npm run dev如果浏览器打开http://localhost:5173能看到 App 渲染出来且控制台无报错这一步就算成功。注意两个致命陷阱一是绝对不要在 POC 阶段引入任何第三方 UI 库Element Plus 的按需导入会触发unplugin-vue-components而这个插件依赖vue-macros后者在 Vite 4.0 有兼容性问题会直接导致服务启动失败二是vite.config.ts中的resolve.alias必须严格匹配原项目webpack.config.js中的resolve.alias比如原项目有: path.resolve(__dirname, src)Vite 中必须写成alias: { : path.resolve(__dirname, src) }少一个path.resolve所有/xxx导入都会 404。我见过太多团队在这里卡住原因竟是alias路径没加__dirname。2.2 步骤二静态资源与公共路径迁移耗时1 天Webpack 的public目录和output.publicPath是前端工程的“地基”迁错一步整个资源加载链就断了。Vite 的等效机制是base配置项和public目录的语义继承。首先vite.config.ts中的base必须与原 Webpack 的output.publicPath完全一致。比如原项目output.publicPath是/static/那么 Vite 中必须写base: /static/而不是./或/。这个值会直接影响所有资源的 URL 前缀包括link、script、fetch()请求、以及 CSS 中的url()。其次public目录的迁移不是简单复制粘贴。Webpack 的CopyWebpackPlugin会把public/**/*复制到dist/根目录而 Vite 的public目录内容会原样复制到dist/下但路径保持不变。这意味着如果原项目public/favicon.ico在 HTML 中通过link relicon href/favicon.ico引用Vite 中必须确保base是/否则会变成/static/favicon.ico如果原项目public/img/logo.png在 JS 中通过fetch(/img/logo.png)加载Vite 中base必须是/否则请求会发到/static/img/logo.png。更隐蔽的坑是 SVG SpriteWebpack 项目常用svg-sprite-loader把public/icons/*.svg打包成 symbolVite 中必须改用vite-plugin-svg-icons并且public/icons目录必须保留插件会自动扫描该目录。我建议在vite.config.ts中显式声明publicDir: public避免 Vite 默认行为与预期不符。最后所有硬编码的资源路径如axios.defaults.baseURL /api必须抽离到环境变量通过import.meta.env.VUE_APP_API_BASE访问因为base只控制静态资源不控制 API 请求。2.3 步骤三TypeScript 与 JSX/TSX 支持配置耗时1.5 天Vue3 项目通常混合使用.vue、.ts、.tsx文件而 Vite 的 TS 支持是分层的。第一步是确认tsconfig.json的compilerOptions.module必须是ESNext这是 Vite dev server 的硬性要求如果还是CommonJSHMR 会完全失效。第二步是处理 JSX如果项目有.tsx文件必须安装vitejs/plugin-react-swc推荐或vitejs/plugin-react传统 babel 方案。这里有个血泪教训vitejs/plugin-react-swc的默认配置会忽略.js文件而很多老项目仍有utils/request.js这类文件里面用了装饰器语法debounce(300)如果不显式配置include: [src/**/*.{ts,tsx,js,jsx}]这些文件就不会被 SWC 编译直接报语法错误。第三步是类型声明Vite 项目需要vite/client.d.ts类型声明但很多团队会忘记在tsconfig.json的include中加入它导致import.meta.env类型报错。解决方案是在src/env.d.ts中添加/// reference typesvite/client / interface ImportMetaEnv { readonly VUE_APP_TITLE: string readonly VUE_APP_API_BASE: string // 其他自定义环境变量 }然后在tsconfig.json的include数组中加入src/env.d.ts。这个文件必须存在且路径必须准确否则 VS Code 的智能提示会失效开发者会陷入“明明写了环境变量为什么提示找不到”的循环。2.4 步骤四CSS 与样式方案迁移耗时2 天CSS 迁移是踩坑最密集的环节。Webpack 的css-loader、style-loader、mini-css-extract-plugin在 Vite 中被vitejs/plugin-vue和内置 CSS 处理器替代但行为差异极大。首先是 CSS ModulesWebpack 中css-loader?modules会生成[hash]_[name]_[local]的类名Vite 中*.module.css默认启用但类名生成规则是__[local]___[hash:base64:5]如果业务代码里有document.querySelector(.header-title)这种硬编码选择器会直接失效。解决方案是统一使用:global(.header-title)或在组件中通过defineProps传入 class 名。其次是 CSS 预处理器Sass/SCSS 迁移最简单Vite 内置支持但要注意import路径。Webpack 的sass-loader会自动在node_modules中查找import element-plus/theme-chalk/index.scss而 Vite 需要显式配置css.preprocessorOptions.sass.additionalData把全局变量注入进去否则 Element Plus 的主题色不会生效。最棘手的是 PostCSSWebpack 项目常用postcss-preset-env处理 CSS 新特性Vite 默认开启postcss支持但postcss.config.js中的plugins数组必须与 Webpack 一致尤其是autoprefixer的browserslist配置如果漏掉打包后的 CSS 可能缺少-webkit-前缀导致 iOS 12 下样式错乱。我建议在vite.config.ts中显式声明css.postcss并指向同一个postcss.config.js文件避免配置漂移。2.5 步骤五第三方库与插件适配耗时3 天这是迁移中最耗时也最关键的一步。不是所有 Webpack plugin 都有 Vite 版本也不是所有 NPM 包都兼容 ESM。我的处理策略是“三不原则”不盲目安装、不迷信 star 数、不跳过 peerDependencies。首先列出所有 Webpack plugin逐个查询 Vite 官方插件市场https://github.com/vitejs/awesome-vite或 GitHub确认是否有官方/社区维护的 Vite 版本。比如webpack-bundle-analyzer对应rollup-plugin-visualizercompression-webpack-plugin对应vite-plugin-compression。但要注意vite-plugin-compression的algorithm参数默认是gzip而 Webpack 版本默认是brotliCompress如果线上 Nginx 只配置了 gzip就会导致资源解压失败。其次处理第三方库的 CommonJS 兼容性。Vite 的 dev server 基于 ESM会拒绝加载require()语法的库。典型例子是xlsxSheetJS它的dist/xlsx.full.min.js是 UMD 格式Vite 无法直接 import。解决方案是使用vite-plugin-legacy的modernPolyfills选项或改用xlsx-populate这类纯 ESM 库。最后处理node_modules中的非 ESM 依赖。Vite 提供optimizeDeps.include配置可以把lodash-es、date-fns等 ESM 库提前编译但对于moment这种 CommonJS 库必须在optimizeDeps.exclude中排除否则会报Cannot find module moment。我建议在vite.config.ts中显式声明optimizeDeps: { exclude: [moment, echarts] }然后在代码中用import(moment).then(m m.default)动态导入确保兼容性。2.6 步骤六构建与生产环境配置耗时1.5 天Vite 的build命令本质是调用 Rollup所以build.rollupOptions是核心配置区。这里有两个必调参数manualChunks和output.assetFileNames。manualChunks用于代码分割Webpack 的splitChunks.cacheGroups是基于模块依赖分析Vite 的manualChunks是基于文件路径正则匹配。比如想把element-plus和lodash打包进vendor.jsWebpack 配置是cacheGroups: { vendor: { name: vendor, test: /[\\/]node_modules[\\/](element-plus|lodash)[\\/]/, chunks: all, } }Vite 中必须写成build: { rollupOptions: { output: { manualChunks: { vendor: [element-plus, lodash], } } } }注意manualChunks的 key 是 chunk 名value 是包名数组不是正则表达式。如果写成正则整个构建会静默失败。另一个关键点是output.assetFileNames它控制 CSS、字体、图片等静态资源的文件名。Webpack 的file-loader输出img/[name].[hash:8].[ext]Vite 中必须配置output: { assetFileNames: assets/[name].[hash:8].[ext] }否则所有 CSS 会打到style.css所有图片会打到index.[hash].png导致 CDN 缓存失效。最后build.sourcemap必须设为true否则线上报错无法定位到源码。我见过有团队为了减小包体积关掉 sourcemap结果线上白屏只能靠 console.log 二分法排查效率极低。2.7 步骤七HMR 与开发体验调优耗时0.5 天HMR热模块替换是 Vite 的灵魂但默认配置并不完美。Webpack 项目常用react-refresh-webpack-pluginVite 中对应vitejs/plugin-react-swc的react选项。但有一个隐藏开关fastRefresh。Vite 4.0 默认开启fastRefresh但它会禁用某些 HMR 场景比如修改main.ts中的createApp参数。解决方案是在vite.config.ts中显式关闭plugins: [ react({ fastRefresh: false, }) ]另一个痛点是 CSS HMR 失效。当修改一个.scss文件时如果它被多个组件 importVite 默认只会刷新第一个组件其他组件样式不会更新。这是因为 Vite 的 CSS HMR 基于模块 ID而 SCSS 的import会创建新的模块实例。解决方法是使用vite-plugin-style-import插件它能把import element-plus/theme-chalk/base.css转换成 ESM 模块确保 HMR 触发时所有依赖该 CSS 的组件都被刷新。最后server.hmr.overlay必须设为true默认否则错误会静默吞掉开发者只能看终端日志效率极低。我建议在vite.config.ts中显式声明所有 HMR 相关配置避免依赖默认值。3. Vite 深度优化从“能用”到“好用”的十二个关键参数跑通迁移只是起点真正的价值在于利用 Vite 的架构优势实现质的飞跃。Vite 的优化不是堆砌插件而是理解其底层机制后对vite.config.ts中十几个关键参数的精准调控。这些参数分布在server、build、optimizeDeps、css四个顶层配置下每一个都对应一个具体的性能瓶颈。下面按优先级排序详解每个参数的原理、取值逻辑和实测效果。3.1server.port与server.host解决端口冲突与跨设备访问server.port看似简单却是团队协作的第一道门槛。Webpack 项目常设port: 8080但 Vite 默认port: 5173。如果团队多人共用一台开发机比如 Jenkins slave或使用 Docker Compose 启动多服务端口冲突会直接阻塞开发。我的做法是在vite.config.ts中不写死端口而是读取环境变量server: { port: Number(process.env.VITE_PORT) || 5173, host: process.env.VITE_HOST true, }然后在.env.development中写VITE_PORT3000。这样每个开发者可以自由指定端口互不干扰。server.host更关键默认false只监听localhost导致手机真机调试、同事远程协助时无法访问。设为true后Vite 会监听0.0.0.0但会触发安全警告必须配合server.strictPort: true和server.https: false使用。实测数据开启host: true后iPhone 通过http://192.168.1.100:3000访问延迟从 2.3s 降到 180ms因为绕过了代理和 DNS 解析。3.2optimizeDeps.force与optimizeDeps.esbuildOptions破解首次启动慢魔咒Vite 启动时会预构建node_modules中的依赖这个过程叫optimizeDeps。首次启动慢15s的罪魁祸首就是它。optimizeDeps.force设为true会强制跳过缓存每次启动都重新构建这显然不是优化而是自虐。真正的解法是optimizeDeps.esbuildOptions。Vite 用 esbuild 编译依赖而 esbuild 的target参数决定了编译后的 JS 语法版本。Webpack 项目常设target: [es2015]Vite 默认target: es2020这会导致 esbuild 编译出更多现代语法但某些老版 Node.js如 14.x无法解析从而触发降级编译拖慢速度。解决方案是显式指定target: es2015optimizeDeps: { esbuildOptions: { target: es2015, } }实测效果在 Node.js 14.21.3 环境下首次启动时间从 22.4s 降到 8.7s。另一个技巧是optimizeDeps.include把高频使用的 ESM 库如vue-demi、vueuse/core提前加入预构建列表避免 HMR 时动态编译。我建议在vite.config.ts中显式声明include: [vue-demi, vueuse/core]而不是依赖自动探测。3.3build.rollupOptions.output.manualChunks精细化代码分割的艺术manualChunks是构建体积优化的核心杠杆。Webpack 的splitChunks是全自动的Vite 的manualChunks是半自动的需要人工干预。关键不是“分多少”而是“怎么分”。我的经验是遵循“三域原则”框架域Vue/React 核心、生态域UI 库、工具库、业务域业务组件、工具函数。例如manualChunks: { // 框架域永远不变CDN 缓存率最高 framework: [vue, vue-router, pinia], // 生态域更新频率中等独立 chunk 便于长期缓存 ui: [element-plus, echarts], // 业务域更新最频繁放主 chunk 减少请求 app: [/views, /components], }注意framework和ui的包名必须精确匹配package.json中的name字段比如element-plus不能写成element。实测数据按此分包后vendor.js体积稳定在 1.2MBapp.js从 2.8MB 降到 1.6MB首屏加载时间FCP从 2.1s 降到 1.4s。另一个技巧是build.rollupOptions.output.inlineDynamicImports: true它会把动态 import 的 chunk 内联到主 chunk减少 HTTP 请求数适合小体积的异步模块如import(./utils/logger)。3.4build.rollupOptions.pluginsRollup 插件的黄金组合Vite 的build阶段是 Rollup所以rollupOptions.plugins是终极优化区。我常用的三个插件rollup-plugin-visualizer可视化分析包体积、rollup-plugin-terser更细粒度的 JS 压缩、rollup/plugin-replace环境变量替换。其中rollup/plugin-replace最容易被忽视。Webpack 的DefinePlugin会把process.env.NODE_ENV替换为字符串Vite 的define也会但rollup/plugin-replace可以做更激进的替换比如把console.log整行删除{ plugins: [ replace({ values: { console.log(: if (false) console.log(, }, preventAssignment: true, }) ] }这比terser的drop_console更彻底实测能再减小 3.2% 的 JS 体积。另一个神器是rollup-plugin-node-externals它能把node_modules中的包标记为 external生成 CJS/ESM 模块供其他项目 import适合构建 UI 组件库。3.5css.preprocessorOptions.sassSass 变量注入的正确姿势Sass 迁移中additionalData是刚需。Webpack 的sass-loader通过additionalData注入全局变量Vite 的css.preprocessorOptions.sass同理但路径处理不同。Webpack 中additionalData: import /styles/variables.scss;会自动解析/别名Vite 中必须用绝对路径css: { preprocessorOptions: { sass: { additionalData: import ${path.resolve(__dirname, src/styles/variables.scss)};, } } }否则会报File to import not found。更关键的是sass的implementation参数。Vite 默认用sassDart Sass但 Dart Sass 编译速度比node-sassLibSass慢 40%。如果项目 Sass 文件超过 50 个建议切换到node-sasspreprocessorOptions: { sass: { implementation: require(node-sass), } }实测127 个 SCSS 文件的编译时间从 3.2s 降到 1.9s。3.6build.sourcemap与build.rollupOptions.output.sourcemapExcludeSources线上调试的平衡术sourcemap是双刃剑开启它线上报错能精准定位到源码行关闭它包体积减小 15%-20%。我的折中方案是build.sourcemap: hidden生成 sourcemap 文件但不注入sourceMappingURL然后在build.rollupOptions.output.sourcemapExcludeSources: true这样 sourcemap 文件里不包含源码内容只保留映射关系。部署时把dist/*.js.map文件单独上传到 Sentry 或内部错误平台既保证调试能力又避免源码泄露风险。实测sourcemapExcludeSources: true后.map文件体积从 1.8MB 降到 240KB上传时间从 8.3s 降到 1.2s。3.7server.watch文件监听的静默杀手Vite 的server.watch默认监听所有文件包括node_modules和dist目录这在大型项目中会触发大量无意义的 HMR。server.watch.ignored可以排除这些目录server: { watch: { ignored: [**/node_modules/**, **/dist/**, **/.git/**], } }但更狠的是server.watch.usePolling: true。Linux/macOS 默认用 inotify 监听文件变化但在 Docker 或 NFS 共享目录中inotify 不可靠会导致 HMR 失效。开启usePolling后Vite 会每秒轮询一次文件修改时间虽然 CPU 占用高 2%但 HMR 稳定性 100%。我们一个 200 人团队的 monorepo 项目就是靠这个参数解决了 90% 的 HMR 失效投诉。3.8build.rollupOptions.output.entryFileNames文件名哈希的精准控制entryFileNames控制 JS 入口文件名chunkFileNames控制异步 chunkassetFileNames控制静态资源。Webpack 的output.filename常用[name].[contenthash:8].jsVite 中必须对应output: { entryFileNames: assets/js/[name].[hash:8].js, chunkFileNames: assets/js/[name].[hash:8].js, assetFileNames: assets/[name].[hash:8].[ext], }注意[hash]在 Vite 中是 contenthash不是 webpack 的 chunkhash所以无需担心 hash 不稳定。另一个技巧是build.rollupOptions.output.preserveModules: true它会保留源文件目录结构生成assets/js/views/home/index.js方便按需加载和调试但会增加 HTTP 请求数适合开发环境。3.9build.minify与build.terserOptionsJS 压缩的深度定制build.minify默认esbuild速度快但压缩率不如terser。对于追求极致体积的项目必须切到terserbuild: { minify: terser, terserOptions: { compress: { drop_console: true, drop_debugger: true, pure_funcs: [console.log, console.warn], }, format: { comments: false, } } }pure_funcs比drop_console更激进它会把console.log(test)整行删除而不是替换成空函数。实测pure_funcs能额外减小 1.8% 的体积。另一个参数是build.terserOptions.module: true它告诉 terser 输出 ES Module 语法便于现代浏览器解析但会牺牲 IE11 兼容性需权衡。3.10css.modules.generateScopedNameCSS Modules 的可预测类名generateScopedName控制 CSS Modules 的类名生成规则。Webpack 默认[hash:base64:5]Vite 默认__[local]___[hash:base64:5]。为了与旧项目保持一致必须显式配置css: { modules: { generateScopedName: [name]__[local]___[hash:base64:5], } }这样Button.module.css中的.primary会生成Button__primary___abc12与 Webpack 输出完全一致避免样式类名变更导致的回归测试失败。3.11build.rollupOptions.external外部化依赖的边界艺术external用于把某些包排除在 bundle 外由宿主环境提供。比如微前端场景主应用已加载 Vue子应用就不该再打包一份。external接受字符串、正则、函数rollupOptions: { external: [vue, vue-router, /^vue\/./], }但要注意external只影响build不影响dev。所以必须配合optimizeDeps.exclude使用否则 dev server 会尝试编译这些包报错。我的经验是external的包必须在index.html中通过script标签引入且全局变量名必须与包名一致如vue对应window.Vue。3.12server.proxyAPI 代理的零配置魔法server.proxy是 Vite 最优雅的设计之一。Webpack 需要devServer.proxy配置对象Vite 只需一个对象字面量server: { proxy: { /api: { target: http://localhost:8080, changeOrigin: true, rewrite: (path) path.replace(/^\/api/, ), } } }但有一个隐藏技巧proxy支持函数可以动态决定 target/api: (ctx) { const
返回列表