告别Webpack:用TypeScript+tsup+Vite+Rolldown重构前端构建链路

📅 2026/8/26 4:46:09
告别Webpack:用TypeScript+tsup+Vite+Rolldown重构前端构建链路
1. 前端构建工具换代先看清 Webpack 的痛点在哪儿过去五年Webpack 几乎成了前端工程化的代名词。无论是 Vue、React 还是 Node 端同构项目脚手架默认配置都是 Webpack开发者也已经习惯了处理 loader、plugin、splitChunks、devServer 这些概念。但随着项目规模增长Webpack 带来的体感越来越明显配置越堆越复杂启动开发服务器要等很久热更新偶尔卡顿构建时内存占用高得吓人。尤其在大量使用 TypeScript 的项目里每次编译等待几十秒、产物体积膨胀、日志排错困难这些痛点会直接影响团队迭代效率。本文围绕一条非常清晰的主线用 TS tsup Vite Rolldown 这套组合替代传统 Webpack 构建链路。它并不是说 Webpack 一无是处而是从工程视角看新一代工具已经能在库开发、业务项目、底层打包引擎三个层面分别给出更优解。适合正在维护 Webpack 老项目、想迁移或重构构建链路的开发者也适合刚接触前端工程化、想一步到位建立现代构建方案的新手。读完本文后你可以掌握 tsup 快速打包 TS 库、Vite 高效构建业务项目、Rolldown 与 Vite 的融合方向以及各种高频迁移报错的排查思路。文章末尾还附了一份可落地的迁移决策清单方便对照自己的项目做判断。2. 新一代工具全景四件工具各自解决什么问题先建立整体认知。这四样东西并非同一层级也没有互相替代关系它们更像是一条链路上的不同环节。2.1 TypeScript不止是类型系统更是构建基础设施严格来说TypeScript 不是打包器它负责的是类型检查与语法编译。但在现代前端工程里TS 已经逐步从“语言增强”升级为“构建基础设施的一部分”。比如interface和type的取舍、PartialT这类内置工具类型的运用、tsconfig.json中moduleResolution的配置都会直接影响打包器如何读取和编译代码。看一个很常见的库代码片段// src/types/user.ts export interface User { id: number; name: string; email: string; role: admin | user; } export type UserProfile PartialUser; export interface UserService { getUser(id: number): PromiseUser; updateUser(id: number, profile: UserProfile): PromiseUser; }注意PartialUser的作用它把User的所有属性变成可选。这种写法在接口更新、表单提交等场景中非常实用。而interface与type的区别简而言之interface更强调对象结构的声明与继承type更适合定义联合类型、交叉类型和工具类型映射。日常开发中两者可以混用但库的对外 API 建议优先用interface因为它在类型推断报错时给出的信息更友好。2.2 tsup库开发者的首选打包器tsup 是基于 esbuild 的上层封装定位非常明确快速把 TypeScript 源码打包成可发布的 JS 库。它的优势不在于功能多而在于“零配置”和“快”。对于写 npm 包、工具函数库、组件库的开发者来说tsup 几乎可以省略掉复杂的 Rollup 或 Webpack 库配置。2.3 Vite业务项目构建的现代方案Vite 是面向业务应用比如 Vue3、React 项目的开发服务器与构建工具。开发阶段借助原生 ESM 和 esbuild 预构建依赖启动速度极快生产构建阶段则借助 Rollup 输出优化产物。Vite 还提供了非常完善的插件体系能承接绝大多数 Webpack 生态场景例如路径别名、代理转发、代码压缩、静态资源处理。2.4 Rolldown底层打包引擎的未来Rolldown 是 VoidZero 团队开源的 Rust 构建引擎目标是重写 Rollup 内核。它现阶段最核心的方向是作为 Vite 下一代的底层引擎业界常把它描述为“Vite 底层从 Rollup 迁移到 Rolldown 的实验方案”。对绝大多数开发者来说Rolldown 短期内不会直接出现在业务代码里但通过rolldown-vite这类实验包可以提前体验到 Rust 引擎带来的构建速度提升。一个更直观的对比维度WebpacktsupViteRolldown核心语言JavaScriptGoesbuildJavaScript RollupRust主要场景大型业务项目npm 库 / 小工具业务项目Vite 底层引擎启动速度慢极快快极快配置复杂度高低中低中实验期生态成熟度极高中高早期这个表能帮助你快速判断如果只是写库别用 Webpack如果是业务系统Vite 是更现代的选择如果关注构建速度的极限Rolldown 值得跟进。3. 环境准备与版本说明在动手前先把环境统一一下。具体版本需根据实际项目调整本文示例以常见环境为准重点演示配置思路。操作系统Windows 11 / macOS / Linux 均可。Node.js建议 18.18 或 20.x 以上版本原因在于新版 Vite 和 esbuild 都依赖较新的 Node API。包管理器推荐 pnpm如果习惯 npm 或 yarn 也可示例命令会同时注明。IDEVS Code 即可建议安装 Vite 官方插件和 TypeScript Vue PluginVolar。先看一下本文实战部分会使用的目录结构webpack-replace-lab ├── packages │ ├── utils # 用 tsup 构建的 TS 工具库 │ │ ├── src │ │ ├── dist │ │ ├── package.json │ │ └── tsup.config.ts │ └── app # 用 Vite 构建的业务项目 │ ├── src │ ├── public │ ├── index.html │ ├── package.json │ └── vite.config.ts ├── rolldown-experiment # Rolldown 实验项目 │ ├── src │ ├── package.json │ └── rolldown.config.ts └── package.json如果没有装 pnpm先执行npm install -g pnpm然后创建一个 monorepo 根目录mkdir webpack-replace-lab cd webpack-replace-lab pnpm init根目录package.json可以简单配置为{ name: webpack-replace-lab, private: true, scripts: { build:utils: pnpm --filter demo/utils build, dev:app: pnpm --filter demo/app dev } }这样后续可以在根目录直接调用子包命令避免路径切换的麻烦。4. 实战一用 tsup 打包一个 TS 工具库这一节的目标把一个包含接口定义、接口类、类型工具比如Partial的 TypeScript 工具库用 tsup 打包成多种格式并成功在业务项目里引用。4.1 创建工具包并安装依赖mkdir packages/utils cd packages/utils pnpm init pnpm add -D typescript tsup types/node在packages/utils下创建tsconfig.json{ compilerOptions: { target: ES2020, module: ESNext, moduleResolution: Bundler, strict: true, declaration: true, skipLibCheck: true, esModuleInterop: true, forceConsistentCasingInFileNames: true }, include: [src] }这里moduleResolution: Bundler是比较新的解析方式专门为 Vite、Rolldown 这类打包器准备能更好处理exports字段和 TS 文件导入。4.2 编写工具库源码// packages/utils/src/types.ts export interface RequestOptions { url: string; method?: GET | POST | PUT | DELETE; params?: Recordstring, unknown; timeout?: number; } export type PartialRequestOptions PartialRequestOptions; export interface ResponseDataT unknown { code: number; message: string; data: T; }这里PartialRequestOptions在封装 axios 时很有意义。比如用户只想覆盖部分请求配置// packages/utils/src/http.ts import axios from axios; import type { RequestOptions, ResponseData, PartialRequestOptions } from ./types; export class HttpClient { private defaultOptions: RequestOptions; constructor(options: RequestOptions) { this.defaultOptions options; } updateOptions(options: PartialRequestOptions) { this.defaultOptions { ...this.defaultOptions, ...options, }; } async requestT(path: string, options: PartialRequestOptions {}): PromiseResponseDataT { const merged: RequestOptions { ...this.defaultOptions, ...options, url: path, }; const response await axios.request({ url: merged.url, method: merged.method ?? GET, params: merged.params, timeout: merged.timeout ?? 10000, }); return response.data as ResponseDataT; } }这段代码把“默认配置”和“本次请求覆盖配置”合并非常适合在大项目里统一管理请求逻辑。Partial的作用在这里体现得很明显调用方不需要每次都传完整的RequestOptions只要传需要覆盖的字段即可。4.3 配置 tsup.config.ts// packages/utils/tsup.config.ts import { defineConfig } from tsup; export default defineConfig({ entry: [src/index.ts], format: [esm, cjs], dts: true, sourcemap: true, clean: true, treeshake: true, outDir: dist, external: [axios], });配置项说明entry入口文件可传入数组构建多个入口。format同时输出 ESModule 和 CommonJS 两种格式。dts生成.d.ts类型声明文件这是库发布必备项。clean每次构建前清空dist防止旧产物残留。treeshake启用摇树优化。external把axios标记为外部依赖不打包进产物由使用方安装。再写src/index.ts// packages/utils/src/index.ts export * from ./types; export { HttpClient } from ./http;然后在package.json中添加脚本{ name: demo/utils, version: 0.1.0, main: ./dist/index.cjs, module: ./dist/index.js, types: ./dist/index.d.ts, exports: { .: { types: ./dist/index.d.ts, import: ./dist/index.js, require: ./dist/index.cjs } }, scripts: { build: tsup, typecheck: tsc --noEmit } }4.4 构建与验证在packages/utils目录运行pnpm build预期输出类似CLI Building entry: src/index.ts CLI Using tsconfig: tsconfig.json CLI tsup v8.x CLI Building entry: src/index.ts CLI Format: esm, cjs CLI dts: true CLI Clean: true CLI Sourcemap: true CLI Treeshake: true CLI External: axios CLI dist/index.js 1.23 KB CLI dist/index.cjs 1.45 KB CLI dist/index.d.ts 0.58 KB CLI dist/index.d.cts 0.58 KB CLI dist/index.js.map CLI dist/index.cjs.map CLI Done in 120ms可以看到tsup 在极短时间内同时产出 ESM、CJS 和类型声明文件。用 Webpack 打包库时这个流程往往需要配置output.library、externals、optimization.minimize还要额外引入dts-bundle-generator之类的工具生成声明文件。对比之下tsup 的优势非常直观。4.5 库的本地引用与调试为了让 Vite 业务项目直接引用本地库在packages/utils/package.json中确认exports字段完整后可以把库加入到业务项目的package.json或者使用 pnpm workspacepnpm --filter demo/app add demo/utilsworkspace:*后续在 Vite 业务项目里即可这样使用import { HttpClient } from demo/utils; const client new HttpClient({ url: , method: GET, timeout: 15000, }); client.updateOptions({ timeout: 20000 }); const result await client.request{ list: string[] }(/api/form/list);这就是一个可复用的封装模式库的构建交给 tsup业务消费交给 Vite职责边界非常清楚。5. 实战二用 Vite 搭建业务项目这一节进入业务项目层面。很多开发者最初接触 Vite 时的疑问是它能不能完全替代 Webpack答案是大多数场景可以。下面完整演示如何搭建一个 Vue3 TypeScript 业务项目并配置路径别名、开发代理、代码混淆与第三方富文本插件。5.1 初始化 Vue3 TS 项目可以使用官方脚手架cd packages pnpm create vite app --template vue-ts cd app pnpm install注意如果你在现有目录创建可能需要手动删除模板自带的示例文件。之后项目结构如下packages/app ├── src │ ├── components │ ├── views │ ├── router │ ├── api │ ├── App.vue │ └── main.ts ├── public ├── index.html ├── package.json └── vite.config.ts5.2 配置 Vite路径别名、代理、代码混淆vite.config.ts是 Vite 项目的核心配置相当于 Webpack 中webpack.config.jsbabel.config.js等文件的集合。// packages/app/vite.config.ts import { defineConfig } from vite; import vue from vitejs/plugin-vue; import { fileURLToPath, URL } from node:url; export default defineConfig({ plugins: [vue()], resolve: { alias: { : fileURLToPath(new URL(./src, import.meta.url)), }, }, server: { port: 5173, proxy: { /api: { target: http://localhost:8080, changeOrigin: true, rewrite: (path) path.replace(/^\/api/, ), }, }, }, build: { minify: esbuild, sourcemap: false, chunkSizeWarningLimit: 1500, rollupOptions: { output: { manualChunks: { vue-vendor: [vue, vue-router, pinia], editor-vendor: [wangeditor/editor, wangeditor/editor-for-vue], }, }, }, }, });这里重点解释几个配置项。server.proxy解决的是跨域问题。很多后端接口没有配 CORS前端请求/api/form/list?page1pagesize10时需要通过代理转发到真实服务。如果你的 Vite 控制台出现类似http proxy error的报错通常就是target地址不可达或代理路径重写规则不对排查思路在后面的常见问题中会展开。build.minify设为esbuild是 Vite 默认值生产构建时压缩代码如果你需要更强的代码混淆比如去掉 console、debugger、类名混淆可以考虑build: { minify: terser, terserOptions: { compress: { drop_console: true, drop_debugger: true, }, mangle: true, } }需要注意terser会比esbuild慢一些但对敏感逻辑的遮蔽效果更好。具体用哪个需要根据项目对体积、混淆程度、构建速度的需求权衡。rollupOptions.output.manualChunks可以把常用依赖拆成独立 chunk减少业务代码变化时用户重新下载依赖包的成本类似 Webpack 中的splitChunks。这里把 Vue 全家桶和富文本编辑器拆成两个独立 vendor。5.3 配置 TypeScript 路径别名在tsconfig.json中同步配置别名否则开发时 TS 会报找不到模块{ compilerOptions: { target: ES2020, useDefineForClassFields: true, module: ESNext, moduleResolution: Bundler, strict: true, jsx: preserve, resolveJsonModule: true, isolatedModules: true, esModuleInterop: true, lib: [ES2020, DOM, DOM.Iterable], skipLibCheck: true, baseUrl: ., paths: { /*: [src/*] } }, include: [src/**/*.ts, src/**/*.d.ts, src/**/*.vue] }注意paths里的/*要与vite.config.ts中的 alias 保持一致。很多同学只改了 vite config忘记改 tsconfig结果运行时正常、编辑器却报错。5.4 接入富文本编辑器等第三方库以 wangEditor 为例安装pnpm add wangeditor/editor wangeditor/editor-for-vue在组件中使用!-- packages/app/src/components/RichTextEditor.vue -- template div styleborder: 1px solid #ccc Toolbar styleborder-bottom: 1px solid #ccc :editoreditorRef :defaultConfigtoolbarConfig modesimple / Editor v-modelvalueHtml styleheight: 300px; overflow-y: hidden :defaultConfigeditorConfig modesimple onCreatedhandleCreated / /div /template script setup langts import { shallowRef, onBeforeUnmount } from vue; import { Editor, Toolbar } from wangeditor/editor-for-vue; import type { IDomEditor } from wangeditor/editor; const editorRef shallowRefIDomEditor(); const valueHtml ref(phello/p); const toolbarConfig {}; const editorConfig { placeholder: 请输入内容..., }; const handleCreated (editor: IDomEditor) { editorRef.value editor; }; onBeforeUnmount(() { editorRef.value?.destroy(); }); /script这个示例演示了 Vue3 TS 第三方富文本插件的基本接入方式。注意shallowRef的使用富文本编辑器实例往往包含大量内部对象用shallowRef可以避免深层响应式代理带来的性能问题。5.5 开发与构建验证在packages/app目录执行pnpm dev浏览器访问http://localhost:5173可以看到页面正常打开。修改App.vue的文字页面应秒级热更新。执行生产构建pnpm build pnpm previewVite 构建完成后dist目录会生成压缩后的静态资源。检查dist/assets下的 JS 文件如果配置了manualChunks你会看到类似vue-vendor.js、editor-vendor.js的文件这就是拆包生效的结果。6. 实战三Rolldown 赋能下的 Vite 构建实验如果说 tsup 和 Vite 是“现在就能用”的方案Rolldown 则是很多开发者关注的后备选项。目前 Rolldown 处于快速迭代期官方提供了实验性的rolldown-vite包用于体验下面演示如何把上面创建的 Vite 项目切换到 Rolldown 实验版。6.1 创建 Rolldown 实验项目mkdir rolldown-experiment cd rolldown-experiment pnpm init pnpm add -D rolldown-vite vitejs/plugin-vue typescript注意由于实验包版本变化很快安装前建议先查看 npm 上的最新版本与 peerDependencies。如果依赖冲突可以加上--ignore-workspace-root-check或在 pnpm-workspace.yaml 中单独设置。创建一个最小rolldown.config.ts// rolldown-experiment/rolldown.config.ts import { defineConfig } from rolldown-vite; import vue from vitejs/plugin-vue; export default defineConfig({ plugins: [vue()], resolve: { alias: { : new URL(./src, import.meta.url).pathname, }, }, build: { minify: esbuild, sourcemap: false, }, });rolldown-vite在设计上尽量兼容 Vite 的配置格式所以大部分 Vite 配置项可以直接复用这也是未来迁移成本较低的原因之一。6.2 在 Vite 项目中启用 rolldown-vite 实验在packages/app中临时切换{ scripts: { dev:rolldown: rolldown-vite, build:rolldown: rolldown-vite build } }然后运行pnpm dev:rolldown如果项目能正常启动说明 Vite 插件生态在 Rolldown 上至少有相当一部分可复用。这里需要提醒的是现阶段 Rolldown 对某些 Vite 插件的兼容性可能还有差异生产环境迁移前一定要做全量回归测试。6.3 Rolldown 与 Rollup 的关系简单总结Rollup 是 JS 编写的模块打包器具备强大的 tree-shaking 能力但大型项目构建性能受限Rolldown 用 Rust 重写内核目标是兼容 Rollup API 的同时获得接近 esbuild 的性能。Vite 生产构建长期以来依赖 Rollup一旦底层切换到 Rolldown开发与构建将共享同一套 Rust 引擎理论上能减少开发与生产环境的差异同时大幅缩短构建时间。对普通业务项目来说短期内不必强行迁移。你可以保留 Vite Rollup 的稳定方案同时用rolldown-vite做“备胎实验”。当依赖 Rolldown 的正式 Vite 版本发布后再评估是否切换风险更可控。7. 常见问题与排查思路无论是 Webpack 迁移到 Vite还是 tsup / Rolldown 使用中都会遇到一些高频报错。下面整理成表格并挑出几个典型问题详细展开。问题现象常见原因解决思路开发服务器启动即报http proxy error代理 target 不可达或 rewrite 规则错误检查后端服务地址、代理规则与端口启动报ERR_MODULE_NOT_FOUND: Cannot find package vite依赖未安装、node_modules 损坏或包管理器 workspace 解析异常执行pnpm install或pnpm install --force报错提示Cannot find package vite imported from 某文件用户把 Vite 作为全局命令而非本地依赖调用优先使用pnpm dev等本地 scripts构建产物中保留了注释未配置代码去除注释与压缩选项用 esbuild 或 terser 压缩并配置注释移除tsup 生成 dts 失败TS 配置中包含不兼容的moduleResolution切换到Bundler或NodeNext并检查include范围Vite 提示content not from webpack is served from public项目残留 Webpack 的 public 目录认知Vite 对 public 资源的处理方式不同了解 Vite public 目录的“原样拷贝”机制避免混淆开发环境正常但生产构建体积巨大缺少手动拆包或 tree-shaking 没有生效配置manualChunks、检查 sideEffects 字段rolldown-vite 插件不生效实验版插件兼容性尚未完善对照官方 issue 列表确认插件支持状态暂时保留 Rollup 构建下面重点展开三个典型的排查过程。7.1 Vite 代理报错http proxy error常见报错信息14:35:43 [vite] http proxy error: /api/form/list?page1pagesize10 aggregate这个报错一般出现在开发环境前端通过 Vite dev server 请求/api前缀接口。排查步骤单独用 curl 或浏览器访问http://localhost:8080/form/list?page1pagesize10确认后端服务是否存活。检查vite.config.ts中server.proxy[/api]的target是否正确路径是否有缺http://前缀。确认后端接口是否真的没有/api前缀如果有则不需要rewrite如果无则需要把/api去掉。如果代理目标本身存在 CORS 限制Vite 代理默认会帮你在服务端转发但仍可能出现错误需要确认后端对代理请求的鉴权方式。修改示例server: { proxy: { /api: { target: http://localhost:8080, changeOrigin: true, rewrite: (path) path.replace(/^\/api/, ), }, }, }7.2 ERR_MODULE_NOT_FOUND无法解析 vite 包报错完整信息形如Error [ERR_MODULE_NOT_FOUND]: Cannot find package vite imported from /path/to/project/vite.config.ts这种情况通常在直接执行node vite.config.ts或使用tsx vite.config.ts时出现。Vite 命令行入口必须由 Vite 自己加载正确的做法是运行pnpm dev或pnpm build而不是直接 node 执行。如果pnpm dev仍报同样的错多半是 node_modules 没有正确安装。此时执行pnpm install --force rm -rf node_modules pnpm install如果使用了 pnpm workspace特别要注意子包是否被 workspace 过滤掉。检查根目录pnpm-workspace.yamlpackages: - packages/*确保packages/app在这个范围内。7.3 Vite 与 public 目录从 webpack 带来的认知偏差有些项目从 webpack 迁移过来后会看到类似这样的日志content not from webpack is served from e:\sourcecode\saaswms\wms\public原因很简单webpack 本身没有内置 public 目录的概念很多脚手架用copy-webpack-plugin把 public 文件拷贝到产物。Vite 则默认把public目录视为静态资源目录构建时原样拷贝到dist根目录开发时直接通过根路径访问。迁移时要注意两点public 下的文件不应通过 import 引入否则会被当作模块处理应该直接以/xxx.png路径引用。如果 public 目录名与路由冲突比如路由/public/xx资源会被优先命中。这个“从 webpack 带来的认知偏差”很常见可以算作迁移老项目的隐藏坑之一。7.4 代码注释去除与混淆不少团队使用 Vite 时默认会认为生产构建会自动去掉注释其实不一定。Vite 默认使用 esbuild 压缩但如果你在build.terserOptions中没有配置注释并不一定会完全清理。更彻底的做法build: { minify: terser, terserOptions: { format: { comments: false, }, }, }如果连变量名也希望能进一步混淆需要谨慎过度混淆可能影响代码可读性和线上排错。建议仅对包含敏感逻辑的独立模块开启强混淆公共业务代码保持可读性降低售后与联调成本。8. 最佳实践与工程建议工具是服务于工程效率的选型不能只看单点构建速度。以下建议来自实际项目中的经验沉淀。8.1 建立清晰的工具边界现在很多团队在做一个项目时试图让一个工具完成所有事这是 Webpack “全家桶”模式带来的惯性。更合理的做法是库开发用 tsup业务项目用 Vite底层性能优化交给 Rolldown。每一层选最合适的工具而不是用一个巨型配置覆盖所有场景。8.2 保持 TS 配置一致避免打包器认知冲突无论使用 tsup 还是 Vite都要保证tsconfig.json、tsup 配置、vite 配置三者之间的路径别名与模块解析方式一致。特别是paths和alias建议使用同一份常量配置或者在根目录维护一个tsconfig.base.json由各子包继承。这样能避免开发环境正常、生产构建报模块找不到的经典问题。8.3 外部依赖尽量提升别重复打包在 tsup 的external中把 react、vue、axios 这类依赖排除掉可以减少库体积同时避免同一依赖被打包多份导致的状态不一致。业务项目中通过manualChunks拆包时也要注意拆分粒度拆得太细会带来过多的 HTTP 请求太粗则缓存利用率下降。8.4 插件安全与最小权限原则引入任何构建插件时比如 Vite 插件或 tsup 插件都要确认它来自可信维护方并查看最近一次更新记录。构建工具往往有执行本机命令的权限恶意插件可能导致供应链攻击。生产构建尽量固定插件版本并通过 lockfile 统一依赖。8.5 异常处理与日志规范在库和业务代码中做统一错误处理例如前面封装的HttpClient建议更进一步try { const data await client.request{ list: string[] }(/api/form/list); } catch (error) { console.error([http-client] request failed, error); throw new Error(请求失败请稍后重试); }日志规范看似与构建工具无关但构建产物中的sourcemap直接决定了线上日志的反向映射能力。生产环境建议开发与预发布保留 sourcemap正式环境按合规要求决定是否关闭或独立托管 sourcemap 文件。8.6 用 TypeScript 工具类型保持接口健壮在大型项目里接口类与Partial、Pick、Omit等工具类型是提升可维护性的核心手段。封装请求时不要把RequestOptions的所有字段都设成必填否则调用方每次都要传一堆无用参数也不要把所有字段都设成可选否则默认值逻辑会变得难以追踪。正确做法是给关键字段设置默认值并用Partial让更新配置变得更灵活。9. 迁移决策与踩坑清单最终给出一个实际可用的迁移清单。判断自己的项目是否应该从 Webpack 迁移到 TS tsup Vite Rolldown 组合拳可以对照下面几条项目是否有大量类型声明和接口逻辑如果是TS 一定是构建链路的中心。是否在维护 npm 库、组件库或工具函数集是就用 tsup。是否在维护面向用户的业务系统是业务侧优先选 Vite开发体验和插件生态足够成熟。是否对构建速度和产物体积有极致要求Rolldown 是关注方向但当前应谨慎实验不要直接作为生产首选项。是否有老旧 Webpack 插件依赖比如某些自研 loader迁移前评估替代方案如果找不到等价 Vite 插件就需要设计包装层。关于 Webpack 老项目最稳妥的迁移方式不是一次性替换而是把库层先拆出来用 tsup 构建业务层逐步切换 Vite公共配置抽成 shared config。历史上很多“Webpack 迁移失败”的案例并不是 Vite 不行而是迁移范围一次铺得太大导致排错成本失控。建议先挑一个非核心的子应用做试点跑通“库用 tsup、业务用 Vite、Rolldown 做实验”的流程再逐步扩展。真正有价值的不是某个工具而是团队能否根据自己的业务形态建立一套清晰、可维护、可持续演进的构建体系。