Webpack构建效率优化实战:从启动加速到产物体积压缩全指南
搞过大型前端项目的人应该都有过这种经历早上刚打开电脑准备改两行代码结果npm run dev跑了一分多钟热更新点一下要等好几秒甚至十几秒才反映到浏览器里。等到项目上了 CI构建一次五六分钟起步产出十几个 MB 的静态文件整个团队每天都在等编译一天算下来浪费的时间其实非常惊人。我自己这几年从 Webpack 3 一路用到现在从纯 JavaScript 项目到 Vue、React、TypeScript 全上齐的大型应用在构建效率优化这件事上踩过太多坑也积累了不少真正有效的方案。这篇就把我实际验证过的优化思路、操作步骤和踩坑记录整理出来希望能让正在被构建速度折磨的同学少走点弯路。构建效率优化到底在优化什么通俗点说就是让你从“保存代码”到“浏览器看到效果”这段时间尽量短同时让最终产出的文件体积尽量小、加载尽量快。它既影响开发体验也直接影响线上性能属于性能优化链条里非常前端、非常基础的一环。适合谁看不管你是前端开发、全栈工程师还是刚开始接触工程化的小白只要你用过构建工具、觉得项目越来越慢这篇内容应该都能帮上忙。下面我先从整体设计思路讲起再逐步拆解具体操作。1. 内容整体设计与思路拆解1.1 先搞明白构建慢在哪里任何优化动作之前一定要先找到瓶颈否则就是瞎忙。构建过程可以大致拆成几个阶段依赖解析、代码编译、文件打包、代码压缩、文件写入。不同项目卡点不一样有的卡在依赖解析有的卡在压缩有的卡在磁盘 I/O。我记得曾经接管过一个老项目dev 启动要 80 多秒第一反应以为是 webpack 配置写得太重结果用工具一看光解析moment、lodash这种大依赖就花了 30 秒再加上项目里到处都是import * as xxx from /utils这种全量引入模块数量直接逼近两万个编译当然慢。所以第一步永远是量化。自己手动掐表不够靠谱我通常用两种方式speed-measure-webpack-plugin能展示每个 loader、插件、最小耗时的插件在构建中的耗时分布。虽然这个插件新版对 webpack 5 支持上偶尔有坑不过实测大部分项目还能跑能帮你快速定位是 loader 耗时高还是插件耗时高。webpack-bundle-analyzer分析产物体积配合stats.json文件可以精确看到每个模块、每个 chunk 的体积判断是不是某个库打得太肥。我提个建议优化不是一口气做完的每次只做一个小改动改完对比一下耗时数据。比如这次只做路由懒加载下次只做缓存优化这样你能清楚看到每项优化的具体收益出了问题也方便回退。1.2 开发体验与生产构建不是一回事很多新手会用一个配置同时服务 dev 和 build结果两边都别扭。实际上开发环境和生产构建的目标完全不同。开发环境追求最快的启动速度和最短的热更新时间。不需要太激进的压缩不需要过度拆包甚至有些性能开销大的插件可以关掉。生产构建追求最小的产物体积、最优的缓存策略和最合理的包拆分。它可以慢一点因为有 CI 兜底但没有必要让开发人员天天等。这个思路影响整个方案选型。我之前见过有人为了让 dev 启动变快把生产构建里用到的所有优化插件全关掉结果上线时被 AI 保险公司卡住又跑了一遍全量构建白白花了二十分钟。所以建议从一开始就建立dev 模式配置和prod 模式配置两者继承公共部分只覆盖不同目标。这样后面每次优化都心里有数。1.3 构建工具选型还是得看场景现在前端构建工具很多Webpack、Vite、Turbopack、Rspack、esbuild、Rollup……没有必要盲目跟风。如果你维护的是一个存量项目Webpack 已经跑了两年配置和插件都成熟那最优解通常是在 Webpack 内部做优化而不是推倒重来换 Vite。如果你是新项目或者团队对构建速度极其敏感那 Vite 或者 Rspack 是更好的选择。这里有个很容易踩的坑Webpack 5 的 persistent cache 和文件名 hash 的关系。如果你用了持久化缓存同时又用contenthash做文件指纹要注意缓存是否会让 hash 失效或导致旧文件不更新。我遇到过一次诡异的线上 CSS 不更新查了半天发现是 webpack 缓存把MiniCssExtractPlugin的结果给缓存了导致 contenthash 没变浏览器拿的还是老 CSS。解决办法是确认 cache 的 version 与构建配置强相关或者干脆在关键环境下关闭某个环节的缓存具体后面讲。1.4 优化的核心原则减少无效工作复用已有成果构建慢的本质是重复做了大量无用功。比如每次启动都要全量解析所有文件每次编译都要重新压缩所有代码每次 CI 都要从零跑一遍依赖安装。所以优化的核心就两条减少编译范围能不编译的就不编译能用缓存复用的绝不动。并行代替串行多个不互相依赖的任务尽量同时跑充分利用 CPU 多核。后面所有方案基本都是围绕这两条主线展开。只要逻辑想通了具体用哪个插件、哪个配置其实都是顺手的事。2. 核心细节解析与实操要点2.1 模块解析加速别再让构建工具大海捞针Webpack 解析模块依赖时默认会走一套完整的解析流程。你可以限制它的搜索范围告诉它哪些地方不用看。核心配置如下// webpack.config.js module.exports { resolve: { extensions: [.js, .jsx, .ts, .tsx, .vue, .json], modules: [path.resolve(__dirname, src), node_modules], alias: { : path.resolve(__dirname, src), }, symlinks: false, }, module: { rules: [ { test: /\.(js|jsx|ts|tsx|vue)$/, include: path.resolve(__dirname, src), exclude: /node_modules/, use: [...], }, ], }, };几点思考extensions别设置太多每个扩展名都会参与判断。只保留实际用到的文件类型不要.js.ts.tsx都堆着更不要加.wasm这种冷门。alias是双刃剑。一方面能让/xxx这种写法生效另一方面也能把某些库强制指向特定版本入口比如react可以指到react/cjs/react.development.js。但用 alias 时必须清楚是否会把某个依赖引入两份否则体积反而变大。include比exclude更重要。rule 里只处理src下面的文件node_modules基本不处理。这样 loader 执行的文件数量会大幅下降。我在一个中型项目里把所有 loader 都加上了include: src启动速度快了大约 25%。2.2 让 loader 做更少的事配好 js/ts 编译范围babel-loader或ts-loader是慢的源头之一。优化思路有这么几条开启缓存。babel-loader可以用cacheDirectory: truets-loader可以用transpileOnly: true配合fork-ts-checker-webpack-plugin做类型检查。注意transpileOnly会跳过类型检查必须单独做类型检查否则你的类型错误会被吞掉。尽量用esbuild-loader或swc-loader替代 babel/ts-loader。如果你项目里没有太多自定义 babel 插件esbuild-loader能把编译速度提升一个量级。但要注意esbuild对个别语法和降级处理不那么严格上线前还是要留意兼容性。别在 loader 里做多余的事。比如eslint-loader在编译时又跑 lint 又跑 autofix开发期建议把 lint 和编译分离只提交前检查。我这里给一个 babel-loader 的参考配置{ test: /\.(js|jsx|mjs)$/, exclude: /node_modules/, use: [ { loader: babel-loader, options: { cacheDirectory: true, cacheCompression: false, presets: [ [babel/preset-env, { targets: 0.25%, not dead }], babel/preset-react, ], plugins: [babel/plugin-transform-runtime], }, }, ], }cacheCompression: false能减少缓存写入时的压缩时间代价是缓存文件更大一些但一般开发环境无所谓。这个配置我用了很久实测缓存命中后编译速度能提升 40% 以上。2.3 代码分割别把所有东西都塞进一个大 bundle代码分割的意义有两个一是减少首屏体积二是利用浏览器缓存让不常变的依赖长期不动。最朴素的方案就是按路由拆分// 路由懒加载示例 const Home () import(/pages/Home); const About () import(/pages/About);看似简单但很多项目做完了路由懒加载依然慢原因是第三方依赖全被分到了一个巨大的vendor包里而且一直在变。我建议把 dependencies 里的稳定依赖单独抽成vendorchunk再通过SplitChunksPlugin控制一下最小体积阈值。optimization: { splitChunks: { chunks: all, cacheGroups: { vendors: { test: /[\\/]node_modules[\\/]/, name: vendors, priority: 10, chunks: all, }, commons: { name: commons, minChunks: 2, priority: 5, chunks: all, }, }, }, }这里要注意name不能固定死不变否则每次构建生成相同 chunk 名内容变化时浏览器缓存会失效。更稳的做法是配合contenthash做文件名output: { filename: [name].[contenthash:8].js, chunkFilename: [name].[contenthash:8].chunk.js, }生产环境用 contenthash 的意义在于只要内容没变文件名就不变浏览器能直接命中缓存。所以每次构建生成的vendor文件 hash 保持稳定是好事反过来如果你改了业务代码业务 chunk 的 hash 变化才合理。2.4 缓存策略让 Webpack 记住已经做过的事Webpack 5 原生支持持久化缓存配置非常简单module.exports { cache: { type: filesystem, buildDependencies: { config: [__filename], }, }, };这能让二次构建只重新编译变化的部分启动速度提升非常明显。我自己的项目里开启前后 dev 启动时间从 60 秒降到 25 秒左右。但要注意几点buildDependencies.config必须写上否则你改了 webpack 配置但缓存还在可能出现改配置不生效的诡案。环境切换时建议换缓存目录。dev 和 prod 的缓存可以分开不然容易出现 dev 的缓存导致 prod 构建结果不对。CI 环境里缓存要持久化比如在 GitLab CI 里把node_modules/.cache作为缓存目录上传这样每次流水线可以复用上一次的缓存效果很好。这里特别提醒如果项目里用了fork-ts-checker-webpack-plugin它自己也有一份缓存路径在node_modules/.cache/ts-loader如果遇到类型检查不更新可以手动清一次缓存。这类“缓存过多连锁问题”我后面在问题排查时会细说。2.5 多进程构建榨干 CPU 的每一颗核心对于大型项目串行编译会很亏因为现代 CPU 多核基本都是闲置的。常见的多进程方案thread-loader把 loader 的工作放到 worker 池里执行适合 babel-loader、ts-loader 这种 CPU 密集型的 loader。terser-webpack-plugin的parallel参数默认就是 true会自动开启多进程压缩但有时会被某些配置覆盖掉建议显式写上。esbuild压缩如果你接受 esbuild 做代码压缩它的压缩速度远超 terser常常能把压缩阶段时间缩小到原来的十分之一。一个 thread-loader 的配置示例module.exports { module: { rules: [ { test: /\.js$/, use: [thread-loader, babel-loader], }, ], }, };需要留神的是thread-loader 有启动成本和通信成本。小项目用了反而更慢因为开启 worker 本身也是时间。我一般建议文件数量超过 3000 或构建时间超过 30 秒的项目才值得加 thread-loader。加之前先测一次加完再测一次用数据说话。2.6 控制依赖体积有时候慢是因为装多了一个很容易被忽视的点是装进 package.json 的依赖越多构建时要处理的节点就越多。哪怕你只 import 了一小部分Webpack 也会扫描整个依赖树。比如你引入了lodash但又写import _ from lodash整个 lodash 都会被构建进去。优化手段使用lodash-es搭配babel-plugin-lodash实现按需引入。使用utilities类的库时尽量只引入具体函数比如import debounce from lodash/debounce。检查是否装了一大堆“以为会用”的库比如moment、day.js、date-fns同时存在。最好统一成一种。建议用depcheck或npm-check做一次依赖清理。上面说的每个大依赖在构建阶段都要被解析、构建、压缩少一个就快一分。3. 实操过程与核心环节实现3.1 从零开始快速生成一份可复用的 webpack 优化配置这里我给出一个比较通用的生产环境 Webpack 配置片段你可以结合自己项目调整。这套配置融合了上面说的缓存、多进程、拆包、压缩等核心优化点// webpack.prod.js const path require(path); const MiniCssExtractPlugin require(mini-css-extract-plugin); const CssMinimizerPlugin require(css-minimizer-webpack-plugin); const TerserPlugin require(terser-webpack-plugin); module.exports { mode: production, entry: ./src/index.js, output: { path: path.resolve(__dirname, dist), filename: [name].[contenthash:8].js, chunkFilename: [name].[contenthash:8].chunk.js, clean: true, }, cache: { type: filesystem, buildDependencies: { config: [__filename] }, }, optimization: { minimizer: [ new TerserPlugin({ parallel: true, terserOptions: { compress: { drop_console: true }, }, }), new CssMinimizerPlugin(), ], splitChunks: { chunks: all, cacheGroups: { vendors: { test: /[\\/]node_modules[\\/]/, name: vendors, priority: 10, chunks: all, }, }, }, runtimeChunk: single, }, module: { rules: [ { test: /\.(js|jsx)$/, include: path.resolve(__dirname, src), exclude: /node_modules/, use: [thread-loader, babel-loader], }, { test: /\.css$/, use: [MiniCssExtractPlugin.loader, css-loader], }, ], }, plugins: [ new MiniCssExtractPlugin({ filename: [name].[contenthash:8].css, }), ], };说明几个关键选择runtimeChunk: single会把 webpack 的 runtime 单独抽成一个文件避免它在每次构建时变化导致所有 chunk 的 hash 都失效。TerserPlugin 显式开启parallel: true默认虽然开启但显式写出来避免被覆盖。生产模式默认启用 tree shaking配合sideEffects: false在 package.json 里设置可以移除未被使用的导出。要注意的是如果你项目里有些文件仅作副作用使用比如import ./global.less就不能把整个 package.json 的 sideEffects 一刀切成 false要按路径保留。3.2 实操一dev 模式启动慢的救急方案如果你现在项目 dev 启动非常慢先不要急着加各种负载插件先做三步检查是否有 source-map 引入过重。dev 环境建议设置为eval-cheap-module-source-map或cheap-module-source-map别上source-map这种完整版速度差异很大。关闭不必要的插件。比如NoEmitOnErrorsPlugin、HotModuleReplacementPlugin在 webpack 5 里已经不用手动配了有些老项目还在重复配会拖慢编译。使用webpack-dev-server的静态资源直出。如果你对某些大图片、大 JSON 只是访问而不做加工可以直接用devServer.static配置指向外部目录让 devServer 直接提供文件不经过打包流程。实际操作示例// webpack.dev.js const path require(path); module.exports { mode: development, devtool: eval-cheap-module-source-map, devServer: { static: { directory: path.join(__dirname, public), watch: false, }, hot: true, port: 8080, historyApiFallback: true, }, cache: { type: filesystem, buildDependencies: { config: [__filename] }, }, };watch: false很关键public 目录里如果有几百张图watch 会消耗大量 CPU 去监听变化。如果你几乎不在 dev 环境改 public 里的静态资源关掉 watch 能明显降低 CPU 占用。3.3 实操二大型项目从 Webpack 4 升到 Webpack 5 的收益如果你的项目还停留在 Webpack 4且构建慢到离谱可以考虑升级。Webpack 5 在缓存、tree shaking、模块联邦等方面都有很大提升尤其是 persistent cache 带来增量构建加速非常明显。升级时重点处理几个方面将webpack-cli、webpack-dev-server同步升级到适配版本。检查webpack-manifest-plugin是否替换为 webpack 5 内置的output.assetModuleFilename。url-loader、file-loader可以统一替换为 webpack 5 的Asset Modules配置更简洁。Asset Modules 的参考配置module: { rules: [ { test: /\.(png|jpe?g|gif|svg)$/i, type: asset, parser: { dataUrlCondition: { maxSize: 8 * 1024, // 小于 8KB 的图片转 base64 内联 }, }, generator: { filename: images/[name].[contenthash:8][ext], }, }, { test: /\.woff2?$/i, type: asset/resource, generator: { filename: fonts/[name].[contenthash:8][ext], }, }, ], }Asset Modules 省略了额外 loader 的安装和调用开销构建阶段整体更轻快。3.4 实操三结合 CI 的构建缓存做提速本地优化有用但团队协作里真正的痛点是 CI 构建。这里给出一种常见 GitLab CI 缓存方案核心是把node_modules和node_modules/.cache都放进 CI 缓存cache: key: files: - package-lock.json paths: - node_modules/ - node_modules/.cache/ build: stage: build script: - npm ci - npm run build only: - mainnpm ci会严格按照 lock 文件安装比npm install更快、更稳定。而且由于缓存 key 绑定package-lock.json依赖不变时直接命中缓存依赖变了就重新缓存互不干扰。如果你用 npm 7 或 Yarn还有 PnP、Zero-Install 等方案但我个人觉得对大多数团队合理配置缓存就是性价比最高的做法。3.5 实操四自定义 loader 与插件的耗时排查如果所有常规优化都做了构建还是慢需要更精细的定位。网上能搜到不少分析方法我推荐一个自己常用的操作流程生成stats.jsonnpx webpack --profile --json stats.json用webpack-bundle-analyzer stats.json分析体积。配合speed-measure-webpack-pluginwebpack 4 老项目好用或自己写了一小段插件计时逻辑把每个 loader 和 plugin 的耗时打印出来。自己写计时插件其实很简单class TimerPlugin { apply(compiler) { compiler.hooks.compile.tap(TimerPlugin, () { this.startTime Date.now(); }); compiler.hooks.done.tap(TimerPlugin, stats { const endTime Date.now(); console.log(构建总耗时${endTime - this.startTime}ms); }); } }进阶一点可以对每个钩子计时看到底是beforeRun、make、emit哪个阶段耗时最长。耗时最多的阶段直接决定优化方向。3.6 实操五用 Vite 或 Rspack 做激进优化对于新项目或者受够了 Webpack 的老项目可以考虑把构建底层换掉。我个人用过一段时间的 Vite 和 Rspack简单说下感受Vite 基于 esbuild 预构建依赖开发服务器是真正的按需编译启动速度几乎秒开热更新也很快。但生产构建默认使用 Rollup复杂度上来后构建时间和产物控制需要花心思。Rspack 是一个 Rust 实现的 Webpack 兼容打包器用户体验和 Webpack 高度一致但构建速度提升好几倍。我在一个三千多个模块的旧项目上做过测试dev 启动从 70 秒降到 10 秒以内生产构建也提升了约 70%。不过要注意换工具不是免罪金牌。如果一个项目本身依赖使用混乱、到处全量引入、没有做代码分割换到哪个工具都会碰壁。我见过有人从 Webpack 换到 Vite结果 dev 是快了生产构建还是慢得要命最后发现路由全是同步引入懒加载都没做。所以我的建议是先用保守优化解决基础问题再根据团队接受度决定是否切换工具。4. 常见问题与排查技巧实录4.1 缓存导致构建结果不更新这是最让人头疼的问题之一。典型表现改了代码重新构建但线上表现还是旧内容或者本地 dev 热更新偶尔失灵。排查思路先确认 webpack 缓存目录位置一般在node_modules/.cache/webpack。手动删除缓存重启构建看看问题是否消失。如果删除后正常说明缓存 key 没覆盖到该变的内容。检查buildDependencies.config是否配置正确。如果配置没有作为依赖考虑那你改配置后用的还是旧缓存。检查文件名是否用了contenthash。如果用hash或chunkhash在缓存复用或构建上下文变化时可能产生不稳定的命名。我自己还遇到过一个很阴间的问题dev 环境热更新某些文件不生效后来发现是cache: { type: filesystem }搭配babel-loader的cacheDirectory双重缓存的兼容问题。解决方式是只保留一层缓存要么关掉 webpack 的 filesystem cache要么关掉 babel-loader 的 cache看你更需要哪种。4.2 thread-loader 在多进程下内存溢出配置了thread-loader后某些情况下会报heap out of memory。这是因为每个 worker 都会复制一份 Node.js 环境默认内存限制是相同的。解决办法是增加 Node.js 内存上限NODE_OPTIONS--max_old_space_size4096 npm run build更精细的控制可以在 thread-loader 里配置workerParallelJobs、poolTimeout等参数但大多数时候不需要调这些内存问题用上面那行命令就能解决。4.3 生产构建比开发构建还慢很多人觉得生产构建要压缩慢是正常的。但如果慢到不可接受需要检查是否用了全量 sourcemap。生产环境完全不需要devtool: source-map可以用nosources-source-map或直接关掉。是否在optimization.minimizer里配置了多个压缩插件并行冲突。例如同时配置了 TerserPlugin 和 UglifyjsWebpackPlugin会重复压缩。是否在postcss.config.js里跑了大量不必要的插件。比如autoprefixercssnano在 dev 阶段也执行白白浪费时间。4.4 常见问题速查表现象可能原因解决方案dev 启动很慢依赖解析范围过大、全量编译加 include、开启 filesystem cache、检查 alias热更新慢编译的文件太多、source map 太重换成 cheap 版本、抽离公共模块、减少 watch 文件构建结果不更新缓存 key 不当、多变 hash配置 buildDependencies、用 contenthash、清理缓存生产构建内存溢出大项目 多进程压缩增加 NODE_OPTIONS 内存上限、减少并发产物体积过大全量引入库、缺少代码分割按需引入、SplitChunks、路由懒加载CI 每次都从零构建没做流水线缓存缓存 node_modules 和 .cache 目录4.5 独家避坑技巧除了上面的常规问题有几个容易被忽略的细节都是我在实战里踩过的源地图选型要谨慎。开发环境用eval-cheap-module-source-map别上eval-source-map后者在大型项目里会显著拖慢构建生产环境我干脆关掉线上排查用业务错误上报平台去定位。别让eslint-loader干一整套 lint 的活儿。我建议把 lint 做成单独的 npm script在pre-commit钩子或 CI 里跑。开发过程中该做的类型检查和错误检查用 IDE 完成不要每次编译都触发。谨慎使用sideEffects。配了sideEffects: false能提升 tree-shaking 效果但如果你项目里有 CSS、polyfill、全局副作用文件可能会被误删导致线上异常。所以配置时一定要列白名单比如sideEffects: [*.css, *.scss]。文件监听是有代价的。在webpack-dev-server里如果监听大量文件CPU 会持续偏高。可以设置server.watchOptions.poll来减少轮询频率或者用ignored忽略 node_modules。4.6 从构建优化到整体性能优化构建效率优化不是孤立的。你会发现构建快了产物小了团队成员每天省下大把时间紧接着大家开始关注线上运行时性能——首屏图片加载、接口聚合、移动端交互卡顿、数据更新带来的重渲染这些才是用户真实感知到的“性能”。我最初做构建优化是因为团队被 CI 卡到怀疑人生后来慢慢延伸到线上指标逐步形成一套完整的前后端性能优化流程。有意思的是最近我研究游戏性能优化和安卓性能优化的思路发现很多原则和前端构建优化是共通的都是先定位瓶颈再做分层优化再通过缓存与并发解决高频问题。比如手游性能优化里常说的减少 DrawCall、合并网格其实和前端减少 HTTP 请求、合并 chunk 的思路非常像。而 Julia 性能优化里强调的“类型稳定”和“避免内存重复分配”也和前端优化里“减少对象创建、避免不必要的 diff”异曲同工。所以这也是我一直强调的不要只盯着某个工具的命令行参数而是理解性能优化的底层思维。构建效率优化的底层思维就是“减少重复工作增加并行度充分利用缓存”这套思维换到任何领域都适用。5. 一键批处理Windows 游戏性能优化脚本参考前面聊了很多前端构建效率优化但性能优化的应用场景其实非常宽泛比如最近不少朋友在问能不能写一个 Windows 批处理脚本一键优化游戏性能这里也分享一个我参考实践中常用做法整理的 bat 脚本思路同样遵循上面说的“关掉不必要的东西、用最优配置、清理无用文件”。echo off chcp 65001 nul title Windows 游戏性能优化脚本 echo echo 正在应用游戏性能优化配置... echo :: 1. 关闭不必要的后台服务 :: 以 DiagTrack 和 SysMain 为例可按需增删 echo [1/4] 关闭不必要的后台服务... sc config DiagTrack start disabled nul 21 sc stop DiagTrack nul 21 sc config SysMain start disabled nul 21 sc stop SysMain nul 21 echo 后台服务处理完成。 :: 2. 调整电源模式为高性能 echo [2/4] 正在切换电源高性能模式... powercfg /setactive SCHEME_MIN echo 电源模式已切换为高性能。 :: 3. 优化网络延迟 echo [3/4] 正在调整网络参数... :: 关闭Nagle算法相关优化需要修改注册表属于系统级调整请谨慎使用 :: 清除DNS缓存解决部分域名解析延迟 ipconfig /flushdns nul 21 :: 重置 Winsock 目录修复网络连接问题 netsh winsock reset nul 21 echo 网络参数优化完成。 :: 4. 清理系统临时文件 echo [4/4] 正在清理系统临时文件... del /f /q %TEMP%\* nul 21 del /f /q C:\Windows\Temp\* nul 21 :: 清理Windows预取文件注意仅优化时会重新生成不必担心 del /f /q C:\Windows\Prefetch\* nul 21 echo 临时文件清理完成。 echo echo 游戏性能优化全部完成建议重启一次电脑使设置彻底生效。 echo pause这段脚本做了四件事关闭部分后台服务、切换高性能电源模式、刷新 DNS 与重置网络配置、清理临时文件。核心逻辑其实和前面讲构建效率优化一模一样关闭不必要的资源占用、调整成最优运行状态、清除历史无用内容。需要注意注册表这种系统级改动除非你很清楚后果否则不要随意加进去任何时候都不要为了“性能”牺牲系统稳定性。游戏性能优化里还有一招很有用就是关闭游戏时的 Windows 自动更新和系统通知。但这类调整往往涉及系统组件不同版本策略不同建议只做上面脚本里列出的安全项目效果已经足够明显。6. 移动端与运行时性能优化的联动思考构建效率优化做到后面你会发现它和移动端性能优化、安卓性能优化等话题越来越挂钩。举个例子前端项目构建后产生的 JS 包如果过大在移动端网络环境下首屏加载会非常吃力。构建时如果能通过代码分割把首屏代码降到 200KB 以内再配合 CDN 边缘缓存首屏渲染时间会明显下降。再比如JSON.stringify在前端性能优化里经常被提及其实它就和一个“构建产物序列化”场景很像。如果你在构建时使用了大量 inline JSON 配置或通过字符串拼接生成代码构建进程会频繁创建大对象并序列化造成 GC 压力。优化方式是把静态配置抽成独立 JSON 文件避免反复解析和序列化。这和运行时优化里“避免不必要的 JSON JSON.stringify 深度拷贝大对象”是同一个道理。我对团队的要求是写完代码保存之后先关注构建反馈速度其次关注线上真实设备的表现。构建反馈速度决定了迭代的效率线上表现决定了用户留存。两者有一个不达标产品体验都会打折扣。所以构建效率优化永远不是“我一个人优化完就结束”的事情它应该沉淀到团队的开发规范、CI/CD 流程和监控体系里。比如每次提交后自动跑构建性能基准一旦构建时间超过阈值就在群里报警谁改动导致明显变慢立刻定位到代码。这样整个团队会被动地养成性能意识。最后说点实际的我在实际项目里总结的经验是构建效率优化没有一劳永逸的银弹但有一点确定——你必须先量化现状再动手改。很多人一上来就换个构建工具、加一堆插件结果反而更慢就是因为没有数据支撑。我现在每接手一个新项目都会先跑一次全量构建和增量构建记录下时间、产物体积、主要依赖清单然后才根据瓶颈横向选择方案。等优化完成再跑一次对比把前后数据贴在 README 里让后来的人知道为什么这些配置是必要的。如果你现在正被构建速度折磨我的建议是从最简单的三步开始做第一把所有 loader 加上include: src并开启 cache第二配置 Webpack 5 的 filesystem cache第三生产环境用 contenthash 拆包。这三个步骤做完大部分项目的构建速度都会有质的提升。之后再慢慢尝试 thread-loader、esbuild、Rspack 这些更激进的手段。踩过几次坑之后你会慢慢发现性能优化其实不是某个瞬间的灵光乍现而是一套持续积累的方法论。从技能角度它需要你理解工具原理、懂得量化分析、熟悉团队协作从心态角度它要求你耐心、细致不迷信某一个方案。无论你是做前端、后端、客户端还是游戏开发这套“量化-定位-优化-验证”的循环都值得复用。希望这篇内容能帮你在性能优化的路上少走一些弯路真正感受到“快”带来的快乐。