Webpack5打包体积过大,怎么优化才能减小vendor.js?

芯依 阅读 47

最近项目升级到Webpack5后,发现打包出来的 vendor.js 超过2MB,首屏加载特别慢。我已经用了 SplitChunksPlugin 做了基础拆分,但效果不明显。试过把 node_modules 单独拆出来,但有些第三方库还是被打包进 vendor 里,比如 lodash 和 moment。

下面是我目前的 splitChunks 配置:

optimization: {
  splitChunks: {
    chunks: 'all',
    cacheGroups: {
      vendor: {
        test: /[\/]node_modules[\/]/,
        name: 'vendors',
        chunks: 'all',
      }
    }
  }
}

是不是配置哪里不对?有没有更有效的拆包策略或者 Tree Shaking 没生效?

我来解答 赞 9 收藏
二维码
手机扫码查看
2 条解答
端木常青
你的配置问题在于把整个 node_modules 打包成了一个文件,这样 lodash 和 moment 肯定都会混在里面。让我帮你一步步解决。

问题分析

先说为什么效果不明显:你现在的配置是把所有 node_modules 里的东西都塞进 vendors.js,lodash 和 moment 当然跑不掉。而且 moment 这种全量引入的库,Tree Shaking 本身就不太好使。

解决方案

第一步:把大库单独拆出来

把那些体积大的第三方库单独拆包,而不是混在 vendors 里:

optimization: {
splitChunks: {
chunks: 'all',
maxInitialRequests: 25,
minSize: 20000,
cacheGroups: {
// 先处理 node_modules 里的大库
moment: {
test: /[/]node_modules[/]moment[/]/,
name: 'moment',
chunks: 'all',
priority: 20,
},
lodash: {
test: /[/]node_modules[/]lodash[/]/,
name: 'lodash',
chunks: 'all',
priority: 20,
},
// 其他 node_modules 库
vendors: {
test: /[/]node_modules[/]/,
name: 'vendors',
chunks: 'all',
priority: 10,
},
}
}
}


这里需要注意 priority 参数,数值越高的会优先匹配,这样大库会被单独拆走。

第二步:解决 lodash 的 Tree Shaking

lodash 默认是全量导出的,Tree Shaking 很难生效。你有两个选择:

方案A:使用 lodash-es(推荐)

// 安装 lodash-es 替代 lodash
// npm install lodash-es

// 然后这样导入
import { debounce, throttle } from 'lodash-es';
// 而不是
import { debounce, throttle } from 'lodash';


lodash-es 是 ESM 版本的,Tree Shaking 可以正常工作。

方案B:使用 babel-plugin-lodash

如果项目里lodash引用太多,改动太大,可以装这个插件自动按需导入:

// .babelrc 或 babel.config.js
{
"plugins": [
["lodash", { "id": "lodash", "commonjs": true }]
]
}


第三步:moment.js 替换方案

moment.js 体积大是因为它把所有时区和 locale 数据都打包进去了。推荐换成 dayjs,只有 2KB 左右:

// npm install dayjs

import dayjs from 'dayjs';
import 'dayjs/locale/zh-cn';

dayjs().format('YYYY-MM-DD');


如果暂时不想换 moment,至少按需加载需要的 locale:

// 只引入需要的语言包
import 'moment/locale/zh-cn';


第四步:确认 Tree Shaking 真的生效

检查一下你的 package.json 和 webpack 配置:

// webpack.config.js
module.exports = {
mode: 'production', // 必须是 production 模式
optimization: {
usedExports: true, // 开启 Tree Shaking
sideEffects: true, // 配合 package.json 的 sideEffects 字段
},
};


然后在 package.json 里加上:

{
"sideEffects": false
}


或者明确指定哪些文件有副作用:

{
"sideEffects": [
"*.css",
"*.scss"
]
}


总结一下

你目前配置的核心问题是把所有 node_modules 混在一起拆。按照上面的步骤来:

1. 先把 moment、lodash 这种大块头单独拆出来
2. lodash 换成 lodash-es 或者装 babel-plugin-lodash
3. moment 能换就换,不能换就只引入需要的 locale
4. 确保 production 模式 + usedExports + sideEffects 配置正确

这样一套下来,vendor.js 体积应该能降很多。如果还有问题,把你现在的 webpack 配置贴出来,我帮你看看具体哪里没配置好。
点赞
2026-03-14 13:12
一翠翠
一翠翠 Lv1
问题在于整个node_modules打成一个包了,需要按库拆分。配置多个cacheGroups把react、lodash、moment这些大头单独拉出来:

optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
react: {
test: /[/]node_modules[/](react|react-dom|scheduler)[/]/,
name: 'react',
chunks: 'all',
priority: 20
},
lodash: {
test: /[/]node_modules[/]lodash[/]/,
name: 'lodash',
chunks: 'all',
priority: 20
},
moment: {
test: /[/]node_modules[/]moment[/]/,
name: 'moment',
chunks: 'all',
priority: 20
},
vendors: {
test: /[/]node_modules[/]/,
name: 'vendors',
chunks: 'all',
priority: 10
}
}
}
}


另外lodash用lodash-es替代,moment直接换dayjs,这两个体积差十几倍。
点赞 1
2026-03-12 14:01