从“龟速打包”到“秒开体验”:Webpack优化你只需要这6招

0 阅读2分钟

项目越写越大,打包一次喝杯咖啡回来还没好?产出的bundle.js比电影还大?今天我们就来一场Webpack“减肥+提速”双修课。不用焦虑,6招下来,你的打包速度会像换了跑车引擎,产物体积瘦成一道闪电。

前言

Webpack就像个勤劳的搬运工,但如果你不告诉它“哪些不用搬”、“怎么抄近道”,它会把你整个项目连同node_modules一起扛上,慢得像蜗牛。今天我们就来调教这个搬运工,让打包速度飞起,让产物体积减半。

本文分两大块:速度优化(开发时等你)和体积优化(上线时快人一步)。

一、速度优化:别让Webpack摸鱼

1. 减少Loader和Plugin的工作范围

Webpack默认会遍历node_modules,但这里面的代码通常已经编译好了。用exclude告诉它:别管node_modules。

module: {
  rules: [
    {
      test: /\.js$/,
      exclude: /node_modules/,  // 跳过node_modules
      use: 'babel-loader'
    }
  ]
}

同理,Plugin里如果不需要在某个环境下执行,可以动态添加。

2. 使用缓存:第二次打包快如闪电

  • babel-loader缓存cacheDirectory: true
use: {
  loader: 'babel-loader',
  options: { cacheDirectory: true }
}
  • cache-loader(Webpack5之前):把结果缓存到硬盘。
  • Webpack5内置缓存:直接开启
module.exports = {
  cache: {
    type: 'filesystem', // 硬盘缓存
  }
};

第一次打包正常,第二次秒开。

3. 多线程/多进程构建

  • thread-loader:把耗时Loader扔到子进程。
use: [
  { loader: 'thread-loader', options: { workers: 3 } },
  'babel-loader'
]
  • HappyPack(不维护了,慎用)。Webpack5里用thread-loader就够了。

4. 使用DLLPlugin(或Webpack5的持久化缓存)

老项目中DLLPlugin可以把第三方库预先打包成动态链接库,现在Webpack5的cache.type: 'filesystem'已够用。如果还想更极致,可以用splitChunks把vendor拆出去。

二、体积优化:让bundle瘦成闪电

1. 代码分割(SplitChunks)

把公共代码抽出来,防止重复打包。Webpack4+内置optimization.splitChunks,默认配置已经很智能:

optimization: {
  splitChunks: {
    chunks: 'all',  // 对所有模块生效
    cacheGroups: {
      vendor: {
        test: /[\\/]node_modules[\\/]/,
        name: 'vendors',
        priority: 10
      }
    }
  }
}

这样会生成一个vendors.js,里面是第三方库,单独缓存。

2. 动态导入(按需加载)

不要一次性加载所有路由的组件。React里用React.lazy + Suspense,Vue里用动态import

// 之前
import Dashboard from './Dashboard';

// 之后
const Dashboard = React.lazy(() => import('./Dashboard'));

Webpack会自动把Dashboard单独打包成一个chunk,只有访问时才加载。

3. Tree Shaking:摇掉死代码

Tree Shaking依赖ES6模块静态结构。确保:

  • 使用import/export,不要用require
  • sideEffects: false 或 指定有副作用的文件。
// package.json
{
  "sideEffects": false  // 告诉Webpack所有文件都没有副作用,可以安全摇掉未引用代码
}

如果你的项目里有import './global.css'这种,需要把CSS文件排除:

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

4. 压缩代码

  • TerserPlugin(JS压缩):Webpack5自带,无需安装。可以开启并行压缩。
optimization: {
  minimize: true,
  minimizer: [
    new TerserPlugin({
      parallel: true,  // 多线程压缩
      terserOptions: {
        compress: { drop_console: true } // 去除console
      }
    })
  ]
}
  • CssMinimizerPlugin(CSS压缩):压缩抽离的CSS文件。

5. 图片压缩与优化

  • image-webpack-loader:无损压缩图片。
{
  test: /\.(png|jpe?g|gif|svg)$/,
  use: [
    'file-loader',
    {
      loader: 'image-webpack-loader',
      options: { bypassOnDebug: true, disable: process.env.NODE_ENV === 'development' }
    }
  ]
}
  • url-loader:小图片转base64,减少请求数。

6. 分析打包结果

不知道哪里胖?用工具照个X光。

  • webpack-bundle-analyzer:生成交互式饼图。
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
plugins: [new BundleAnalyzerPlugin()]

一看便知哪个库占最大,然后决定替换或按需引入(比如lodash换成lodash-es)。

三、实战:一个优化前后的对比

假设项目原始打包时间30秒,体积2.5MB。

优化措施时间效果体积效果
exclude + 缓存30s → 10s-
thread-loader10s → 6s-
splitChunks-2.5MB → 主包1MB,vendors 1.2MB
动态导入-首屏只加载主包1MB
压缩+tree shaking-主包700KB,vendors 900KB
图片压缩-再减200KB

最终打包时间6秒,首屏加载1.2MB(原来2.5MB),体验大幅提升。

四、总结:优化口诀

  • 速度:缩小范围、开启缓存、多线程。
  • 体积:代码分割、动态导入、摇树、压缩、图片瘦身。
  • 工具:用webpack-bundle-analyzer看胖在哪,用speed-measure-webpack-plugin测谁慢。

优化不是一次性的事,项目每增加一个依赖,都要留心。但掌握了这6招,你已经能解决90%的性能问题。

如果你觉得今天的“减肥+提速”课够干,点个赞让更多人看到。明天我们将进入Vite原理——比Webpack更快的下一代构建工具。我们明天见!