webpack 相关配置

复制代码
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const EslintWebpackPlugin = require('eslint-webpack-plugin')
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin')
const CssMinimizerWebpackPlugin = require('css-minimizer-webpack-plugin')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const WebpackBar = require('webpackbar')
const SpriteLoaderPlugin = require('svg-sprite-loader/plugin')
const TerserWebpackPlugin = require('terser-webpack-plugin')

const isProduction = process.env.NODE_ENV === 'production'

module.exports = {
    mode: isProduction ? 'production' : 'development',
    cache: false,
    resolve: {
        extensions: ['.js', '.jsx', '.ts', '.tsx', '.json'],
        alias: {
            '@src': path.resolve(__dirname, '../src'),
            '@app': path.resolve(__dirname, '../src/app'),
            '@assets': path.resolve(__dirname, '../src/assets'),
            '@common': path.resolve(__dirname, '../src/common'),
            '@components': path.resolve(__dirname, '../src/components'),
            '@pages': path.resolve(__dirname, '../src/pages'),
            '@language': path.resolve(__dirname, '../src/language'),
            '@redux': path.resolve(__dirname, '../src/redux'),
            '@router': path.resolve(__dirname, '../src/router')
        }
    },
    entry: './src/index.tsx',
    output: {
        path: isProduction ? path.resolve(__dirname, '../desktop/build') : undefined,
        filename: 'js/[name].[contenthash:8].js',
        chunkFilename: 'js/[name].[contenthash:8].chunk.js',
        clean: true,
        publicPath: isProduction ? './' : '/'
    },
    module: {
        rules: [
            {
                oneOf: [
                    {
                        test: /\.(css|less)$/,
                        use: [
                            isProduction ? MiniCssExtractPlugin.loader : 'style-loader',
                            'css-loader',
                            {
                                loader: 'postcss-loader',
                                options: {
                                    postcssOptions: {
                                        plugins: ['postcss-preset-env']
                                    }
                                }
                            },
                            {
                                loader: 'less-loader',
                                options: {
                                    lessOptions: {
                                        javascriptEnabled: true
                                    }
                                }
                            },
                            {
                                loader: 'style-resources-loader',
                                options: {
                                    patterns: path.resolve(__dirname, '../src/assets/style/variables.less')
                                }
                            }
                        ]
                    },
                    {
                        test: /\.(png|jpe?g|gif|webp|svg|ico)$/,
                        type: 'asset',
                        exclude: [path.resolve(__dirname, '../src/svgIcons/icons')],
                        parser: {
                            dataUrlCondition: {
                                maxSize: 8 * 1024
                            }
                        },
                        generator: {
                            filename: 'image/[name].[hash:8][ext]'
                        }
                    },
                    {
                        test: /\.(woff2?|eot|ttf|otf|mp3|mp4|avi|mkv)$/,
                        type: 'asset/resource',
                        generator: {
                            filename: 'media/[name].[hash:8][ext]'
                        }
                    },
                    {
                        test: /\.svg$/,
                        include: [path.resolve(__dirname, '../src/svgIcons/icons')],
                        use: {
                            loader: 'svg-sprite-loader',
                            options: {
                                symbolId: 'svg-[name]',
                            },
                        },
                    },
                    {
                        test: /\.(js|ts)x?$/,
                        exclude: /node_modules/,
                        use: [
                            {
                                loader: 'babel-loader',
                                options: {
                                    presets: [
                                        // 按需导入core-js
                                        [
                                            '@babel/preset-env',
                                            {
                                                useBuiltIns: 'usage',
                                                corejs: 3
                                            }
                                        ],
                                        '@babel/preset-react',
                                        '@babel/preset-typescript'
                                    ],
                                    cacheDirectory: true,
                                    cacheCompression: false,
                                    plugins: [
                                        !isProduction && 'react-refresh/babel',
                                        '@babel/plugin-transform-runtime',
                                        // 按需导入antd
                                        [
                                            'import',
                                            {
                                                libraryName: 'antd',
                                                libraryDirectory: 'es',
                                                style: true
                                            }
                                        ]
                                    ].filter(Boolean)
                                }
                            }
                        ]
                    },
                ]
            }
        ]
    },
    plugins: [
        new EslintWebpackPlugin({
            context: path.resolve(__dirname, '../src'),
            cache: true
        }),
        new HtmlWebpackPlugin({
            template: './public/index.html',
            filename: 'index.html',
        }),
        new WebpackBar(),
        new CopyWebpackPlugin({
            patterns: [
                {
                    from: path.resolve(__dirname, '../public'),
                    to: path.resolve(__dirname, '../desktop/build'),
                    globOptions: {
                        ignore: ['**/index.html']
                    }
                }
            ]
        }),
        new SpriteLoaderPlugin({ plainSprite: true }),
        isProduction && new MiniCssExtractPlugin({
            filename: 'style/[name].[contenthash:8].css',
            chunkFilename: 'style/[name].[contenthash:8].chunk.css'
        }),
        !isProduction && new ReactRefreshWebpackPlugin()
    ].filter(Boolean),
    optimization: {
        minimize: isProduction,
        minimizer: [
            new CssMinimizerWebpackPlugin(),
            new TerserWebpackPlugin(),
        ],
        splitChunks: {
            chunks: 'all',
            name: false,
            cacheGroups: {
                reactBase: {
                    name: 'reactBase',
                    test: /[\\/]node_modules[\\/](react|react-dom|react-router-dom)[\\/]/,
                    priority: 10,
                    chunks: 'all'
                },
                antdBase: {
                    name: 'antdBase',
                    test: /[\\/]node_modules[\\/](antd|@ant-design)[\\/]/,
                    priority: 9,
                    chunks: 'all'
                },
                common: {
                    name: 'common',
                    minChunks: 2,
                    priority: 5,
                    chunks: 'all'
                }
            }
        },
        runtimeChunk: {
            name: entrypoint => `runtime-${entrypoint.name}`
        }
    },
    devServer: {
        historyApiFallback: true,
        compress: true,
        host: '0.0.0.0',
        port: 8000,
        hot: true
    },
    devtool: isProduction ? 'source-map' : 'eval-cheap-module-source-map',
    performance: {
        hints: false,
        maxEntrypointSize: 512000,
        maxAssetSize: 512000
    }
}

这个 Webpack 配置文件是一个典型的现代前端项目配置,主要用于构建和优化一个基于 React 的 TypeScript 项目。下面我将逐个解释这些配置在项目中的作用:

基础配置

  1. **`mode`**:
  • 根据环境变量 `NODE_ENV` 的值设置 Webpack 的模式为 `production` 或 `development`。这会影响 Webpack 的默认行为,例如在生产模式下会压缩代码。
  1. **`cache`**:
  • 设置为 `false`,表示禁用 Webpack 的缓存。这在开发过程中通常不需要,但在生产环境中可以提高构建速度。
  1. **`resolve`**:
  • **`extensions`**: 自动解析指定的扩展名,这样在导入模块时可以省略扩展名。

  • **`alias`**: 设置路径别名,方便在项目中快速引用特定的目录,例如 `@src` 指向 `src` 目录。

  1. **`entry`**:
  • 指定项目的主要入口文件,这里是 `./src/index.tsx`。
  1. **`output`**:
  • **`path`**: 输出文件的目录,生产模式下输出到 `../desktop/build`。

  • **`filename`**: 输出的文件名,使用 `[contenthash:8]` 生成基于内容的哈希值,用于缓存控制。

  • **`chunkFilename`**: 代码分割后的文件名。

  • **`clean`**: 在每次构建前清理输出目录。

  • **`publicPath`**: 设置资源的公共路径,生产模式下为 `./`,开发模式下为 `/`。

模块加载器(`module.rules`)

  1. **CSS 和 LESS 文件**:
  • 使用 `MiniCssExtractPlugin.loader` 或 `style-loader` 将 CSS 提取为单独的文件(生产模式)或直接注入到页面中(开发模式)。

  • 使用 `css-loader` 和 `less-loader` 解析 CSS 和 LESS 文件。

  • 使用 `postcss-loader` 进行 CSS 预处理,例如自动添加浏览器前缀。

  • 使用 `style-resources-loader` 全局注入 LESS 变量文件。

  1. **图片和字体文件**:
  • 使用 `asset` 类型处理图片和字体文件,根据文件大小决定是否转换为 Base64(小于 8KB 的文件)。

  • 设置输出路径为 `image` 或 `media` 目录。

  1. **SVG 文件**:
  • 对于 `src/svgIcons/icons` 目录下的 SVG 文件,使用 `svg-sprite-loader` 将 SVG 文件打包为一个精灵图,方便在项目中使用。
  1. **JavaScript 和 TypeScript 文件**:
  • 使用 `babel-loader` 转译 JavaScript 和 TypeScript 文件,支持 ES6+、React 和 TypeScript。

  • 使用 `@babel/preset-env` 按需导入 `core-js`,确保兼容性。

  • 使用 `@babel/preset-react` 支持 JSX 语法。

  • 使用 `@babel/preset-typescript` 支持 TypeScript。

  • 在开发模式下启用 `react-refresh/babel` 插件,支持热更新。

插件(`plugins`)

  1. **`EslintWebpackPlugin`**:
  • 在构建过程中运行 ESLint,确保代码风格一致并发现潜在问题。
  1. **`HtmlWebpackPlugin`**:
  • 自动生成 HTML 文件,并将打包后的 JS 和 CSS 文件注入到 HTML 中。
  1. **`WebpackBar`**:
  • 在控制台显示一个进度条,方便观察构建进度。
  1. **`CopyWebpackPlugin`**:
  • 将 `public` 目录下的文件(除了 `index.html`)复制到输出目录。
  1. **`SpriteLoaderPlugin`**:
  • 用于处理 SVG 精灵图。
  1. **`MiniCssExtractPlugin`**:
  • 在生产模式下提取 CSS 为单独的文件。
  1. **`ReactRefreshWebpackPlugin`**:
  • 在开发模式下启用 React 热更新。

优化(`optimization`)

  1. **`minimize`**:
  • 在生产模式下启用代码压缩。
  1. **`minimizer`**:
  • 使用 `CssMinimizerWebpackPlugin` 和 `TerserWebpackPlugin` 分别压缩 CSS 和 JavaScript 文件。
  1. **`splitChunks`**:
  • 配置代码分割,将公共模块(如 React、Ant Design 等)提取到单独的文件中,减少重复代码,提高缓存效率。
  1. **`runtimeChunk`**:
  • 将 Webpack 的运行时代码提取到单独的文件中,提高缓存效率。

开发服务器(`devServer`)

  • 配置开发服务器,支持热更新、压缩、自定义主机和端口等。

源码映射(`devtool`)

  • 在生产模式下使用 `source-map`,在开发模式下使用 `eval-cheap-module-source-map`,方便调试。

性能(`performance`)

  • 禁用性能提示,设置最大入口点和资源大小,避免构建过程中出现警告。

这个配置文件涵盖了从开发到生产环境的各种需求,确保项目在开发时具有良好的开发体验,在生产环境中具有高效的构建和优化。

相关推荐
醉方休10 小时前
vite与webpack对比
前端·webpack·devops
wallflower202011 小时前
🚀 从 Webpack 到 Vite:企业级前端构建、代码分割与懒加载优化完全指南
webpack·vite
一枚前端小能手16 小时前
🚀 Webpack打包慢到怀疑人生?这6个配置让你的构建速度起飞
前端·javascript·webpack
全栈技术负责人20 小时前
webpack性能优化指南
webpack·性能优化·devops
和雍1 天前
webpack5 创建一个 模块需要几步?
javascript·面试·webpack
渊不语3 天前
Webpack 深入学习指南
前端·webpack
光影少年3 天前
webpack打包优化都有哪些
前端·webpack·掘金·金石计划
小宋搬砖第一名5 天前
深入剖析 Webpack AsyncQueue 源码:异步任务调度的核心
前端·webpack
飞阿飞飞7 天前
Webpack(一)基本概念+使用方法(新手渡劫)
前端·webpack