webpack优化前端性能

Webpack 优化前端性能主要从构建时优化运行时优化两个维度进行。以下是全面的优化方案:

1. 代码分割与按需加载

1.1 动态导入 (懒加载)

// React 路由懒加载
const Home = lazy(() => import(/* webpackChunkName: "home" */ './views/Home'))
const About = lazy(() => import(/* webpackChunkName: "about" */ './views/About'))

// Vue 组件懒加载
const AsyncComponent = () => ({
  component: import('./AsyncComponent.vue'),
  loading: LoadingComponent,
  delay: 200
})

// 条件懒加载
document.getElementById('btn').addEventListener('click', () => {
  import('./heavy-module.js')
    .then(module => {
      module.heavyFunction()
    })
})

1.2 SplitChunks 代码分割

module.exports = {
  optimization: {
    splitChunks: {
      chunks: 'all',
      minSize: 20000, // 超过20KB才单独打包
      maxSize: 244000, // 尝试拆分大于244KB的包
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          priority: 10,
          chunks: 'all'
        },
        react: {
          test: /[\\/]node_modules[\\/](react|react-dom)[\\/]/,
          name: 'react-vendor',
          priority: 20
        },
        common: {
          name: 'common',
          minChunks: 2,
          priority: 5,
          reuseExistingChunk: true
        },
        styles: {
          name: 'styles',
          test: /\.css$/,
          chunks: 'all',
          enforce: true
        }
      }
    }
  }
}

2. 资源压缩与优化

2.1 JavaScript 压缩

const TerserPlugin = require('terser-webpack-plugin')

module.exports = {
  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin({
        parallel: true, // 多进程压缩
        terserOptions: {
          compress: {
            drop_console: true, // 移除console
            drop_debugger: true, // 移除debugger
            pure_funcs: ['console.log'] // 移除特定函数
          },
          mangle: {
            safari10: true // 解决Safari 10/11 bugs
          }
        },
        extractComments: false // 不提取注释
      })
    ]
  }
}

2.2 CSS 压缩与提取

const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          process.env.NODE_ENV === 'production' 
            ? MiniCssExtractPlugin.loader 
            : 'style-loader',
          'css-loader',
          'postcss-loader' // 添加前缀等
        ]
      }
    ]
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: 'css/[name].[contenthash:8].css',
      chunkFilename: 'css/[name].[contenthash:8].chunk.css'
    })
  ],
  optimization: {
    minimizer: [
      new CssMinimizerPlugin({
        parallel: true
      })
    ]
  }
}

2.3 图片资源优化

module.exports = {
  module: {
    rules: [
      {
        test: /\.(png|jpg|jpeg|gif|svg)$/,
        type: 'asset',
        parser: {
          dataUrlCondition: {
            maxSize: 8 * 1024 // 8KB以下转base64
          }
        },
        generator: {
          filename: 'images/[name].[contenthash:8][ext]'
        },
        use: [
          {
            loader: 'image-webpack-loader',
            options: {
              mozjpeg: { progressive: true, quality: 65 },
              optipng: { enabled: false },
              pngquant: { quality: [0.65, 0.90], speed: 4 },
              gifsicle: { interlaced: false },
              webp: { quality: 75 }
            }
          }
        ]
      }
    ]
  }
}

3. 缓存策略

3.1 输出文件哈希命名

module.exports = {
  output: {
    filename: 'js/[name].[contenthash:8].js',
    chunkFilename: 'js/[name].[contenthash:8].chunk.js'
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: 'css/[name].[contenthash:8].css'
    })
  ]
}

3.2 模块ID优化

module.exports = {
  optimization: {
    moduleIds: 'deterministic', // 保持模块ID稳定
    chunkIds: 'deterministic', // 保持块ID稳定
    runtimeChunk: {
      name: 'runtime' // 提取runtime代码
    }
  }
}

4. Tree Shaking 与副作用优化

4.1 启用 Tree Shaking

module.exports = {
  mode: 'production',
  optimization: {
    usedExports: true, // 标记使用到的导出
    sideEffects: false, // 开启副作用检测
    concatenateModules: true // 模块作用域提升
  }
}

4.2 package.json 配置

{
  "name": "your-package",
  "sideEffects": [
    "*.css",
    "*.scss",
    "./src/polyfills.js"
  ]
}

4.3 Lodash 按需引入

// 安装 babel-plugin-lodash
npm install --save-dev babel-plugin-lodash

// .babelrc
{
  "plugins": ["lodash"]
}

// 使用方式
import _ from 'lodash'
// 会被转换为:
// import _cloneDeep from 'lodash/cloneDeep'
// import _debounce from 'lodash/debounce'

5. 预加载与预获取

5.1 资源提示

// 预加载关键资源
import(/* webpackPreload: true */ './critical-module')

// 预获取非关键资源
import(/* webpackPrefetch: true */ './non-critical-module')

// 在路由组件中使用
const LazyComponent = lazy(() => import(
  /* webpackPrefetch: true */ 
  './LazyComponent'
))

5.2 PreloadPlugin 自动预加载

const PreloadWebpackPlugin = require('preload-webpack-plugin')

module.exports = {
  plugins: [
    new PreloadWebpackPlugin({
      rel: 'preload',
      include: 'initial',
      fileBlacklist: [/\.map$/, /hot-update/]
    })
  ]
}

6. 打包分析优化

6.1 打包分析工具

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin

module.exports = {
  plugins: [
    new BundleAnalyzerPlugin({
      analyzerMode: 'static',
      openAnalyzer: false,
      reportFilename: 'bundle-report.html'
    })
  ]
}

6.2 自定义分析插件

class BundleSizePlugin {
  apply(compiler) {
    compiler.hooks.done.tap('BundleSizePlugin', (stats) => {
      const assets = stats.toJson().assets
      assets.forEach(asset => {
        const size = (asset.size / 1024).toFixed(2)
        if (size > 500) { // 大于500KB警告
          console.warn(`🚨 ${asset.name} 体积过大: ${size} KB`)
        }
      })
    })
  }
}

7. 运行时性能优化

7.1 长缓存优化

module.exports = {
  optimization: {
    splitChunks: {
      cacheGroups: {
        // 第三方库单独打包
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          chunks: 'all'
        },
        // 提取webpack runtime
        runtime: {
          name: 'runtime',
          chunks: 'all',
          test: /runtime/
        }
      }
    }
  }
}

7.2 外部扩展 (Externals)

module.exports = {
  externals: {
    // 从CDN引入,不打包
    react: 'React',
    'react-dom': 'ReactDOM',
    vue: 'Vue',
    axios: 'axios'
  }
}

// 在HTML中通过CDN引入
<script src="https://cdn.jsdelivr.net/npm/react@17/umd/react.production.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/react-dom@17/umd/react-dom.production.min.js"></script>

8. 高级优化技巧

8.1 模块联邦 (微前端)

const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin')

module.exports = {
  plugins: [
    new ModuleFederationPlugin({
      name: 'app',
      filename: 'remoteEntry.js',
      remotes: {
        shared: 'shared@https://cdn.example.com/remoteEntry.js'
      },
      shared: {
        react: { singleton: true },
        'react-dom': { singleton: true }
      }
    })
  ]
}

8.2 PWA 优化

const WorkboxPlugin = require('workbox-webpack-plugin')

module.exports = {
  plugins: [
    new WorkboxPlugin.GenerateSW({
      clientsClaim: true,
      skipWaiting: true,
      runtimeCaching: [{
        urlPattern: /\.(?:png|jpg|jpeg|svg)$/,
        handler: 'CacheFirst',
        options: {
          cacheName: 'images',
          expiration: {
            maxEntries: 50,
            maxAgeSeconds: 30 * 24 * 60 * 60 // 30天
          }
        }
      }]
    })
  ]
}

9. 开发环境性能优化

9.1 热更新优化

module.exports = {
  devServer: {
    hot: true,
    port: 8080,
    compress: true, // 开启gzip
    overlay: true, // 错误覆盖层
    stats: 'minimal', // 精简输出
    clientLogLevel: 'warning' // 控制台日志级别
  },
  cache: {
    type: 'memory', // 内存缓存
    maxGenerations: 1
  }
}

9.2 增量编译

module.exports = {
  snapshot: {
    managedPaths: [path.resolve(__dirname, 'node_modules')]
  },
  cache: {
    type: 'filesystem',
    buildDependencies: {
      config: [__filename]
    }
  }
}

10. 性能监控与度量

10.1 性能预算

module.exports = {
  performance: {
    hints: 'warning',
    maxEntrypointSize: 500000, // 入口点最大500KB
    maxAssetSize: 300000, // 资源最大300KB
    assetFilter: function(assetFilename) {
      return assetFilename.endsWith('.js') || assetFilename.endsWith('.css')
    }
  }
}

10.2 构建监控

// webpack.config.js
class BuildMonitorPlugin {
  apply(compiler) {
    compiler.hooks.done.tap('BuildMonitorPlugin', (stats) => {
      const info = stats.toJson()
      
      console.log('构建时间:', info.time + 'ms')
      console.log('资源数量:', info.assets.length)
      
      // 发送构建报告
      if (process.env.CI) {
        this.sendReport(info)
      }
    })
  }
}

优化效果评估指标

实施优化后,关注以下指标:

指标 优化目标 测量工具
首次加载时间 < 3秒 Lighthouse
首次内容绘制 (FCP) < 1.5秒 Web Vitals
最大内容绘制 (LCP) < 2.5秒 Web Vitals
打包体积 主包 < 200KB Bundle Analyzer
缓存命中率 > 90% 浏览器Network

通过综合运用这些优化策略,可以显著提升前端应用的加载性能和运行时性能。

posted @ 2025-10-13 20:48  阿木隆1237  阅读(38)  评论(0)    收藏  举报