素说Webpack(2):一个典型的Webpack4配置

391 阅读3分钟

一个Webpack配置文件的构成

  • mode 输出模式
  • entry 入口文件
  • output 输出位置配置
  • module.rules 不同源码模块的加载规则配置(即使用不同loader加载不同模块)
  • plugins loader以外的工作配置
  • devServer 配置开发服务器(代理+热更新)
  • optimization 优化配置
  • optimization.minify 文件压缩
  • optimization.splitChunks 分包配置

一个完整的webpack.config.js配置案例

具体细节可查阅: Webpack官方文档

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

module.exports = {

    /* 打包模式(生产模式下会自动开启Tree-Shaking) */
    // mode: "development",
    mode: "production",

    /* 入口JS文件 每个入口文件对应着一棵依赖树 */
    entry: {
        index: "../src/js/index.js",
        other: "../src/js/other.js",
    },

    /* bundle输出位置 */
    /* dev */
    output: {
        // 根据js文件内容不同 生成不同的哈希 用于判断是否应该重新下载该文件
        filename: "[name].[hash8].js", 

        // bundle输出文件夹
        path: "D:/phpStudy/WWW/jdzb_client_js",
    },

    /* 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模块 */
            {
                // 找到所有的js文件
                test: /\.js$/, // 使用babel-loader做ES高级语法向ES5的转换

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

                // 查找范围仅限于src目录
                include: "../src",

                // 不查找node_modules目录
                exclude: /node_modules/,
            },

            /* dev */
            /* 编译加载图片模块 */
            // {
            //     test: /\.(png|jpg|jpeg|gif)$/,
            //     use: [
            //         {
            //             loader: "file-loader",
            //             options: {},
            //         },
            //     ],
            // },

            // 开发环境下CSS的配置
            /* 编译加载CSS模块 */
            // {
            //     test: /\.css$/,

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

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

            /* prod */
            /* 编译加载图片模块 */
            // 考虑 base64 编码的情况
            {
                test: /\.(png|jpg|jpeg|gif)$/,
                use: {
                    loader: "url-loader",
                    options: {
                        // 小于 5kb 的图片用 base64 格式产出
                        // 否则,依然延用 file-loader 的形式,产出 url 格式
                        limit: 1 * 1024,

                        // 输出到bundle根目录下的img文件夹
                        outputPath: "img/",

                        // 不一定以ESM模块形式去引入
                        // 不要看到源代码中未以ESM模块形式去引入a.png 就给哥tree-shaking掉(html中可能以src形式引用)
                        esModule: false,
                    },
                },
            },

            /* 编译加载CSS模块 */
            // 抽离css
            {
                test: /\.css$/,
                use: [

                    // 将样式统一提取到独立的CSS文件
                    MiniCssExtractPlugin.loader,

                    // 加载CSS文件
                    "css-loader",

                    // 先对C3的样式定义加必要的浏览器兼容前缀
                    "postcss-loader",
                ],
            },

            /* 编译加载SCSS模块 */
            {
                test: /\.scss$/,
                use: [
                    MiniCssExtractPlugin.loader,
                    "css-loader",

                    // 将SCSS编译为CSS
                    "sass-loader",
                    "postcss-loader",
                ],
            },
        ],
    },

    plugins: [
        /* common */
        /* 为html文件注入自动识别hash后缀的能力 */
        new HtmlWebpackPlugin({
            // 令html识别原始的<img src="xxx"/>
            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,
            },

            // 需要依赖的具体chunk
            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({
        //     // 相当于定义全局变量const ENV = 'production'
        //     ENV: JSON.stringify("development"),
        // }),

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

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

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

    ],

    /* dev */
    /* 
    开发服务器(生产环境下使用Nginx)
    1. 跨域代理
    2. 模块热更新(hot modudle replacement)
     */
    devServer: {
        hot: true, // 热更新
        port: 8000, // 测试服务器端口
        open: true, // 自动打开浏览器
        compress: true, // 启动 gzip 压缩

        /* 跨域代理 */
        proxy: {
            "/api": {
                target: "http://localhost:9000/api",
                changeOrigin: true,
                // webpack-dev-server通过websocket协议与浏览器的内核服务器保持长连接
                ws: true,

                // 覆盖/api为卵都没有
                pathRewrite: {
                    "^/api": "",
                },
            },
        },
    },

    /* prod */
    /* 性能优化选项 */
    optimization: {

        /* 压缩JS与CSS */
        minimizer: [
            new TerserPlugin(),
            new OptimizeCssAssetsPlugin({})
        ],

        /* 分包配置 */
        splitChunks: {
            // 同步异步都使用分包
            // initial 只考虑同步引入 import xxx from "path"
            // async   只考虑异步引入 const About = import(path)
            // all     同步异步都考虑
            chunks: "all",

            /* 拆包配置 */
            cacheGroups: {

                // 第三方模块统一拆到vender.js中
                vendor: {
                    name: "vendor", // chunk 名称
                    priority: 1, // 权限更高的优先抽离,重要!!!
                    test: /node_modules/,
                    minSize: 0, // 大小限制
                    minChunks: 1, // 最少复用过几次
                },

                // utils下的轮子统一拆到common.js中
                common: {
                    name: "common", // chunk 名称
                    priority: 0, // 优先级
                    test: /src\/utils/,
                    minSize: 0, // 公共模块的大小限制
                    minChunks: 1, // 公共模块最少复用过几次
                },

            },
        },

    },
};

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

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

git clone https://gitee.com/steveouyang/learn_webpack.git
cd learn_js_pro
git checkout feat1-wp4
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;
        }
    }

下一篇我们来讲讲Webpack5与4的几个主要不同