Webpack的loader和plugin是其核心功能,loader用于转换文件,plugin用于扩展功能。

常用Loader

1. 样式相关Loader

css-loader & style-loader

// webpack.config.js
module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
        // style-loader: 将CSS插入到DOM中
        // css-loader: 解析CSS文件中的@import和url()
      }
    ]
  }
};

sass-loader & less-loader

{
  test: /\.scss$/,
  use: [
    'style-loader',
    'css-loader',
    'sass-loader'  // 将Sass编译为CSS
  ]
},
{
  test: /\.less$/,
  use: [
    'style-loader', 
    'css-loader',
    'less-loader'  // 将Less编译为CSS
  ]
}

postcss-loader

// webpack.config.js
{
  test: /\.css$/,
  use: [
    'style-loader',
    'css-loader',
    {
      loader: 'postcss-loader',
      options: {
        postcssOptions: {
          plugins: [
            ['autoprefixer'],  // 自动添加浏览器前缀
            ['cssnano']        // CSS压缩
          ]
        }
      }
    }
  ]
}
 
// postcss.config.js
module.exports = {
  plugins: [
    require('autoprefixer'),
    require('cssnano')
  ]
};

2. JavaScript相关Loader

babel-loader

// webpack.config.js
{
  test: /\.js$/,
  exclude: /node_modules/,
  use: {
    loader: 'babel-loader',
    options: {
      presets: [
        '@babel/preset-env',     // ES6+转换
        '@babel/preset-react'    // React JSX转换
      ],
      plugins: [
        '@babel/plugin-proposal-class-properties'
      ]
    }
  }
}
 
// .babelrc
{
  "presets": [
    ["@babel/preset-env", {
      "targets": {
        "browsers": ["last 2 versions"]
      }
    }],
    "@babel/preset-react"
  ]
}

ts-loader

{
  test: /\.tsx?$/,
  use: 'ts-loader',  // TypeScript编译
  exclude: /node_modules/
}
 
// tsconfig.json
{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "jsx": "react"
  }
}

3. 文件相关Loader

file-loader & url-loader

// webpack.config.js
{
  test: /\.(png|jpe?g|gif|svg)$/,
  use: {
    loader: 'file-loader',
    options: {
      name: '[name].[hash].[ext]',
      outputPath: 'images/'
    }
  }
},
{
  test: /\.(woff|woff2|eot|ttf|otf)$/,
  use: {
    loader: 'url-loader',  // 小文件转base64,大文件使用file-loader
    options: {
      limit: 8192,        // 8KB以下转base64
      name: '[name].[hash].[ext]',
      outputPath: 'fonts/'
    }
  }
}

现代替代方案(Webpack 5内置)

// Webpack 5内置asset modules
{
  test: /\.(png|jpe?g|gif|svg)$/,
  type: 'asset/resource',  // 相当于file-loader
  generator: {
    filename: 'images/[name].[hash][ext]'
  }
},
{
  test: /\.(woff|woff2|eot|ttf|otf)$/,
  type: 'asset',          // 相当于url-loader
  parser: {
    dataUrlCondition: {
      maxSize: 8192
    }
  }
}

4. 其他常用Loader

raw-loader

{
  test: /\.txt$/,
  use: 'raw-loader'  // 将文件作为字符串导入
}
 
// 使用
import textContent from './file.txt';
console.log(textContent);

html-loader

{
  test: /\.html$/,
  use: 'html-loader'  // 处理HTML中的图片等资源
}

常用Plugin

1. HTML相关Plugin

HtmlWebpackPlugin

const HtmlWebpackPlugin = require('html-webpack-plugin');
 
module.exports = {
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html',    // 模板文件
      filename: 'index.html',          // 输出文件名
      title: '我的应用',               // 页面标题
      minify: {
        removeComments: true,          // 删除注释
        collapseWhitespace: true       // 删除空格
      },
      chunks: ['main']                 // 指定包含的chunk
    }),
    // 多页面应用
    new HtmlWebpackPlugin({
      template: './src/about.html',
      filename: 'about.html',
      chunks: ['about']
    })
  ]
};

2. CSS相关Plugin

MiniCssExtractPlugin

const MiniCssExtractPlugin = require('mini-css-extract-plugin');
 
module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          MiniCssExtractPlugin.loader,  // 替代style-loader
          'css-loader'
        ]
      }
    ]
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: 'css/[name].[contenthash].css',  // CSS文件名
      chunkFilename: 'css/[id].[contenthash].css'
    })
  ]
};

CssMinimizerWebpackPlugin

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

3. JavaScript相关Plugin

TerserWebpackPlugin

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
          },
          mangle: true,              // 混淆变量名
          format: {
            comments: false          // 删除注释
          }
        },
        extractComments: false       // 不提取注释到单独文件
      })
    ]
  }
};

4. 开发相关Plugin

DefinePlugin

const webpack = require('webpack');
 
module.exports = {
  plugins: [
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify('production'),
      'process.env.API_URL': JSON.stringify('https://api.example.com'),
      __DEV__: false
    })
  ]
};
 
// 在代码中使用
if (__DEV__) {
  console.log('开发模式');
}

HotModuleReplacementPlugin

const webpack = require('webpack');
 
module.exports = {
  plugins: [
    new webpack.HotModuleReplacementPlugin()  // 热模块替换
  ],
  devServer: {
    hot: true
  }
};

5. 优化相关Plugin

CleanWebpackPlugin

const { CleanWebpackPlugin } = require('clean-webpack-plugin');
 
module.exports = {
  plugins: [
    new CleanWebpackPlugin({
      cleanOnceBeforeBuildPatterns: ['**/*'],  // 构建前清理
      cleanAfterEveryBuildPatterns: ['*.js.map']  // 构建后清理
    })
  ]
};

CopyWebpackPlugin

const CopyPlugin = require('copy-webpack-plugin');
 
module.exports = {
  plugins: [
    new CopyPlugin({
      patterns: [
        { 
          from: 'public',           // 源目录
          to: 'assets',            // 目标目录
          globOptions: {
            ignore: ['*.DS_Store']  // 忽略文件
          }
        },
        {
          from: 'src/images',
          to: 'images'
        }
      ]
    })
  ]
};

BundleAnalyzerPlugin

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
 
module.exports = {
  plugins: [
    new BundleAnalyzerPlugin({
      analyzerMode: 'static',        // 生成静态HTML文件
      openAnalyzer: false,           // 不自动打开浏览器
      reportFilename: 'bundle-report.html'
    })
  ]
};

6. PWA相关Plugin

WorkboxWebpackPlugin

const { GenerateSW } = require('workbox-webpack-plugin');
 
module.exports = {
  plugins: [
    new GenerateSW({
      clientsClaim: true,
      skipWaiting: true,
      runtimeCaching: [
        {
          urlPattern: /^https:\/\/api\./,
          handler: 'NetworkFirst',
          options: {
            cacheName: 'api-cache'
          }
        }
      ]
    })
  ]
};

完整配置示例

开发环境配置

// webpack.dev.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');
 
module.exports = {
  mode: 'development',
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].js'
  },
  
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env', '@babel/preset-react']
          }
        }
      },
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader', 'postcss-loader']
      },
      {
        test: /\.scss$/,
        use: ['style-loader', 'css-loader', 'postcss-loader', 'sass-loader']
      },
      {
        test: /\.(png|jpe?g|gif|svg)$/,
        type: 'asset',
        parser: {
          dataUrlCondition: {
            maxSize: 8192
          }
        }
      }
    ]
  },
  
  plugins: [
    new HtmlWebpackPlugin({
      template: './public/index.html'
    }),
    new webpack.HotModuleReplacementPlugin(),
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify('development')
    })
  ],
  
  devServer: {
    hot: true,
    open: true,
    port: 3000
  }
};

生产环境配置

// webpack.prod.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const TerserPlugin = require('terser-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].js',
    clean: true
  },
  
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: [
              ['@babel/preset-env', { targets: 'defaults' }],
              '@babel/preset-react'
            ]
          }
        }
      },
      {
        test: /\.css$/,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',
          'postcss-loader'
        ]
      },
      {
        test: /\.scss$/,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',
          'postcss-loader',
          'sass-loader'
        ]
      },
      {
        test: /\.(png|jpe?g|gif|svg)$/,
        type: 'asset',
        generator: {
          filename: 'images/[name].[contenthash][ext]'
        }
      }
    ]
  },
  
  plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
      template: './public/index.html',
      minify: {
        removeComments: true,
        collapseWhitespace: true,
        removeRedundantAttributes: true
      }
    }),
    new MiniCssExtractPlugin({
      filename: 'css/[name].[contenthash].css'
    })
  ],
  
  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin({
        parallel: true,
        terserOptions: {
          compress: {
            drop_console: true
          }
        }
      }),
      new CssMinimizerPlugin()
    ],
    splitChunks: {
      chunks: 'all',
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          chunks: 'all'
        }
      }
    }
  }
};

这些loader和plugin构成了现代前端构建工具链的核心,能够处理各种文件类型、优化代码、提升开发体验。