webpack 配置

1、基础配置

javascript 复制代码
// node js核心模塊
const path = require('path')
// 插件是需要引入使用的
const ESLintPlugin = require('eslint-webpack-plugin')
// 自动生成index.html
const HtmlWebpackPlugin = require('html-webpack-plugin');
// 将css文件单独打包,在index.html中使用 link引入,不使用 style
// 因为 style 标签,在网络慢的情况下加载的时候,有可能一加载时啥也没有,然后突然就出现东西
// 因为 style 是有js创建的, 需要等待js执行完才行,但是link不用等待
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
// css 压缩
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin")
// 引入多进程成相关的配置
const TerserWebpackPlugin = require("terser-webpack-plugin")
// 引入Cpu 相关的东西,获取cpu核数,需要对应的安装 thread-loader
const os = require('os')
const threads = os.cpus().length

function getCssLoader(pre){
    return [
        MiniCssExtractPlugin.loader,
        "css-loader",
        {
            loader: "postcss-loader",
            options: {
                postcssOptions: {
                    plugins: [
                        [
                            "postcss-preset-env",
                            {
                            // Options
                            },
                        ],
                    ],
                },
            },
        },
        pre
    ].filter(Boolean)
}


/**
 * webpack 优化 从下面四个角度找方法(plugins/loader 及结合其他方式)
 * 1、提升开发体验
 *      devtool: 配置 devtool: 'source-map'
 * 2、提升打包构建速度
 *      2.1、oneOf的使用
 *      2.2、include/exclude
 *      2.3、cache babel/eslint
 * 3、减少代码体积
 *      tree-shaking 去除用不上代码,webpack 默认配置
 * 4、优化代码运行性能
 *      4.1、code split代码分割
 *          分割文件: 将打包生成的文件进行分割,生成多个js文件
 *          按需加载: 需要那个文件就加载那个文件 import()
 */


// 运营命令 npx webpack --config ./config/webpack.prod.js
module.exports = {
    // 入口
    entry: "./src/main.js",
    // 输出
    output: {
        // 需要回退一下路径,因为当前文件,不是在根目录下
        path:  path.resolve(__dirname, "../dist"),
        filename: 'static/js/main.js',
        // chunk 模块命名
        chunkFilename: 'static/js/[name].chunk.js',
        // 其他公共模块,这里是字体图标与图片都放一起了
        assetModuleFilename: "static/media/[hash:10][ext][query]",
        // 每次打包前都先清空dist
        clean: true
    },
    // 加载器
    module: {
        rules:[
            {
                oneOf: [
                    {
                        test: /\.css$/i,
                        use: getCssLoader(),
                    },
                    {
                        test: /\.less$/i,
                        use: getCssLoader("less-loader"),
                    },
                    {
                        test: /\.s[ac]ss$/i,
                        use: getCssLoader("sass-loader"),
                    },
                    {
                        test: /\.(jpg|png|svg|jpeg)$/,
                        type: 'asset',
                        parser: {
                            dataUrlCondition: {
                                // 设置图片小于多少kb就转成base64 字符串
                                // 有点事可以减少请求,缺点是内容会变大,大图会变更大,所以大图不转
                                // webpack5 内置了 file-loader 与 url-loader 但是这个转base操作需要自己开启
                                maxSize: 30 * 1024 // 30kb
                            }
                        },
                        // 图片放到自己的目录
                        // generator: {
                        //     // hash 值保留十位
                        //     filename: 'static/image/[hash:10][ext][query]'
                        // }
                    },
                    {
                        // 处理字体图标及媒体相关文件
                        test: /\.(ttf|woff2?|map3|map4|avi)$/,
                        // 小图不转base64, 原封不动
                        type: 'asset/resource',
                        // 图片放到自己的目录
                        // generator: {
                        //     // hash 值保留十位
                        //     filename: 'static/media/[hash:10][ext][query]'
                        // }
                    },
                    {
                        test: /\.(?:js|mjs|cjs)$/,
                        // include: path.resolve(__dirname, "src")
                        exclude: /node_modules/,    // 排除那些文件,这些文件不处理
                        use: [
                            {
                                loader: "thread-loader",
                                options: {
                                    // 工作的 cpu 核数
                                    works: threads
                                }
                            },
                            // 对于promise 数组一些高级方法 例如 includes 有些低版本浏览器不兼容,需要 corejs 做处理
                            {
                                loader: 'babel-loader',
                                // 这个配置一般可以在这配置,也可以在外边使用 babel.config.js 配置
                                // options: {
                                //     presets: [
                                //     ['@babel/preset-env', { targets: "defaults" }]
                                //     ]
                                // }
                                options: {
                                    // 开启缓存,第一次,不会起作用,第二次之后,每次打包
                                    // 都只会检查改变的那些文件
                                    cacheDirectory: true,
                                    // 不开启缓存文件压缩,会拖慢速度
                                    cacheCompression: false,
                                    // 减少代码体积,因为babel会给每个js 文件添加一些辅助代码(例如__extend函数定义)
                                    // 是用了,下面这个,所有js文件就会统一从下面这个获取,节俭代码体积
                                    plugins: ["@babel/plugin-transform-runtime"]
                                }
                            }
                        ]
                    }
                ]
            }
        ]
    },
    // 插件
    plugins: [
        new ESLintPlugin({
            // 检查那些文件
            // 这会会报错,得有eslint配置文件才行, 例如 .eslintrc.js
            context: path.resolve(__dirname, "../src"),
            // 开启缓存
            cache: true,
            // 缓存路径
            cacheLocation: path.resolve(
                __dirname,
                "../node_modules/.cache/eslintcache"
            ),
            // 开启多进程
            threads,
        }),
        // 这个插件可以自动引入,打包文件
        new HtmlWebpackPlugin({
            // 以这个文件为模板,自动生成index.html 文件
            template: 'public/index.html'
        }),
        new MiniCssExtractPlugin({
            // 所有 样式文件合成一个,多个文件的时候使用各自的名字
            filename: "static/css/[name].css",
            // 对于一些动态引入的css 模块的打包文件名
            chunkFilename: "static/css/[name].chunk.css"
        }),
    ],
    // 官方放压缩的地方,生产才会有压缩,开发没有压缩,不需要
    optimization: {
        minimizer:[
             // 开启css压缩
            new CssMinimizerPlugin(),
            // 压缩js
            new TerserWebpackPlugin({
                // 开启多进程和设置进程数量, 但是这是对于js打包比较慢的情况才合适
                // 否则开进程也是需要耗时的
                parallel: threads
            })
        ],
        // 代码分割配置, a.js b.js 都引入c.js 都会在a.js b.js 中引入,但是这样配置之后就不会了
        // 但是打包后会多出一份文件 xx.js a ,文件下也会多出 一些引用c.js文件的代码
        splitChunks: {
            chunks: "all", // 对所有模块都进行分割
            // 以下是默认值
            // minSize: 20000, // 分割代码最小的大小
            // minRemainingSize: 0, // 类似于minSize,最后确保提取的文件大小不能为0
            // minChunks: 1, // 至少被引用的次数,满足条件才会代码分割
            // maxAsyncRequests: 30, // 按需加载时并行加载的文件的最大数量
            // maxInitialRequests: 30, // 入口js文件最大并行请求数量
            // enforceSizeThreshold: 50000, // 超过50kb一定会单独打包(此时会忽略minRemainingSize、maxAsyncRequests、maxInitialRequests)
            // cacheGroups: { // 组,哪些模块要打包到一个组
            //   defaultVendors: { // 组名
            //     test: /[\\/]node_modules[\\/]/, // 需要打包到一起的模块
            //     priority: -10, // 权重(越大越高)
            //     reuseExistingChunk: true, // 如果当前 chunk 包含已从主 bundle 中拆分出的模块,则它将被重用,而不是生成新的模块
            //   },
            //   default: { // 其他没有写的配置会使用上面的默认值
            //     minChunks: 2, // 这里的minChunks权重更大
            //     priority: -20,
            //     reuseExistingChunk: true,
            //   },
            // },
            // 修改配置
            // cacheGroups: {
            // 组,哪些模块要打包到一个组
            // defaultVendors: { // 组名
            //   test: /[\\/]node_modules[\\/]/, // 需要打包到一起的模块
            //   priority: -10, // 权重(越大越高)
            //   reuseExistingChunk: true, // 如果当前 chunk 包含已从主 bundle 中拆分出的模块,则它将被重用,而不是生成新的模块
            // },
            //   default: {
            //     // 其他没有写的配置会使用上面的默认值
            //     minSize: 0, // 我们定义的文件体积太小了,所以要改打包的最小文件体积
            //     minChunks: 2,
            //     priority: -20,
            //     reuseExistingChunk: true,
            //   },
            // },
        },
    },
    // 模式, 默认开启 js 及 html 压缩
    mode: 'production',
    // 开启代码映射,当代吗出错的时候,就可以在控制台 有对应的出错位置映射,具有行与列映射
    devtool: 'source-map'
}

corejs处理,在项目根目录下的 babel.config.js 文件配置

javascript 复制代码
module.exports = {
    presets: [
        [
            '@babel/preset-env',
            {
                // 按需加载,自动引入,corejs 相关包
                useBuiltIns: "usage",
                corejs: 3
            }
        ]
    ]
}

2、高级优化

3、Vue脚手架 webpack配置

项目文件目录

webpack.config.js文件

javascript 复制代码
const path = require("path");
const EslintWebpackPlugin = require("eslint-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CssMinimizerWebpackPlugin = require("css-minimizer-webpack-plugin");
const TerserWebpackPlugin = require("terser-webpack-plugin");
const ImageMinimizerPlugin = require("image-minimizer-webpack-plugin");
const CopyPlugin = require("copy-webpack-plugin");
const { VueLoaderPlugin } = require("vue-loader");
const { DefinePlugin } = require("webpack");
const AutoImport = require("unplugin-auto-import/webpack");
const Components = require("unplugin-vue-components/webpack");
const { ElementPlusResolver } = require("unplugin-vue-components/resolvers");

const isProduction = process.env.NODE_ENV === "production";

// 返回处理样式loader函数
const getStyleLoaders = (pre) => {
  return [
    isProduction ? MiniCssExtractPlugin.loader : "vue-style-loader",
    "css-loader",
    {
      // 处理css兼容性问题
      // 配合package.json中browserslist来指定兼容性
      loader: "postcss-loader",
      options: {
        postcssOptions: {
          plugins: ["postcss-preset-env"],
        },
      },
    },
    pre && {
      loader: pre,
      options:
        pre === "sass-loader"
          ? {
              additionalData: `@use "@/styles/element/index.scss" as *;`,
            }
          : {},
    },
  ].filter(Boolean);
};

module.exports = {
  entry: "./src/main.js",
  output: {
    path: isProduction ? path.resolve(__dirname, "../dist") : undefined,
    filename: isProduction ? "static/js/[name].[contenthash:10].js" : "static/js/[name].js",
    chunkFilename: isProduction ? "static/js/[name].[contenthash:10].chunk.js" : "static/js/[name].chunk.js",
    assetModuleFilename: "static/media/[hash:10][ext][query]",
    clean: true,
  },
  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: /\.js$/,
        include: path.resolve(__dirname, "../src"),
        loader: "babel-loader",
        options: {
          cacheDirectory: true,
          cacheCompression: false,
        },
      },
      {
        test: /\.vue$/,
        loader: "vue-loader",
        options: {
          // 开启缓存
          cacheDirectory: path.resolve(__dirname, "../node_modules/.cache/vue-loader"),
        },
      },
    ],
  },
  // 处理html
  plugins: [
    new EslintWebpackPlugin({
      context: path.resolve(__dirname, "../src"),
      exclude: "node_modules",
      cache: true,
      cacheLocation: path.resolve(__dirname, "../node_modules/.cache/.eslintcache"),
    }),
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, "../public/index.html"),
    }),
    isProduction &&
      new MiniCssExtractPlugin({
        filename: "static/css/[name].[contenthash:10].css",
        chunkFilename: "static/css/[name].[contenthash:10].chunk.css",
      }),
    isProduction &&
      new CopyPlugin({
        patterns: [
          {
            from: path.resolve(__dirname, "../public"),
            to: path.resolve(__dirname, "../dist"),
            globOptions: {
              // 忽略index.html文件
              ignore: ["**/index.html"],
            },
          },
        ],
      }),
    new VueLoaderPlugin(),
    // cross-env定义的环境变量给打包工具使用
    // DefinePlugin定义环境变量给源代码使用,从而解决vue3页面警告的问题
    new DefinePlugin({
      __VUE_OPTIONS_API__: true,
      __VUE_PROD_DEVTOOLS__: false,
    }),
    // 按需加载element-plus
    AutoImport({
      resolvers: [ElementPlusResolver()],
    }),
    Components({
      resolvers: [
        ElementPlusResolver({
          // 自定义主题,引入sass
          importStyle: "sass",
        }),
      ],
    }),
  ].filter(Boolean),
  mode: isProduction ? "production" : "development",
  devtool: isProduction ? "source-map" : "cheap-module-source-map",
  optimization: {
    splitChunks: {
      chunks: "all",
      cacheGroups: {
        vue: {
          test: /[\\/]node_modules[\\/]vue(.*)?[\\/]/,
          name: "vue-chunk",
          priority: 40,
        },
        elementPlus: {
          test: /[\\/]node_modules[\\/]element-plus[\\/]/,
          name: "elementPlus-chunk",
          priority: 30,
        },
        libs: {
          test: /[\\/]node_modules[\\/]/,
          name: "libs-chunk",
          priority: 20,
        },
      },
    },
    runtimeChunk: {
      name: (entrypoint) => `runtime~${entrypoint.name}.js`,
    },
    minimize: isProduction,
    minimizer: [
      new CssMinimizerWebpackPlugin(),
      new TerserWebpackPlugin(),
      new ImageMinimizerPlugin({
        minimizer: {
          implementation: ImageMinimizerPlugin.imageminGenerate,
          options: {
            plugins: [
              ["gifsicle", { interlaced: true }],
              ["jpegtran", { progressive: true }],
              ["optipng", { optimizationLevel: 5 }],
              [
                "svgo",
                {
                  plugins: [
                    "preset-default",
                    "prefixIds",
                    {
                      name: "sortAttrs",
                      params: {
                        xmlnsOrder: "alphabetical",
                      },
                    },
                  ],
                },
              ],
            ],
          },
        },
      }),
    ],
  },
  // webpack解析模块加载选项
  resolve: {
    // 自动补全文件扩展名
    extensions: [".vue", ".js", ".json"],
    // 路径别名
    alias: {
      "@": path.resolve(__dirname, "../src"),
    },
  },
  devServer: {
    host: "localhost",
    port: 3000,
    open: true,
    hot: true, // 开启HMR
    historyApiFallback: true, // 解决前端路由刷新404问题
  },
  performance: false,
};

.eslintrc.js 文件

javascript 复制代码
module.exports = {
  root: true,
  env: {
    node: true,
  },
  extends: ["plugin:vue/vue3-essential", "eslint:recommended"],
  parserOptions: {
    parser: "@babel/eslint-parser",
  },
};

babel.config.js文件

javascript 复制代码
module.exports = {
  presets: ["@vue/cli-plugin-babel/preset"],
};

记录学习 webpack 的过程

相关推荐
垣宇12 小时前
Vite 和 Webpack 的区别和选择
前端·webpack·node.js
小纯洁w1 天前
Webpack 的 require.context 和 Vite 的 import.meta.glob 的详细介绍和使用
前端·webpack·node.js
海盗强1 天前
Webpack打包优化
前端·webpack·node.js
祈澈菇凉2 天前
如何优化 Webpack 的构建速度?
前端·webpack·node.js
懒羊羊我小弟2 天前
常用 Webpack Plugin 汇总
前端·webpack·npm·node.js·yarn
祈澈菇凉3 天前
Webpack的持久化缓存机制具体是如何实现的?
前端·webpack·gulp
懒羊羊我小弟4 天前
Webpack 基础入门
前端·webpack·rust·node.js·es6
刽子手发艺4 天前
Selenium+OpenCV处理滑块验证问题
opencv·selenium·webpack
懒羊羊我小弟4 天前
常用Webpack Loader汇总介绍
前端·webpack·node.js
真的很上进6 天前
【1.8w字深入解析】从依赖地狱到依赖天堂:pnpm 如何革新前端包管理?
java·前端·vue.js·python·webpack·node.js·reactjs