webpack5 (四)

react-cli 中配置

开发环境

const path = require('path')
const EslintWebpackPlugin = require('eslint-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
//封装处理样式配置
const getStyleloaders = (pre)=>{
    return [
        'style-loader',
        'css-loader',
        // 处理 css 兼容性问题
        //需要配合 package.json 中的browserslist 来指定兼容性做到什么程度
        {
            loader: 'postcss-loader',
            options: {
                postcssOptions: {
                    plugins: 'postcss-preset-env'
                }
            }
        },
        pre
    ].filter(Boolean)
};
//要用 commonjs的方式以对象的模式暴露出去
module.exports = {
    // 入口文件
    entry: './src/main.js',
    // 出口文件
    output: {
        path: undefined,
        filename: 'static/js/[name].js',
        chunkFilename: 'static/js/[name].chunk.js',
        assetModuleFilename: 'static/media/[hash:10][etx][query]'
    },
    // 配置loader
    module: {
        rules: [
            // 处理 css 
            {
                test: /\.css$/,
                use: getStyleloaders()
            },
            {
                test: /\.less$/,
                use: getStyleloaders('less-loader')
            },
            {
                test: /\.s[ac]ss$/,
                use: getStyleloaders('sass-loader')
            },
            {
                test: /\.styl$/,
                use: getStyleloaders('stylus-loader')
            },
            // 处理 图片
            {
                test:/\.(jpe?g|png|gif|webp|svg)$/,
                type:'asset',
                parser:{
                    dataUrlCondition:{
                        maxSize:10*1024,
                    }
                }
            },
            //处理其他资源
            {
                test:/\.(woff2?|ttf)$/,
                type:'asset/resource'
            },
            // 处理 js
            {
                test:/\.jsx?$/,
                include:path.resolve(__dirname,'../src'),
                loader:'babel-loader',//babel 也需要有一个 babel 的配置文件
                options:{
                    catchDirectory:true,
                    catchCompression:false,
                    plugins:[
                        'react-refresh/babel',//用来解决react脚手架下 js不能热更新的问题
                    ]
                }
            }
        ]
    },
    // 配置plugin
    // 处理html 
    plugin:[
        //eslint 插件也是需要有自己的配置文件
        new EslintWebpackPlugin({
            context:path.resolve(__dirname,'../src'),
            exclude:'node_modules',
            cache:true,
            cacheLocation:path.resolve(__dirname,'../node_modules/.catch/.eslintcache'),
        }),
        new HtmlWebpackPlugin({
            template:path.resolve(__dirname,'../public/index.html'),
        }),
        new ReactRefreshWebpackPlugin()//用来解决react脚手架下 js不能热更新的问题
    ],
    // 环境设置
    mode:'development',
    devtool:'cheap-module-source-map',
    optimization:{
        splitChunks:{
            chunks:'all'
        },
        runtimeChunk:{
            name:(entrypoint)=>`runtime~${entrypoint.name}.js`,
        }
    },
    //webpack 解析模块加载选项 
    // 解决运行react项目时报错 Module not found:Error:can't resolve './App' in 'xx/xxx/xxx/x'
    resolve:{
        //自动补全文件扩展名
        extentions:['.jsx','.js','json']
    },
    devServer:{
        host:'localhost',
        port:3000,
        open:true,
        hot:true,
        historyApiFallback:true,//解决前端路由刷新404问题
    }
}

生产模式

const path = require('path')
const EslintWebpackPlugin = require('eslint-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
// 生产模式下不需要激活热更新
// const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
// CSS提取为单独文件
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
// css 压缩文件
const CssMinimizerWebpackPlugin = require('css-minimizer-webpack-plugin')
// js 压缩,使用css压缩后必须使用的插件
const TerserWebpackPlugin = require('terser-webpack-plugin')
// 图片 压缩插件
const ImageMinimizerWebpackPlugin = require('image-minimizer-webpack-plugin')
// 如果出现 网站图标 需要用该复制插件将其复制到dist目录下
const CopyPlugin = require("copy-webpack-plugin");


const getStyleloaders = (pre) => {
    return [
        // 'style-loader',
        MiniCssExtractPlugin.loader,//将style-loader替换为插件loader,打包为单独文件
        'css-loader',
        {
            loader: 'postcss-loader',
            options: {
                postcssOptions: {
                    plugins: 'postcss-preset-env'
                }
            }
        },
        pre
    ].filter(Boolean)
};
module.exports = {
    entry: './src/main.js',
    output: {
        path: path.resolve(__dirname, '../dist'),//设置出口文件路径
        filename: 'static/js/[name].[contenthash:10].js',//加入哈希值
        chunkFilename: 'static/js/[name].[contenthash:10].chunk.js',//加入哈希值
        assetModuleFilename: 'static/media/[hash:10][etx][query]',
        clean: true,//将上次打包内容清空
    },
    module: {
        rules: [
            {
                test: /\.css$/,
                use: getStyleloaders()
            },
            {
                test: /\.less$/,
                use: getStyleloaders('less-loader')
            },
            {
                test: /\.s[ac]ss$/,
                use: getStyleloaders('sass-loader')
            },
            {
                test: /\.styl$/,
                use: getStyleloaders('stylus-loader')
            },
            {
                test: /\.(jpe?g|png|gif|webp|svg)$/,
                type: 'asset',
                parser: {
                    dataUrlCondition: {
                        maxSize: 10 * 1024,
                    }
                }
            },
            {
                test: /\.(woff2?|ttf)$/,
                type: 'asset/resource'
            },
            {
                test: /\.jsx?$/,
                include: path.resolve(__dirname, '../src'),
                loader: 'babel-loader',
                options: {
                    catchDirectory: true,
                    catchCompression: false,

                    // 生产模式下不需要激活热更新
                    // plugins:[
                    //     'react-refresh/babel',
                    // ]
                }
            }
        ]
    },
    plugin: [
        new EslintWebpackPlugin({
            context: path.resolve(__dirname, '../src'),
            exclude: 'node_modules',
            cache: true,
            cacheLocation: path.resolve(__dirname, '../node_modules/.catch/.eslintcache'),
        }),
        new HtmlWebpackPlugin({
            template: path.resolve(__dirname, '../public/index.html'),
        }),
        // new ReactRefreshWebpackPlugin(),// 生产模式下不需要激活热更新
        // css 打包为单独文件插件
        new MiniCssExtractPlugin({
            filename: 'static/css/name.[contenthash:10].css',
            chunkFilename: 'static/css/name.[contenthash:10].chunk.css'
        }),
        // 复制插件 处理public下其他资源 如网站图标
        new CopyPlugin({
            patterns: [
                // 设置从何处复制到何处
                {
                    from: path.resolve(__dirname,'../public'),
                    to: path.resolve(__dirname,'../dist')
                },
            ],
            globOptions: {
                //设置忽略 index.html 文件
                ignore: ['**/index.html']
            }
        }),
    ],
    mode: 'production', // 改为生产模式
    devtool: 'source-map',//使用 source-map
    optimization: {
        splitChunks: {
            chunks: 'all'
        },
        runtimeChunk: {
            name: (entrypoint) => `runtime~${entrypoint.name}.js`,
        },
        // 压缩插件放在 optimization 对象内
        minimizer: [
            new CssMinimizerWebpackPlugin(),//压缩 css 插件,
            new TerserWebpackPlugin(),//压缩 js 插件,
            //压缩图片插件,
            new ImageMinimizerWebpackPlugin({
                minimizerOptions: {
                    plugins: [
                        ["gifsicle", { interlaced: true }],
                        ["jpegtran", { progressive: true }],
                        ["optipng", { optimizationLevel: 5 }],
                        [
                            "svgo",
                            {
                                plugins: extendDefaultPlugins([
                                    {
                                        name: "removeViewBox",
                                        active: false,
                                    },
                                    {
                                        name: "addAttributesToSVGElement",
                                        params: {
                                            attributes: [{ xmlns: "http://www.w3.org/2000/svg" }],
                                        },
                                    },
                                ]),
                            },
                        ],
                    ],
                },
            }),
        ]
    },
    resolve: {
        extentions: ['.jsx', '.js', 'json']
    },

    //生产模式不需要devsever
    // devServer:{
    //     host:'localhost',
    //     port:3000,
    //     open:true,
    //     hot:true,
    //     historyApiFallback:true,
    // }
}

合并配置

将生产模式和开发模式的配置进行合并,通过 process.env.NODE_ENV 的值来判断当前为生产环境还是开发环境。

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


//三元判断 加载哪一个插件
isProd ? MiniCssExtractPlugin.loader : 'style-loader',


//根据是否为生产模式来决定是否加载插件
plugins:[
    !isProd && 'react-refresh/babel',//用来解决react脚手架下 js不能热更新的问题
].filter(Boolean)

你可能感兴趣的:(webpack5,前端,webpack)