手动配置Webpack+Babel的React项目报JS堆内存溢出错误
问题根因
这个报错是Node默认内存上限不足+手动写的webpack配置存在内存累积问题共同导致的:
- Node 14.x默认给单进程分配的老生代内存上限约2GB,从你的报错日志看,内存涨到2045MB左右就触发GC失败、进程崩溃,刚好卡着默认上限
- 你的配置有三个明显不合理的点,会导致热更新过程中旧的构建产物无法被垃圾回收,内存越跑越高,这也是为啥同一份代码用CRA能连续跑十几个小时不炸——CRA默认做了缓存优化、选了低内存占用的sourcemap模式,还规避了已知的内存泄漏问题:
- 开发环境用了
inline-source-map,这种模式会把所有sourcemap转成base64内联到bundle里,热更新时旧的sourcemap缓存不会被及时清理,持续占内存 - babel配置里给
@babel/preset-env设了targets: { node: 'current' },这个配置是给Node端脚本用的,前端浏览器项目用这个会让babel输出大量不必要的转译代码,既增大产物体积,又增加构建时内存开销 - 没开构建缓存,每次热更新都做全量编译,额外消耗内存,还会让旧的编译产物残存在内存里
- 开发环境用了
临时修复:调整Node内存上限
你查到的--max_old_space_size=4096参数是传给Node进程的,不是传给webpack的,不能写在webpack命令后面,直接修改package.json里的start脚本即可:
"scripts": { "start": "node --max_old_space_size=4096 ./node_modules/webpack-cli/bin/cli.js serve --config webpack.dev.js" }
上面的配置是把Node老生代内存上限调到4GB,改完重启服务就生效,如果还是跑久了崩,可以把数值调到6144(即6GB),根据自己电脑的实际内存调整就行。
长期优化:从根源解决内存持续上涨
光加内存只是延缓崩溃时间,改三个配置点就能让服务内存稳定在固定区间,跑一整天也不会溢出:
- 修正babel配置
打开babel.config.js,把给Node用的targets配置替换成浏览器适配配置:module.exports = { presets: [ '@babel/react', ['@babel/preset-env', { targets: { browsers: ['last 2 versions', 'not dead'] } }], ], }; - 替换开发环境sourcemap模式,开启构建缓存
打开webpack.dev.js,替换devtool配置,加上缓存规则:
注意要把const { merge } = require('webpack-merge'); const openBrowser = require('react-dev-utils/openBrowser'); const common = require('./webpack.common'); const host = process.env.HOST || 'localhost'; const port = parseInt(process.env.PORT, 10) || 3000; module.exports = merge(common, { mode: 'development', // 替换inline-source-map,这个模式构建快、内存占用低,报错定位精度足够开发用 devtool: 'eval-cheap-module-source-map', // 开webpack持久化缓存,避免热更新全量重编 cache: { type: 'filesystem', allowCollectingMemory: true }, module: { rules: [ { test: /\.(js|jsx)$/, exclude: /node_modules/, use: [ { loader: 'babel-loader', // 给babel开缓存,大幅减少重复编译开销 options: { cacheDirectory: true } } ] } ] }, devServer: { historyApiFallback: true, hot: true, onListening: () => { openBrowser(`http://${host}:${port}`); }, port, host, }, });webpack.common.js里原来写的js/jsx规则删掉,避免重复规则冲突。 - 把生产专用插件移到生产配置里
CleanWebpackPlugin和WebpackManifestPlugin都是打包生产产物时才用的,开发环境跑服务不会输出build目录,这两个插件挂在公共配置里,每次热更新都会做不必要的文件扫描,白白占内存。把这两个插件从webpack.common.js里删掉,移到webpack.prod.js的plugins数组里即可。
改完之后删掉项目里的node_modules/.cache目录,重启服务就行,后续热更新时内存会稳定在一个固定范围,不会随运行时间持续上涨。
内容的提问来源于stack exchange,提问作者Sandip Dhang
相关产品推荐
相关产品推荐

