想象你要盖一栋楼。传统总包施工队(Webpack)会先把所有瓷砖、钢筋、水管从不同的工厂运到工地,再按图纸统一切割、拼接成预制板,最后整体安装。装配式施工队(Vite)则不同,它们先把最常用的标准构件用机器快速预制好,主体结构直接吊装标准件,哪个房间需要什么材料,再到现场临时取。前者胜在工序完整、生态成熟,后者胜在启动快、改动能精准反馈。 这就是前端两大构建工具的核心区别:Webpack 主张把所有模块先“打包”(bundle)成一个整体,Vite 则借助浏览器原生 ESM,让源码“按需加载”。本文会用同一套施工队比喻,带你理解打包原理、loader/plugin、开发体验、生产构建、性能取舍和迁移选型。学完之后,你不需要记住所有配置项,也能在项目启动前做出第一道技术决策。

岗位关联

无论你是训练模型还是开发 AI 应用,构建工具都决定着你交付的产品能否快速启动、稳定运行;搞懂这场对决,你选型时就不会凭感觉拍脑袋。

目录
  1. 可视化演示
  2. 1. 构建工具定位
  3. 2. 打包原理对比
  4. 3. 插件体系扩展
  5. 4. 开发体验差异
  6. 5. 生产构建能力
  7. 6. 性能与取舍
  8. 7. 选型与迁移
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

双流水线对比展示Vite与Webpack的构建差异:Webpack全量打包bundle vs Vite原生ESM按需加载,切换开发/生产模式查看冷启动速度和构建产物对比。

本节配有交互动效(进入视口后自动加载,约 3KB)。

开发模式冷启动对比 Vite利用浏览器原生ESM,按需加载模块,冷启动0.3秒 Webpack需全量打包bundle后启动,冷启动15秒,项目越大越慢 cold_start: Vite 0.3s vs Webpack 15s 开发模式:Vite快50倍

1. 构建工具定位

老工头接活时,第一件事不是问水泥多少钱一吨,而是问工地现状和交付标准。前端项目也一样,技术栈越来越复杂,JS、CSS、图片、字体、TypeScript、JSX 混在一起,浏览器根本认不全。构建工具就是那个“施工队总包”,负责把散落各处的源文件读懂、转换、合并,最后交付浏览器能直接运行的静态资源。

没有构建工具,你只能用 <script> 标签手动管理文件顺序,每加一个依赖都要小心翼翼。Webpack 出现后,把“谁是入口、谁依赖谁”画成一张完整的图纸,然后统一打包;Vite 则换了一条路,浏览器本来就能识别 ES Module,所以它只做“轻量调度”,把转换工作交给浏览器按需触发。

回到工地视角:Webpack 是“先运料再切割再整体装配”,Vite 是“标准件直接吊装、零碎材料现场加工”。定位不同,后续所有差异都从这里生长出来。

Build=Resolve→Transform→Bundle\text{Build} = \text{Resolve} \rightarrow \text{Transform} \rightarrow \text{Bundle}
这条公式把构建拆成三步:先找到模块在哪,再转换格式,最后打包输出。Webpack 三步全做,Vite 开发期只做前两步加依赖预构建。
  1. Resolve(解析定位)根据 import 路径找到模块的真实文件地址,相当于施工队先找到每批材料在仓库里的位置。
    Resolve:import path→absolute file path\text{Resolve}: \text{import path} \rightarrow \text{absolute file path}
  2. Transform(转换加工)把 TypeScript、Sass 等浏览器不认识的内容转成 JS/CSS,相当于把原材料切割成标准件。
    Transform:TS/Sass/JSX→Browser-friendly Code\text{Transform}: \text{TS/Sass/JSX} \rightarrow \text{Browser-friendly Code}
  3. Bundle(打包输出)把许多模块合并成少量文件,减少浏览器请求数,相当于把所有材料装进集装箱再发车。
    Bundle:∑Modulei→Chunk files\text{Bundle}: \sum \text{Module}_i \rightarrow \text{Chunk files}

2. 打包原理对比

同样是盖十层楼,总包队会把所有楼层需要的钢材一次性进场,因为后面要统一浇筑;装配式队伍则只需先吊装主体框架,层内隔断等住进去再装。Webpack 开发服务器启动时,会从入口文件出发,深度优先遍历整张依赖图,把所有模块全部编译并合并成 bundle。模块越多,启动前要干的活越多,所以“冷启动”偏慢。

Vite 则抓住了一个关键事实:现代浏览器已经原生支持 ESM。开发时,Vite 不需要把所有源码打包,只对 node_modules 里的依赖用 esbuild 做一次预构建,把它们转成标准 ESM 和统一 chunk;至于项目源码,浏览器发多少请求,Vite 就按需转换多少。首次打开页面时,只有到达首屏的那部分模块会被处理。

用施工队的话说:Webpack 是“整栋楼全部材料先到场再开工”,Vite 是“先立主体、按需送料”。所以 Vite 在开发期天然轻盈,但这不代表它不需要预构建——依赖还是要先统一成标准件。

Twebpack=∑i=1Nti+tbundle(N),Tvite=tpre(D)+Tfirst(n)T_{\text{webpack}} = \sum_{i=1}^{N} t_i + t_{\text{bundle}}(N), \quad T_{\text{vite}} = t_{\text{pre}}(D) + T_{\text{first}}(n)
冷启动时间差异的关键:Webpack 与总模块数 N 相关,Vite 主要与预构建依赖数 D 和首屏模块数 n 相关。
  1. Webpack 全量成本每个模块都要做转换,最后还要额外花时间把 N 个模块捆成 chunk,所以模块越多启动越慢。
    Twebpack=∑i=1Nti+tbundle(N)T_{\text{webpack}} = \sum_{i=1}^{N} t_i + t_{\text{bundle}}(N)
  2. Vite 预构建成本只对依赖集合 D 做一次统一预构建,而不处理全部源码。
    tpre(D)=esbuild translate all dependenciest_{\text{pre}}(D) = \text{esbuild translate all dependencies}
  3. Vite 首屏成本浏览器请求哪些模块,才转换哪些模块,工作量和首屏模块数 n 成正比。
    Tfirst(n)=∑j=1ntjT_{\text{first}}(n) = \sum_{j=1}^{n} t_j

3. 插件体系扩展

工地上会遇到各种特殊材料:有的瓷砖需要水刀切割,有的管线需要防火处理。Webpack 里的 loader 就是这些“特种工种师傅”,它按照规则处理某类文件,比如 babel-loader 处理 JS 语法,sass-loader 处理 SCSS。loader 的工作单位单一且清晰:输入一个文件,输出一个转换后的文件。

plugin 则是“监理加调度系统”。它不直接处理单份材料,而是监听整个工地的施工节点:开始挖地基、浇筑完成、验收通过……比如 HtmlWebpackPlugin 在构建结束后自动生成 HTML,MiniCssExtractPlugin 把 CSS 抽成独立文件。Vite 在插件模型上刻意向 Rollup 靠拢,所以很多 Rollup 插件可以直接复用,同时它也有自己的 Vite 特有钩子。

对于想扩展构建能力的人来说,Webpack 的插件生态更像“老牌工头手里的一整本施工规范”,Vite 则像“新队伍背靠着现代机械和通用接口”。生态没有绝对好坏,只看你的项目需要哪些工种。

Asset=LoaderChain(Source)→Bundle\text{Asset} = \text{LoaderChain}(\text{Source}) \rightarrow \text{Bundle}
loader 负责把源文件变成可打包的模块,plugin 则在整个流程上做横切增强。两者是“切割师傅”和“调度监理”的关系。
  1. LoaderChain 转换链源文件要经过多个 loader 依次加工,例如 SCSS → CSS → 注入 JS,每个 loader 只做一件事。
    LoaderChain(S)=L1(L2(…Lk(S)… ))\text{LoaderChain}(S) = L_1(L_2(\dots L_k(S)\dots))
  2. Plugin 接管产物loader 处理完模块后,plugin 在打包生命周期中监听钩子,最终影响 asset 的生成方式。
    Asset=PluginHooks(LoaderOutput)\text{Asset} = \text{PluginHooks}(\text{LoaderOutput})

4. 开发体验差异

开发时最怕两件事:第一是敲下启动命令后要等半分钟才看到页面;第二是改一行代码,整页刷新,之前调试的状态全部丢失。Webpack 像总包队,每次开工都要把所有材料重新点一遍,即使只改了一面墙,也得重新过一遍图纸。Vite 则像装配式工地,依赖预构建只做一次并缓存,之后源码按需转换,所以冷启动极快。

HMR(热模块替换)是另一个重要战场。Webpack 本身也支持 HMR,但模块越多,更新时需要重建的依赖范围越大;Vite 基于原生 ESM,修改一个模块时,可以精确地让浏览器重新请求那一个模块,再通过 WebSocket 推送更新,仿佛只换掉一块坏砖,而不是拆掉整面墙。

所以很多开发者第一次用 Vite 的感受是“快到没感觉”。但要注意,这种快是开发期体验,和最终线上性能没有直接关系。

tHMRVite≈tupdate(1)+tpush(1),tHMRWebpack≈trecompile(N)t_{\text{HMR}}^{\text{Vite}} \approx t_{\text{update}}(1) + t_{\text{push}}(1), \quad t_{\text{HMR}}^{\text{Webpack}} \approx t_{\text{recompile}}(N)
Vite 的 HMR 成本与当前改动模块数强相关,Webpack 的 HMR 成本仍会随整体模块规模上升。
  1. Vite 单点更新浏览器只重新请求被修改的模块,然后通过 WebSocket 推送更新指令,工作量近似常数。
    tupdate(1)≪trecompile(N)t_{\text{update}}(1) \ll t_{\text{recompile}}(N)
  2. Webpack 图级重构即使只改一个文件,也要在依赖图上重新计算受影响范围,项目越大重建范围越大。
    trecompile(N)∝Nt_{\text{recompile}}(N) \propto N

5. 生产构建能力

施工队再快,也不能靠“临时吊装”交付整栋楼,最后还是要做精装修、验收和交付。Vite 生产构建时没有继续用 esbuild,而是切换成 Rollup 作为主打包器。Rollup 打包经验更成熟,尤其擅长 Tree Shaking、代码分割和产物优化,就像一支专业的精装收尾队,能把每个房间的家具都安排得明明白白。

Tree Shaking 是“把不需要的家具提前扔出清单”。如果你引入了一个工具库只用了其中一个函数,Webpack 和 Rollup 都会尝试按静态语法分析,把没被用到的导出从最终产物中删掉。代码分割则把原来一个大 bundle 拆成多个 chunk,做到“首屏只加载需要的,其他路由后来再取”,这相当于把一整车家具拆成按房间配送的小包裹。

回到比喻:Vite 的开发队负责“快速盖”,Rollup 精装队负责“体面交付”。Webpack 的总包队则选择把开发和交付两件事都揽在自己身上,因此它的生产配置也更庞大、更灵活。

Sfinal=∑m∈Us(m)+OruntimeS_{\text{final}} = \sum_{m \in \mathcal{U}} s(m) + O_{\text{runtime}}
最终产物体积只与真正被使用的模块集合 \(\mathcal{U}\) 相关,再加上少量运行时开销。这就是 Tree Shaking 和代码分割优化出来的结果。
  1. Used 集合\(\mathcal{U}\) 表示从入口出发、真正被引用到的导出集合,没进集合的模块都会被移除。
    U={m∣m is reachable and used}\mathcal{U} = \{ m \mid m \text{ is reachable and used} \}
  2. 最终体积把每个使用模块的体积相加,再叠加不可消除的运行时开销,就是 bundle 的优化后体积。
    Sfinal=∑m∈Us(m)+OruntimeS_{\text{final}} = \sum_{m \in \mathcal{U}} s(m) + O_{\text{runtime}}

6. 性能与取舍

工地越大,问题越复杂。Webpack 的总包模式在小型项目里显得笨重,但在大型项目里反而有稳定优势:它已经把整个依赖图握在手里,可以做更精细的代码分割、公共依赖提取和长缓存策略。Vite 的开发服务器很轻,但当项目有上百个页面、上千个模块时,浏览器按需请求的模块数量也会上升,首屏请求瀑布流可能变得又深又长。

内存占用也值得关注。Webpack 需要维护整张模块图和转换结果,模块越多内存越高;Vite 把大量转换工作交给浏览器,Node 侧压力较小,但依赖预构建如果遇到超大 monorepo 或复杂 CJS 依赖,esbuild 预构建也可能成为新的瓶颈。没有“永远更快”的工具,只有“更适合当前规模”的选型。

因此,选型不能只看演示项目里的“秒开”,还要站在项目的生命周期上看:团队熟不熟悉、插件够不够用、老浏览器要不要兼容、构建链路要不要深度定制。这些变量叠加起来,才是真正的性价比。

Cwebpack=αN+βE,Cvite=αnpage+γDC_{\text{webpack}} = \alpha N + \beta E, \quad C_{\text{vite}} = \alpha n_{\text{page}} + \gamma D
复杂度模型:Webpack 的构建成本随总模块数 N 和依赖边数 E 增长,Vite 的增量成本更依赖单页模块数 n 和依赖复杂度 D。
  1. Webpack 图级复杂度每个模块都要解析、转换、连接,边越多依赖关系越复杂,成本越高。
    Cwebpack=αN+βEC_{\text{webpack}} = \alpha N + \beta E
  2. Vite 页面级复杂度开发时主要处理当前页面涉及的模块,同时还要处理依赖预构建的复杂度。
    Cvite=αnpage+γDC_{\text{vite}} = \alpha n_{\text{page}} + \gamma D

7. 选型与迁移

最后回到甲方提问:我到底该用哪个施工队?答案取决于你要盖的是什么样的楼。如果是新项目、团队愿意接受新工具、目标用户使用现代浏览器,Vite 的开发体验几乎是降维打击,从脚手架到开发服务器都干净利落。如果项目已经运行多年,大量老插件、老配置、特殊构建需求绑定在 Webpack 上,强行换队伍反而会造成迁移事故。

渐进迁移是一个折中方案。你不必把整个项目一夜推翻,可以先把某个独立页面或子应用切到 Vite,验证插件兼容性和产物一致性;也可以保留 Webpack 作为生产构建,只在开发期尝试 Vite。常见的坑包括:CommonJS 三方依赖需要预构建、Node 版本不满足、某些 Webpack loader 没有 Vite 等价物、代码分割策略导致产物变化等。每次迁移都像旧楼改造,要先做结构评估,再一层层换装。

说到底,Vite 和 Webpack 不是敌人,而是同一道选择题的两种解。理解它们背后的“施工哲学”,比记住一百条配置更值钱。

Score=w1⋅Speed+w2⋅Ecosystem+w3⋅Stability\text{Score} = w_1 \cdot \text{Speed} + w_2 \cdot \text{Ecosystem} + w_3 \cdot \text{Stability}
选型不是非黑即白,而是给速度、生态、稳定性三个维度分配权重,再根据项目阶段做决策。
  1. 速度权重开发启动、HMR、构建时间是否影响团队效率,新项目可以给更高权重。
    Speed=α⋅1Tstart+Thmr\text{Speed} = \alpha \cdot \frac{1}{T_{\text{start}} + T_{\text{hmr}}}
  2. 生态权重现有插件、loader、团队经验能否覆盖业务需求,老项目往往更依赖生态。
    Ecosystem=β⋅Coverage\text{Ecosystem} = \beta \cdot \text{Coverage}
  3. 稳定性权重生产产物一致性、CI 可复现性、历史包袱决定了能不能平稳切换。
    Stability=γ⋅Risk−1\text{Stability} = \gamma \cdot \text{Risk}^{-1}

AI 应用场景

AI 模型演示沙盒(Playground)

阶段:模型展示与前端交付

解决的问题:AI 团队常把模型封装成 Web Demo,传统 Webpack 冷启动慢,产品经理每看一次改动都要等;Vite 让本地开发秒级启动,把模型演示平台的迭代周期从“分钟级”降到“秒级”。

具体案例:某大模型团队用 Vite 搭建模型对话 Playground,配合 HMR 快速调 prompt 模板和 UI 组件;生产环境再用 Rollup 打包并做代码分割,减少首屏加载时间。

模型评估平台的数据大屏

阶段:评估结果可视化

解决的问题:模型评估要展示大量图表、指标卡和日志流,构建产物过大容易拖慢首屏。通过 Webpack 的代码分割、公共依赖提取和 Tree Shaking,可以把首屏 bundle 体积降到最低。

具体案例:某 MLOps 平台坚持用 Webpack 构建评估大屏,因为团队需要深度自定义 chunk 命名和缓存策略,并兼容内部老浏览器环境。

AI 平台的 CI/CD 构建优化

阶段:持续集成与发布

解决的问题:每次训练任务结束都要重新构建前端静态资源,CI 构建时间直接影响实验反馈。团队可以用构建速度分析插件定位瓶颈,再决定是否把纯展示型子应用迁移到 Vite,保留核心管理后台在 Webpack 上。

具体案例:某 AI 中台团队通过拆分子应用和渐进迁移,将 CI 构建时间从 12 分钟降到 4 分钟,同时保持生产产物稳定。

Python 演示

python34 行
import randomfrom collections import deque def make_dependency_graph(modules, deps):    graph = {m: [] for m in range(modules)}    for m in range(modules // 2):        for _ in range(deps):            nxt = m + 1 + random.randint(0, max(1, (modules - m - 1) // 4))            if nxt < modules:                graph[m].append(nxt)    return graph def reachable(graph, entry):    seen = set()    queue = deque([entry])    while queue:        node = queue.popleft()        if node in seen:            continue        seen.add(node)        queue.extend(graph[node])    return seen def compare(modules=1000, deps=3, prebuilt=50):    random.seed(0)    graph = make_dependency_graph(modules, deps)    webpack_units = modules + modules // 10    vite_units = len(reachable(graph, 0)) + prebuilt    print("Webpack 工作单元:", webpack_units)    print("Vite 工作单元:", vite_units)    print("模拟加速比: {:.2f}x".format(webpack_units / vite_units)) if __name__ == "__main__":    compare()
目的:用随机依赖图模拟 Webpack 全量打包与 Vite 按需加载的工作量差异,帮助理解两者冷启动速度差距的来源。
  1. def make_dependency_graph(modules, deps):生成一张模拟项目依赖图,每个模块指向后面的若干模块,避免环。
  2. graph = {m: [] for m in range(modules)}用字典表示每个模块的依赖列表。
  3. if nxt < modules:只保留仍在模块范围内的依赖边,防止越界。
  4. def reachable(graph, entry):从入口模块出发做 BFS,求首屏按需加载需要访问多少模块。
  5. webpack_units = modules + modules // 10模拟 Webpack 要处理全部模块,还要额外付出打包开销。
  6. vite_units = len(reachable(graph, 0)) + prebuilt模拟 Vite 只处理首屏可达模块,并加上依赖预构建成本。

常见误区

误区别人说“Vite 比 Webpack 快”,我就以为生产打包时 Vite 也一定秒杀 Webpack,结果一测发现并没有快多少,甚至更慢。

正解Vite 的开发快来自浏览器原生 ESM 和 esbuild 预构建,这是“现场吊装”的功劳;但生产构建要交付最稳的产物,Vite 会切换到 Rollup 做精细打包。就像装配式建筑现场拼装快,但精装收尾未必比传统装修队省时。

为何常见:大家容易把“启动快”这个体验泛化成“所有环节都快”,忽略了开发链路和生产链路的工具并不相同。

误区很多初学者以为 loader 和 plugin 都用来“处理文件”,可以混着用,配置的时候也容易互相替代。

正解loader 负责把单个源文件从 A 格式转成 B 格式,是“特种工种师傅”;plugin 负责监听构建生命周期,做全局性的调度和增强,是“监理加调度系统”。两者职责不同,不能互相替代。

为何常见:因为在配置里它们都出现在 modules/rules 和 plugins 两个相邻区域,名字又都有“处理”的意味,所以容易混淆。

误区听到“Vite 借助原生 ESM 按需加载”,就以为 Vite 开发时什么都不打包,所有文件原样发给浏览器。

正解Vite 依然会对 node_modules 中的依赖做 esbuild 预构建,把 CommonJS 转成 ESM、合并成数量更少的 chunk;只是项目源码不整体打包,等浏览器请求时再按需转换。它不是不打包,而是“只预打包依赖,不打包源码”。

为何常见:“不打包”这个说法太有传播力,让人忽略了 esbuild 预构建正是 Vite 启动快的关键之一。

误区有人觉得 Vite 配置比 Webpack 简洁,于是直接把 `webpack.config.js` 扔掉,改个启动命令就上线,结果一堆兼容问题。

正解迁移要先核对 Node 版本、浏览器目标、CommonJS 依赖、Rollup 插件兼容性、代码分割策略和生产产物差异。旧楼改造要先做结构评估,而不是直接换施工队。

为何常见:Vite 的“零配置体验”会让人低估它背后对现代浏览器和 ESM 生态的强依赖,老项目里这些前提往往并不满足。

误区很多前端新人觉得选 Webpack 还是 Vite 只是“敲命令时爽不爽”的区别,线上性能都一样。

正解生产构建中的 Tree Shaking、代码分割、资源压缩和缓存策略都会直接影响首屏体积和加载速度。工具选择会决定你能否方便地做这些优化,所以构建工具实际上是线上性能的上游。

为何常见:开发和生产是两条链路,用户看到的是生成后的产物,容易忽略产物质量从哪来。

面试题

Q1. Webpack 的核心产物通常是什么?

单选题 · easy

  • A.打包后的一个或多个 bundle 文件← 正确答案
  • B.保持原样的一份源码目录结构
  • C.浏览器可直接运行的 TypeScript 源码
  • D.一个专门用于发布的 npm 包

答案:A。Webpack 的核心思路是把所有模块打包成 bundle,浏览器最终加载的是打包后的文件。源码目录结构和 TypeScript 源码都不能直接作为线上产物,npm 包则是另一种分发形式,不是 Webpack 的核心产物。

Q2. Vite 开发服务器为什么冷启动比 Webpack 快?

单选题 · easy

  • A.它提前把所有模块编译成单个 bundle
  • B.它使用浏览器原生 ESM 按需加载源码← 正确答案
  • C.它完全不需要处理 node_modules
  • D.它把源码全部复制到内存中

答案:B。Vite 开发时利用浏览器原生 ESM,源码不整体打包,浏览器请求哪个模块就转换哪个模块。它仍然会对 node_modules 做 esbuild 预构建,所以 C 错;A 描述的是 Webpack 的做法。

Q3. loader 在 Webpack 中的主要职责是什么?

单选题 · easy

  • A.监听构建生命周期并生成额外文件
  • B.把一种模块文件转换成另一种模块← 正确答案
  • C.自动下载 npm 第三方依赖
  • D.对 bundle 做代码压缩和混淆

答案:B。loader 是“特种工种师傅”,核心职责是把源文件从一种格式转成另一种模块格式。监听生命周期和生成额外文件是 plugin 的事;下载依赖由包管理器负责;代码压缩通常由专门的 plugin 或压缩器完成。

Q4. 下面哪些属于 Vite 生产构建阶段会使用的特性或工具?

多选题 · mid

  • A.Rollup 打包← 正确答案
  • B.代码分割← 正确答案
  • C.esbuild 依赖预构建
  • D.Tree Shaking← 正确答案

答案:ABD。Vite 生产构建使用 Rollup 作为主打包器,支持代码分割和 Tree Shaking,最终生成优化后的静态产物。esbuild 依赖预构建主要发生在开发服务器启动阶段,不是生产构建阶段的核心流程。

Q5. 关于 HMR(热模块替换),下列说法最准确的是?

单选题 · mid

  • A.Webpack 无法实现 HMR
  • B.Vite 的 HMR 只对 CSS 生效
  • C.修改一个模块时按需更新该模块,而不是整页刷新← 正确答案
  • D.HMR 只有在生产环境才生效

答案:C。HMR 的价值在于开发时修改模块后只替换变更部分,保留页面状态。Webpack 也支持 HMR,Vite 的 HMR 不只针对 CSS,HMR 也只用于开发环境,因此 A、B、D 都是错的。

Q6. 大型项目从 Webpack 迁移到 Vite 时,哪种做法最稳妥?

单选题 · mid

  • A.一次性重写全部业务代码
  • B.先引入 Vite 的依赖预构建再迁移配置
  • C.保留 Webpack,用 Vite 构建整个生产包
  • D.先小范围试点,兼容插件和构建产物后渐进迁移← 正确答案

答案:D。迁移本质是旧楼改造,小范围试点可以提前暴露插件兼容、依赖格式和生产产物差异,再逐步扩大范围。一次性重写风险极高;同时维护两套构建链路也需要清晰边界,不是简单保留一种再做生产。

Q7. 关于 Vite 的依赖预构建(esbuild),说法正确的有?

多选题 · hard

  • A.将 CommonJS 依赖转换成 ESM← 正确答案
  • B.把多个内部模块合并,减少浏览器请求数← 正确答案
  • C.每次页面请求时都重新转换所有源码
  • D.依赖预构建结果可以缓存← 正确答案

答案:ABD。esbuild 预构建的核心目标是把依赖转成标准 ESM,并通过合并模块减少请求数,结果可以持久化缓存。它只处理依赖,不处理项目源码,因此不会每次重新转换所有源码,C 错。

Q8. Webpack plugin 与 loader 的核心区别是什么?

单选题 · hard

  • A.loader 负责打包,plugin 负责压缩
  • B.plugin 可以访问编译生命周期,loader 负责模块转换← 正确答案
  • C.loader 只能处理 JS,plugin 只能处理 CSS
  • D.plugin 在 Webpack 5 中已被废弃

答案:B。plugin 的核心能力是挂钩编译生命周期,做全局增强;loader 的职责是文件级转换。loader 不只处理 JS,plugin 也不只处理 CSS,plugin 也没有被废弃。A 把职责说反了。

Q9. 在大型老项目中,Webpack 相对 Vite 仍可能更受欢迎的原因是什么?

单选题 · mid

  • A.启动速度一定比 Vite 快
  • B.插件生态成熟稳定,兼容老项目多← 正确答案
  • C.完全不依赖 Node 环境
  • D.不需要任何配置就能支持所有文件

答案:B。Webpack 在长期发展中积累了庞大而稳定的插件和 loader 生态,很多老项目深度依赖这些自定义构建能力。它在启动速度上不一定占优,而且同样依赖 Node 环境,也不是零配置。

Q10. 要让 Webpack Tree Shaking 真正生效,通常需要哪些条件配合?

多选题 · extreme

  • A.ESM 语法(import/export)← 正确答案
  • B.sideEffects: false 标记← 正确答案
  • C.CommonJS 格式的依赖
  • D.external 第三方依赖

答案:AB。Tree Shaking 依赖静态语法分析,只有 ESM 的 import/export 才能被可靠识别;package.json 中的 sideEffects: false 告诉打包器可以安全删除未使用模块。CommonJS 是动态模块系统,难以静态分析,external 只是把依赖排除出打包范围,两者都不能帮助 Tree Shaking。