webpack打包后bundle文件过大解决方案

文章类型:webpack

发布者:hp

发布时间:2026-07-14

一:查找问题

通过webpack-bundle-analyzer搞清楚bundle里面装了什么,区分出业务代码还是其他三方占用。

npm install webpack-bundle-analyzer -D
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');

module.exports = {
  // 其他基础配置
  plugins: [
    new BundleAnalyzerPlugin({
      analyzerMode: 'server', // 启动本地服务自动打开分析页面
      analyzerHost: '127.0.0.1',
      analyzerPort: 8888, // 自定义端口,避免冲突
      openAnalyzer: true, // 构建完成后自动打开浏览器
      generateStatsFile: false, // 不生成额外的stats文件,避免冗余
    })
  ]
};

二:核心优化

1:采用Tree Shaking剔除无用代码,只能识别 ES6 的 import/export 语法,CommonJS 的 require 完全不支持。同时注意css过滤,避免副作用影响。

// 全量引入整个 lodash 库,哪怕只用到一个方法
const _ = require('lodash');
const data = _.get(user, 'info', {});


//正确写法(支持 Tree Shaking):

// 只引入用到的单个方法,体积从70KB降到2KB
import get from 'lodash/get';
const data = get(user, 'info', {});
module.exports = {
  mode: 'production', // 生产模式下自动开启部分优化
  optimization: {
    usedExports: true, // 标记未被使用的模块导出
    sideEffects: false, // 标记无副作用的模块,允许安全删除未引用部分
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: [
              ['@babel/preset-env', { modules: false }] 
              // 禁止 Babel 将 ES6 模块转成 CommonJS,否则 Tree Shaking 直接失效
            ]
          }
        }
      }
    ]
  }
};
{
  "sideEffects": [
    "*.css", "*.less", "*.scss"
  ]
}

2:代码分割,利用SplitChunksPlugin把大bundle拆成小文件,设置体积大小,以及单独抽离三方依赖包

module.exports = {
  optimization: {
    splitChunks: {
      chunks: 'all', // 同时对同步和异步模块生效
      minSize: 20000, // 只有体积大于20KB的模块才会被拆分
      minChunks: 1, // 至少被1个chunk引用就可以拆分
      cacheGroups: {
        // 单独抽离所有node_modules中的第三方依赖
        vendors: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          priority: 10, // 优先级高于其他分组
          reuseExistingChunk: true, // 复用已存在的chunk,避免重复打包
        },
        // 单独抽离体积较大的UI组件库
        elementUI: {
          name: 'element-plus',
          test: /[\\/]node_modules[\\/]element-plus[\\/]/,
          priority: 20,
        },
        // 抽离项目中自己写的公共工具函数
        common: {
          name: 'common',
          minChunks: 2,
          priority: 5,
        }
      }
    }
  }
}

3:路由懒加载,实现按需加载,通过动态 import() 实现路由级别的代码分割,只有用户访问这个页面时才加载对应代码

// Vue 路由懒加载示例
const Home = () => import('@/views/Home.vue');
const About = () => import('@/views/About.vue');

const routes = [
  { path: '/', component: Home },
  { path: '/about', component: About }
];

4:全量压缩,压缩js、css、各种代码注释,进一步缩小体积文件,部署时在 Nginx 中开启 Gzip 支持

npm install terser-webpack-plugin -D
const TerserPlugin = require('terser-webpack-plugin');

module.exports = {
  optimization: {
    minimizer: [
      new TerserPlugin({
        parallel: true, // 开启多进程压缩,提升构建速度
        terserOptions: {
          compress: {
            drop_console: true, // 删除所有console.log语句
            drop_debugger: true, // 删除所有debugger语句
            pure_funcs: ['console.log'] // 彻底移除console相关函数调用
          },
          format: {
            comments: false, // 删除所有注释
          }
        },
        extractComments: false, // 不单独生成LICENSE注释文件
      })
    ]
  }
};
npm install css-minimizer-webpack-plugin -D
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');

module.exports = {
  optimization: {
    minimizer: [
      new CssMinimizerPlugin({
        minimizerOptions: {
          preset: [
            'default',
            { discardComments: { removeAll: true } } // 删除所有CSS注释
          ]
        }
      })
    ]
  }
};
npm install compression-webpack-plugin -D
const CompressionPlugin = require('compression-webpack-plugin');

module.exports = {
  plugins: [
    new CompressionPlugin({
      algorithm: 'gzip',
      test: /\.(js|css|html)$/,
      threshold: 10240, // 只对大于10KB的文件进行压缩
      minRatio: 0.8, // 压缩率小于0.8才生成压缩文件
    })
  ]
};

5:静态资源瘦身,针对图片和字体优化,小图片转Base64,或者采用cdn或者网络图片地址

image-webpack-loader
module.exports = {
  module: {
    rules: [
      {
        test: /\.(png|jpe?g|gif|svg)$/i,
        use: [
          { loader: 'url-loader', options: { limit: 8192 } }, // 小于8KB的图片转Base64内联
          {
            loader: 'image-webpack-loader',
            options: {
              mozjpeg: { quality: 80, progressive: true }, // JPG压缩
              optipng: { enabled: false },
              pngquant: { quality: [0.6, 0.8] }, // PNG压缩
              gifsicle: { interlaced: false }, // GIF压缩
            }
          }
        ]
      }
    ]
  }
}

6:第三包优化,替代重型库为轻量替代方案,超大库通过CDN外链引入,

  • 把全量 lodash 替换成按需引入的 lodash-es,或者直接用原生 JS 方法替代常用工具函数
  • 把 moment.js(200KB+)替换成 dayjs(2KB),功能几乎完全一致
npm install unplugin-auto-import unplugin-vue-components -D
// webpack.config.js 配置externals
module.exports = {
  externals: {
    'echarts': 'echarts',
    'vue': 'Vue',
    'react': 'React'
  }
};
script src="https://cdn.jsdelivr.net/npm/vue@3/dist/vue.global.prod.js"></script>
<script src="https://cdn.jsdelivr.net/npm/echarts@5/dist/echarts.min.js">


评论
0条评论遵守法律,文明用语,共同建设文明评论区

暂无评论,快来发表第一条评论吧~