素说Webpack(3):一个典型的Webpack5配置

520 阅读2分钟

Webpack4与5的核心不同

  • merge函数的引入方式
// const merge = require("webpack-merge");
const { merge } = require("webpack-merge");
  • CSS的压缩插件变化: 由optimize-css-assets-webpack-plugin变更为css-minimizer-webpack-plugin
// const OptimizeCssAssetsPlugin = require("optimize-css-assets-webpack-plugin");
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");

module.exports = {
    ...
    optimization: {
        ...
        minimizer: [
            new TerserPlugin(),

            // new OptimiazeCssAssetPlugin(),
            new CssMinimizerPlugin(),
        ],
        ...
}
  • optimization中的压缩配置变化
    optimization: {
        /* Webpack4 => Webpack5 */
        // minimizer: [
        //     new TerserPlugin(), 
        //     new OptimizeCssAssetsPlugin({})
        // ],
        
        usedExports: true, //只导出被使用的模块
        minimize: true, // 启动压缩
        concatenateModules: true,
        minimizer: [
            new TerserPlugin(),

            // new OptimiazeCssAssetPlugin(),
            new CssMinimizerPlugin(),
        ],
    },
  • 图片文件的加载方式由file-loader/url-loader变更为assets类型定义
    关于asset详见:官方文档描述
    // {
    //     test: /\.(png|jpg|jpeg|gif)$/,
    //     use: {
    //         loader: "url-loader",
    //         options: {
    //             // 小于 5kb 的图片用 base64 格式产出
    //             // 否则,依然延用 file-loader 的形式,产出 url 格式
    //             limit: 5 * 1024,

    //             // 打包到 img 目录下
    //             outputPath: "img/",

    //             // 不一定以ESM模块形式去引入
    //             // 不要看到源代码中未以ESM模块形式去引入a.png 就给哥tree-shaking掉(html中可能以src形式引用)
    //             esModule: false,
    //         },
    //     },
    // },
    {
        // 图标的转化
        test: /\.(woff|woff2|eot|ttf|otf|svg)$/i,
        type: "asset/resource",
    },
    {
        // 图片的转化
        test: /\.(jpe?g|png|gif|bmp)$/i,
        // type: "asset/resource",
        // type: "asset/inline",

        // 自动切换resource与inline
        type: "asset",
        parser: {
            dataUrlCondition: {
                maxSize: 8192, // 8kb
            },
        },
    },

以下是一个比较典型的Webpack5工程配置案例

/* 引入webpack及配置合并函数 */
const webpack = require("webpack");

/* Webpack4 => Webpack5 */
// const merge = require("webpack-merge");
const { merge } = require("webpack-merge");

/* 引入本地输出路径 */
const path = require("path");
const { srcPath, distPath, wwwPath } = require("./path");

/* 引入通用配置对象(等待合并) */
const commonConf = require("./webpack.common.js");

/* 引入各种功能插件 */
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const TerserPlugin = require("terser-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

/* Webpack4 => Webpack5 */
// const OptimizeCssAssetsPlugin = require("optimize-css-assets-webpack-plugin");
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");

module.exports = {
    /* 输出模式 */
    // mode: "development",
    mode: "production",

    /* 入口文件 每个入口文件对应着一棵依赖树 */
    entry: {
        index: path.join(srcPath, "js", "index.js"),
        other: path.join(srcPath, "js", "other.js"),
    },

    /* bundle输出位置 */
    /* dev */
    // output: {
    //     filename: "[name].[hash].js", // 打包代码时,加上 hash 戳
    //     path: distPath,
    // },

    /* prod */
    output: {
        filename: "[name].[contenthash:8].js", // 打包代码时,加上 hash 戳
        path: wwwPath,

        // 如果有CDN
        // publicPath: 'http://cdn.abc.com'

        // 异步chunk输出位置
        chunkFilename: "async/[id].js",
    },

    /* 使用不同【loader+具体配置】去编译加载不同【源码模块】 */
    module: {
        rules: [
            /* common */
            {
                // 找到所有的js文件
                test: /\.js$/, // 使用babel-loader做ES高级语法向ES5的转换

                use: ["babel-loader"] /* 以下两个只需要写一个 */,

                // 查找范围仅限于src目录
                include: srcPath,
                exclude: /node_modules/,
            },

            // 开发环境下CSS的配置
            {
                test: /\.css$/,

                // loader 的执行顺序是:从后往前
                /* 
                postcss.config.js中的配置
                module.exports = {
                    plugins: [require("autoprefixer")],
                };
                */
                use: ["style-loader", "css-loader", "postcss-loader"],
            },

            /* Webpack4 => Webpack5 */
            /* 关于asset详见:https://webpack.docschina.org/guides/asset-modules/ */
            // {
            //     test: /\.(png|jpg|jpeg|gif)$/,
            //     use: [
            //         {
            //             loader: "file-loader",
            //             options: {},
            //         },
            //     ],
            // },
            {
                // 图片的转化
                test: /\.(jpe?g|png|gif|bmp)$/i,
                type: "asset/resource",
            },

            // scss开发环境
            {
                test: /\.scss$/, // 增加 'less-loader' ,注意顺序
                use: [
                    "style-loader",
                    "css-loader",
                    "sass-loader",
                    "postcss-loader",
                ],
            },

            /* prod */
            /* Webpack4 => Webpack5 */
            /* 关于asset详见:https://webpack.docschina.org/guides/asset-modules/ */
            // {
            //     test: /\.(png|jpg|jpeg|gif)$/,
            //     use: {
            //         loader: "url-loader",
            //         options: {
            //             // 小于 5kb 的图片用 base64 格式产出
            //             // 否则,依然延用 file-loader 的形式,产出 url 格式
            //             limit: 5 * 1024,

            //             // 打包到 img 目录下
            //             outputPath: "img/",

            //             // 不一定以ESM模块形式去引入
            //             // 不要看到源代码中未以ESM模块形式去引入a.png 就给哥tree-shaking掉(html中可能以src形式引用)
            //             esModule: false,
            //         },
            //     },
            // },
            {
                // 图标的转化
                test: /\.(woff|woff2|eot|ttf|otf|svg)$/i,
                type: "asset/resource",
            },
            {
                // 图片的转化
                test: /\.(jpe?g|png|gif|bmp)$/i,
                // type: "asset/resource",
                // type: "asset/inline",

                // 自动切换resource与inline
                type: "asset",
                parser: {
                    dataUrlCondition: {
                        maxSize: 8192, // 8kb
                    },
                },
            },

            // 生产环境下CSS配置
            // 抽离 css
            {
                test: /\.css$/,
                use: [
                    MiniCssExtractPlugin.loader,
                    "css-loader",
                    "postcss-loader",
                ],
            },

            {
                test: /\.scss$/,
                use: [
                    MiniCssExtractPlugin.loader,
                    "css-loader",
                    "sass-loader",
                    "postcss-loader",
                ],
            },
        ],
    },

    plugins: [
        /* common */
        new HtmlWebpackPlugin({
            template: `html-withimg-loader!${path.join(srcPath, "index.html")}`,
            filename: "index.html",
            minify: {
                collapseWhitespace: true,
                keepClosingSlash: true,
                removeComments: true,
                removeRedundantAttributes: true,
                removeScriptTypeAttributes: true,
                removeStyleLinkTypeAttributes: true,
                useShortDoctype: true,
            },
            chunks: ["index", "common"],
        }),

        new HtmlWebpackPlugin({
            template: `html-withimg-loader!${path.join(
                srcPath,
                "views",
                "other.html"
            )}`,
            filename: "other.html",
            minify: {
                collapseWhitespace: true,
                keepClosingSlash: true,
                removeComments: true,
                removeRedundantAttributes: true,
                removeScriptTypeAttributes: true,
                removeStyleLinkTypeAttributes: true,
                useShortDoctype: true,
            },
            chunks: ["other", "common", "vendor"],
        }),

        /* dev */
        new webpack.DefinePlugin({
            // 相当于window.ENV = 'production'
            ENV: JSON.stringify("development"),
        }),

        // 会默认清空 output.path 文件夹
        new CleanWebpackPlugin(),

        /* prod */
        // 抽离 css 文件
        new MiniCssExtractPlugin({
            filename: "css/[name].[contenthash:8].css",
        }),

        new webpack.DefinePlugin({
            ENV: JSON.stringify("production"),
        }),

        new CleanWebpackPlugin(),
    ],

    /* dev */
    devServer: {
        hot: true, // 热更新
        port: 8000, // 测试服务器端口
        open: true, // 自动打开浏览器
        compress: true, // 启动 gzip 压缩
        proxy: {
            "/api": {
                target: "http://localhost:9000/api",
                changeOrigin: true,
                ws: true,
                pathRewrite: {
                    "^/api": "",
                },
            },
        },
    },

    /* prod */
    optimization: {

        /* Webpack4 => Webpack5 */
        // minimizer: [
        //     new TerserPlugin(), 
        //     new OptimizeCssAssetsPlugin({})
        // ],
        usedExports: true, //只导出被使用的模块
        minimize: true, // 启动压缩
        concatenateModules: true,
        minimizer: [
            new TerserPlugin(),

            // new OptimiazeCssAssetPlugin(),
            new CssMinimizerPlugin(),
        ],

        splitChunks: {
            // 同步异步都使用分包
            chunks: "all",
            cacheGroups: {
                // 第三方模块
                vendor: {
                    name: "vendor", // chunk 名称
                    priority: 1, // 权限更高的优先抽离,重要!!!
                    test: /[\\/]node_modules[\\/]/,
                    minSize: 0, // 大小限制
                    minChunks: 1, // 最少复用过几次
                },

                // 公共的模块
                common: {
                    name: "common", // chunk 名称
                    test:/[\\/]src[\\/]utils[\\/]/
                    priority: 2, // 优先级
                    minSize: 0, // 公共模块的大小限制
                    minChunks: 1, // 公共模块最少复用过几次
                },
            },
        },
    },
};

以下是一个能跑起来的Webpack5工程配置

原生JS仿京东首页+Webpack5打包

git clone https://gitee.com/steveouyang/learn_webpack.git
cd learn_js_pro
git checkout feat2-wp5
npm i
npm run mock
npm run dev
npm run build

配套的Nginx配置

    server {
        listen       8002;
        server_name  localhost;

        root   "D:/phpStudy/WWW/jdzb_client_js";

        location / {
           index  index.html;
           autoindex  on;
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

        location /api {
           proxy_pass   http://10.3.134.65:9000/api;
        }
    }