生产环境优化

生产环境优化是 Webpack 配置的重要部分。本章介绍代码压缩、Tree Shaking、作用域提升等生产环境优化技巧。


📋 学习目标

  • ✅ 掌握代码压缩配置
  • ✅ 理解 Tree Shaking 原理
  • ✅ 学会作用域提升
  • ✅ 掌握资源优化技巧
  • ✅ 了解生产环境最佳实践

代码压缩

JavaScript 压缩

安装 TerserPlugin

npm install --save-dev terser-webpack-plugin

配置

const TerserPlugin = require('terser-webpack-plugin')
 
module.exports = {
  mode: 'production',
  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin({
        terserOptions: {
          compress: {
            drop_console: true,  // 移除 console
            drop_debugger: true,  // 移除 debugger
            pure_funcs: ['console.log']  // 移除指定函数
          },
          format: {
            comments: false  // 移除注释
          }
        },
        extractComments: false
      })
    ]
  }
}

CSS 压缩

安装 CssMinimizerPlugin

npm install --save-dev css-minimizer-webpack-plugin

配置

const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
 
module.exports = {
  optimization: {
    minimizer: [
      new CssMinimizerPlugin({
        minimizerOptions: {
          preset: [
            'default',
            {
              discardComments: { removeAll: true }
            }
          ]
        }
      })
    ]
  }
}

HTML 压缩

const HtmlWebpackPlugin = require('html-webpack-plugin')
 
module.exports = {
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html',
      minify: {
        removeComments: true,
        collapseWhitespace: true,
        removeRedundantAttributes: true,
        useShortDoctype: true,
        removeEmptyAttributes: true,
        removeStyleLinkTypeAttributes: true,
        minifyJS: true,
        minifyCSS: true
      }
    })
  ]
}

Tree Shaking

Tree Shaking 用于移除未使用的代码。

启用 Tree Shaking

module.exports = {
  mode: 'production',  // 自动启用 Tree Shaking
  optimization: {
    usedExports: true,
    sideEffects: false
  }
}

标记副作用

package.json 中标记副作用:

{
  "sideEffects": false  // 无副作用,可以安全地进行 Tree Shaking
}

或者指定有副作用的文件:

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

ES Module 要求

Tree Shaking 要求使用 ES Module:

// ✅ 支持 Tree Shaking
import { func1, func2 } from './utils'
export { func1 }
 
// ❌ 不支持 Tree Shaking
const utils = require('./utils')
module.exports = utils

示例

utils.js

export function used() {
  return 'used'
}
 
export function unused() {
  return 'unused'
}

index.js

import { used } from './utils'
console.log(used())

结果unused 函数会被移除。


作用域提升(Scope Hoisting)

作用域提升可以减少函数声明和闭包,提升代码执行效率。

启用作用域提升

module.exports = {
  optimization: {
    concatenateModules: true  // 启用作用域提升
  }
}

效果对比

未启用

// 每个模块都被包装在函数中
(function(module, exports, __webpack_require__) {
  // 模块代码
})

启用后

// 模块代码直接合并,减少函数包装
// 更少的闭包,更快的执行速度

资源优化

图片优化

module.exports = {
  module: {
    rules: [
      {
        test: /\.(png|jpg|jpeg|gif|svg)$/,
        type: 'asset',
        parser: {
          dataUrlCondition: {
            maxSize: 8 * 1024  // 8KB 以下转 base64
          }
        },
        generator: {
          filename: 'images/[hash][ext]'
        }
      }
    ]
  }
}

字体优化

module.exports = {
  module: {
    rules: [
      {
        test: /\.(woff|woff2|eot|ttf|otf)$/,
        type: 'asset/resource',
        generator: {
          filename: 'fonts/[hash][ext]'
        }
      }
    ]
  }
}

使用 CDN

module.exports = {
  externals: {
    'react': 'React',
    'react-dom': 'ReactDOM',
    'lodash': '_'
  },
  output: {
    publicPath: 'https://cdn.example.com/'
  }
}

生产环境配置示例

完整配置

const path = require('path')
const TerserPlugin = require('terser-webpack-plugin')
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
 
module.exports = {
  mode: 'production',
  
  entry: './src/index.js',
  
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'js/[name].[contenthash:8].js',
    chunkFilename: 'js/[name].[contenthash:8].chunk.js',
    clean: true
  },
  
  devtool: 'source-map',
  
  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin({
        terserOptions: {
          compress: {
            drop_console: true,
            drop_debugger: true
          }
        }
      }),
      new CssMinimizerPlugin()
    ],
    usedExports: true,
    sideEffects: false,
    concatenateModules: true
  },
  
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader'
        ]
      }
    ]
  },
  
  plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
      template: './src/index.html',
      minify: {
        removeComments: true,
        collapseWhitespace: true
      }
    }),
    new MiniCssExtractPlugin({
      filename: 'css/[name].[contenthash:8].css'
    })
  ]
}

最佳实践

1. 使用 contenthash 实现长期缓存

module.exports = {
  output: {
    filename: '[name].[contenthash:8].js'
  }
}

2. 分离第三方库

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

3. 使用 Source Map(可选)

module.exports = {
  devtool: 'source-map'  // 或 'hidden-source-map'
}

4. 启用 Gzip 压缩

const CompressionPlugin = require('compression-webpack-plugin')
 
module.exports = {
  plugins: [
    new CompressionPlugin({
      algorithm: 'gzip'
    })
  ]
}

总结

  • 代码压缩:使用 TerserPlugin 和 CssMinimizerPlugin
  • Tree Shaking:移除未使用的代码
  • 作用域提升:减少函数包装,提升性能
  • 资源优化:图片、字体等资源优化
  • 长期缓存:使用 contenthash 实现缓存优化

下一步


Webpack 生产环境 优化 TreeShaking 代码压缩