webpack5通关指南(一)

webpack 基础

webpack5 官方文档

什么是 webpack

webpack 是一个用于现代 JavaScript 应用程序的 静态模块打包工具 。当 webpack 处理应用程序时,它会在内部从一个或多个入口点构建一个 依赖图(dependency graph),然后将你项目中所需的每一个模块组合成一个或多个 bundles,它们均为静态资源,用于展示你的内容。

安装 npmjs package.json内在机制

sh 复制代码
npm init -y
npm install webpack webpack-cli --save-dev
json 复制代码
// package.json配置
{
   "name": "webpack-demo",
   "version": "1.0.0",
   "description": "",
-  "main": "index.js",
+  "private": true,
   "scripts": {
     "test": "echo "Error: no test specified" && exit 1"
   },
   "keywords": [],
   "author": "",
   "license": "MIT",
   "devDependencies": {
     // 核心依赖
     "webpack": "^5.38.1",
     "webpack-cli": "^4.7.2"
   }
 }

配置文件

webpack 的配置文件是 JavaScript 文件,文件内导出了一个 webpack 配置的对象 webpack 会根据该配置定义的属性进行处理。配置文件名根目录创建 webpack.config.jswebpack.config.js 需要根据特定情况使用不同的配置文件,则可以通过在命令行中使用 --config 标志修改

json 复制代码
"scripts": {
  "build": "webpack --config prod.config.js"
}

常用loader

style-loadercss-loader

  1. css-loader: (解析 CSS 文件)

    • 作用 : css-loader 负责解析 CSS 文件,处理其中的 @importurl() 等语法,并将这些依赖关系转换为 Webpack 可以理解的模块。
    • 功能: 它可以将 CSS 文件中的内容转换为 JavaScript 模块,使得 CSS 可以被 JavaScript 动态加载和使用。
  2. style-loader: (将 CSS 注入到 DOM 中)

    • 作用 : style-loader 负责将 css-loader 处理后的 CSS 代码动态插入到 HTML 文档的 <style> 标签中,从而使得样式生效。
    • 功能: 它会在页面加载时,将 CSS 样式注入到 DOM 中,使得样式能够立即应用到页面上。
sh 复制代码
## 安装
npm install --save-dev style-loader css-loader
js 复制代码
// webpack.config.js
const path = require('path');

 module.exports = {
   entry: './src/index.js',
   output: {
     filename: 'bundle.js',
     path: path.resolve(__dirname, 'dist'),
   },
   mode: "development", // 必须配置不然build报错 模式 开发 or 生产 默认开发
+  module: {
+    rules: [
+      {
+        test: /.css$/i,
+        use: ['style-loader', 'css-loader'],
+      },
+    ],
+  },
 };

请确保 loader 的先后顺序:'style-loader' 在前,而 'css-loader' 在后。如果不遵守此约定,webpack 可能会抛出错误

  • element.classList.add('xxx'); 是 JavaScript 中用于向一个 DOM 元素添加 CSS 类名的方法 比如.test类名 则为 element.classList.add('test')
  • classList 提供了多种方法来操作元素的类名,例如 add()remove()toggle() 等。

csv-loader 和 xml-loader

js 复制代码
const path = require("path");
const toml = require('toml');
const yaml = require('yamljs');
const json5 = require('json5');

module.exports = {
  entry: "./src/index.js",
  mode: "development",
  devtool: "source-map",
  module: {
    rules: [
      {
        test: /\.css$/i,
        // 请确保 loader 的先后顺序:'style-loader' 在前,而 'css-loader' 在后
        use: ["style-loader", "css-loader"],
      },
      {
        // 处理图片文件 内置laoder
        test: /\.(png|jpe?g|gif|svg)$/i,
        type: "asset/resource",
      },
      {
        // 处理字体文件 内置laoder
        test: /\.(woff|woff2|eot|ttf|otf)$/i,
        type: "asset/resource",
      },
      // 加载数据
      {
        test: /\.(csv|tsv)$/i,
        use: ['csv-loader'],
      },
      {
        test: /\.xml$/i,
        use: ['xml-loader'],
      },
      {
        test: /\.toml$/i,
        type: 'json',
        parser: {
          parse: toml.parse,
        },
      },
      {
        test: /\.yaml$/i,
        type: 'json',
        parser: {
          parse: yaml.parse,
        },
      },
      {
        test: /\.json5$/i,
        type: 'json',
        parser: {
          parse: json5.parse,
        },
      },
    ],
  },
  output: {
    filename: "main.js",
    path: path.resolve(__dirname, "dist"),
  },
};

在 Webpack 5 中,处理图片和字体文件的功能已经内置 了,不再需要额外安装 file-loaderurl-loader。Webpack 5 引入了 Asset Modules 的概念,可以直接通过配置 type 属性来处理这些资源。

Webpack 5 中处理图片和字体的方式

在 Webpack 5 中,可以使用以下 type 值来处理图片和字体文件:

  1. asset/resource:

    • 作用:将文件作为资源输出到输出目录,并返回文件的 URL。

    • 类似于 file-loader 的功能。

    • 示例:

      js 复制代码
      {
        test: /.(png|jpe?g|gif|svg)$/i,
        type: "asset/resource",
      }
  2. asset/inline:

    • 作用:将文件作为 Data URL 内联到打包后的文件中。

    • 类似于 url-loader 的功能。

    • 示例:

      js 复制代码
      {
        test: /.(png|jpe?g|gif|svg)$/i,
        type: "asset/inline",
      }
  3. asset/source:

    • 作用:将文件内容作为字符串导入。

    • 类似于 raw-loader 的功能。

    • 示例:

      js 复制代码
      {
        test: /.txt$/i,
        type: "asset/source",
      }
  4. asset:

  • 作用:根据文件大小自动选择 asset/resourceasset/inline

  • 可以通过 parser.dataUrlCondition.maxSize 设置阈值。

  • 示例:

    js 复制代码
    {
      test: /.(png|jpe?g|gif|svg)$/i,
      type: "asset",
      parser: {
        dataUrlCondition: {
          maxSize: 4 * 1024, // 小于 4KB 的文件会被内联为 Data URL
        },
      },
    }

css字体使用方式:示例 iconfont 下载字体 或者 UI人员提供 下载好解压 使用即可

css 复制代码
@font-face {
  font-family: 'MyFont';
  src: url('./AlimamaFangYuanTiVF-Thin.woff2') format('woff2'),
    url('./AlimamaFangYuanTiVF-Thin.woff') format('woff');
  font-weight: 600;
  font-style: normal;
}

.hello {
  color: red;
  font-family: 'MyFont';
  background: url('./test.jpg');
}

babel-loader

作用:将 ES6+ 代码转换为 ES5,兼容旧版浏览器

sh 复制代码
# 安装
npm install -D babel-loader @babel/core @babel/preset-env
js 复制代码
// webpack.config.js
module: {
  rules: [
    {
      test: /.m?js$/,
      // 多个排除规则 使用数组 排除不应参与转码的库
      "exclude": [
          // \ for Windows, / for Mac OS and Linux
          /node_modules[\/]core-js/,
          /node_modules[\/]webpack[\/]buildin/,
      ],
      // exclude: /(node_modules|bower_components)/,
      use: {
        loader: 'babel-loader',
        options: {
          presets: ['@babel/preset-env'],
          // 额外安装 @babel/plugin-transform-runtime  @babel/runtime
          // 禁用 Babel 自动对每个文件的 runtime 注入
          plugins: ['@babel/plugin-transform-runtime'],
        },
      },
    },
  ];
}

babel-loader 很慢!

确保转译尽可能少的文件。你可能使用 /.m?js$/ 来匹配,这样也许会去转译 node_modules 目录或者其他不需要的源代码。

要排除 node_modules,参考文档中的 loaders 配置的 exclude 选项。

你也可以通过使用 cacheDirectory 选项,将 babel-loader 提速至少两倍。这会将转译的结果缓存到文件系统中。

sass-loader

  • 作用:将 SCSS/SASS 文件编译为 CSS。

  • 安装:

    sh 复制代码
    npm install --save-dev sass-loader sass
  • 配置:

    js 复制代码
    {
      test: /.scss$/,
      use: ['style-loader', 'css-loader', 'sass-loader'],
    }
  • style-loader 将 JS 字符串生成为 style 节点

  • css-loader 将 CSS 转化成 CommonJS 模块

  • sass-loader 将 Sass 编译成 CSS

sass-loader 需要预先安装 Dart SassNode Sass(可以在这两个链接中找到更多的资料)。这可以控制所有依赖的版本, 并自由的选择使用的 Sass 实现。

这样可以控制所有依赖项的版本,并选择要使用的 Sass 实现。

ℹ️ 推荐使用 Dart Sass

less-loader

  • 作用:将 less 文件编译为 CSS。

  • 安装:

    sh 复制代码
    npm install --save-dev less-loader less
  • 配置:

    js 复制代码
    {
      test: /.scss$/,
      // 还支持对象配置风格 {loader:xxx,options:{}}
      use: ['style-loader', 'css-loader', 'less-loader'],
    }

vue-loader vue-loader官方文档

  • 作用:解析 Vue 单文件组件(.vue 文件)。

  • 安装:

    sh 复制代码
    npm install --save-dev vue-loader vue-template-compiler
  • 配置:

    js 复制代码
    const { VueLoaderPlugin } = require('vue-loader');
    
    module.exports = {
      module: {
        rules: [
          {
            test: /.vue$/,
            use: 'vue-loader',
          },
        ],
      },
      plugins: [new VueLoaderPlugin()],
    };

html-loader

  • 作用:解析 HTML 文件中的 <img> 标签等资源。

  • 安装:

    sh 复制代码
    npm install --save-dev html-loader
  • 配置:

    js 复制代码
    {
      test: /.html$/,
      use: 'html-loader',
    }

ts-loader

  • 作用:将 TypeScript 编译为 JavaScript。

  • 安装:

    sh 复制代码
    npm install --save-dev ts-loader typescript
  • 配置:

    js 复制代码
    {
      test: /.ts$/,
      use: 'ts-loader',
      exclude: /node_modules/,
    }

官网loader案例

可以逐步击破,尝试各自有什么作用~这里不在一一介绍

常用插件

HtmlWebpackPlugin

HtmlWebpackPlugin 是 Webpack 中一个非常常用的插件,它的主要功能是自动生成 HTML 文件,并将打包后的 JavaScript、CSS 等资源文件自动注入到生成的 HTML 中。

sh 复制代码
# 安装
npm install --save-dev html-webpack-plugin

HtmlWebpackPlugin 的主要功能是:

  1. 自动生成 HTML 文件。
  2. 自动注入打包后的资源文件(核心的核心)。
  3. 支持自定义模板和多页面应用。
  4. 在生产模式下自动压缩 HTML 文件。 参阅 HtmlWebpackPlugin 仓库源码以了解 HtmlWebpackPlugin 插件提供的全部功能。
js 复制代码
// webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: __dirname + '/dist',
  },
  plugins: [
    new HtmlWebpackPlugin({
      title: 'My App', // 生成的 HTML 文件的标题
      filename: 'index.html', // 生成的 HTML 文件的名称
      template: './src/index.html', // 使用的模板文件
    }),
  ],
};

自定义模板 : 如果使用自定义模板(例如 src/index.html),可以在模板中使用 HtmlWebpackPlugin 提供的占位符:

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
  <div id="root"></div>
</body>
</html>
选项 说明
title 生成的 HTML 文件的标题。
filename 生成的 HTML 文件的名称,默认是 index.html
template 指定自定义模板文件的路径。
inject 资源注入的位置,可选值:true(默认,注入到 body 底部)、head
favicon 指定 favicon 文件的路径。
minify 在生产模式下是否压缩 HTML 文件,默认根据 mode 决定。
chunks 指定要注入的 chunk,默认注入所有 chunk。
chunksSortMode 控制 chunk 的注入顺序,例如 automanual 等。

MiniCssExtractPlugin

建议 mini-css-extract-plugincss-loader 一起使用

  • 作用: 将 CSS 提取到单独的文件中,而不是内联到 JavaScript 中。

  • 安装:

    sh 复制代码
    npm install --save-dev mini-css-extract-plugin
  • 配置:

    js 复制代码
    const MiniCssExtractPlugin = require('mini-css-extract-plugin');
    
    module.exports = {
      module: {
        rules: [
          {
            test: /.css$/,
            use: [MiniCssExtractPlugin.loader, 'css-loader'],
          },
        ],
      },
      plugins: [new MiniCssExtractPlugin()],
    };

CleanWebpackPlugin

  • 作用: 在每次构建前清理输出目录,确保没有旧文件残留。

  • 安装:

    sh 复制代码
    npm install --save-dev clean-webpack-plugin
  • 配置:

    js 复制代码
    const { CleanWebpackPlugin } = require('clean-webpack-plugin');
    
    module.exports = {
      plugins: [new CleanWebpackPlugin()],
    };

DefinePlugin

  • 作用: 在编译时定义全局常量,通常用于注入环境变量。

  • 内置插件,无需安装。

  • 配置:

    js 复制代码
    const webpack = require('webpack');
    
    module.exports = {
      plugins: [
        new webpack.DefinePlugin({
          'process.env.NODE_ENV': JSON.stringify('production'),
        }),
      ],
    };

CopyWebpackPlugin

  • 作用: 将文件或目录复制到输出目录中,通常用于复制静态资源。

  • 安装:

    sh 复制代码
    npm install --save-dev copy-webpack-plugin
  • 配置:

    js 复制代码
    const CopyWebpackPlugin = require('copy-webpack-plugin');
    
    module.exports = {
      plugins: [
        new CopyWebpackPlugin({
          patterns: [
            // 确保 `src/assets` 目录存在
            // 确保 `src/assets` 目录中有文件
            { from: 'src/assets', to: 'assets' }, // 将 src/assets 复制到 dist/assets
          ],
        }),
      ],
    };

BundleAnalyzerPlugin

  • 作用: 生成打包文件的体积分析报告,帮助优化代码。

  • 安装:

    sh 复制代码
    npm install --save-dev webpack-bundle-analyzer
  • 配置:

    js 复制代码
    const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
    
    module.exports = {
      plugins: [new BundleAnalyzerPlugin()],
    };

CompressionPlugin

  • 作用 : 生成压缩文件(如 .gz),用于优化资源加载性能。

  • 安装:

    sh 复制代码
    npm install --save-dev compression-webpack-plugin
  • 配置:

    js 复制代码
    const CompressionPlugin = require('compression-webpack-plugin');
    
    module.exports = {
      plugins: [
        new CompressionPlugin({
          algorithm: 'gzip', // 使用 gzip 压缩 打包后生成gz文件
        }),
      ],
    };

HotModuleReplacementPlugin

  • 作用: 启用模块热替换(HMR),在不刷新页面的情况下更新模块。

  • 内置插件,无需安装。

  • 配置:

    js 复制代码
    const webpack = require('webpack');
    
    module.exports = {
      devServer: {
        hot: true, // 启用 HMR
      },
      plugins: [new webpack.HotModuleReplacementPlugin()],
    };

TerserPlugin

  • 作用: 压缩 JavaScript 代码,移除未使用的代码和注释。

  • 安装:

    sh 复制代码
    npm install --save-dev terser-webpack-plugin
  • 配置:

    js 复制代码
    const TerserPlugin = require('terser-webpack-plugin');
    
    module.exports = {
      optimization: {
        minimize: true,
        minimizer: [new TerserPlugin()],
      },
    };

SplitChunksPlugin

在 Webpack 5 中,SplitChunksPlugin 的用法与 Webpack 4 基本一致,但 Webpack 5 对默认配置进行了一些优化,使得开箱即用的体验更好。

webpack 将根据以下条件自动拆分 chunks:

  • 新的 chunk 可以被共享,或者模块来自于 node_modules 文件夹
  • 新的 chunk 体积大于 20kb(在进行 min+gz 之前的体积)
  • 当按需加载 chunks 时,并行请求的最大数量小于或等于 30
  • 当加载初始化页面时,并发请求的最大数量小于或等于 30

当尝试满足最后两个条件时,最好使用较大的 chunks。

  • 作用: 将公共代码拆分为单独的 chunk,避免重复打包。

  • 内置插件,无需安装。

  • 配置:

    js 复制代码
    module.exports = {
      optimization: {
        splitChunks: {
          chunks: 'all', // 将所有公共代码拆分为单独的 chunk
        },
      },
    };

默认行为

Webpack 5 的 SplitChunksPlugin 默认配置已经足够智能,能够自动提取公共模块和 node_modules 中的第三方库。默认配置如下:

js 复制代码
module.exports = {
  optimization: {
    splitChunks: {
      chunks: 'async', // 默认只优化异步加载的 chunk
      minSize: 20000,  // 模块最小大小为 20KB
      minRemainingSize: 0,
      minChunks: 1,    // 模块至少被引用一次
      maxAsyncRequests: 30, // 异步加载时最大并行请求数
      maxInitialRequests: 30, // 初始加载时最大并行请求数
      enforceSizeThreshold: 50000, // 强制拆分的最小大小
      cacheGroups: {
        defaultVendors: {
          test: /[\/]node_modules[\/]/, // 匹配 node_modules 中的模块
          priority: -10, // 优先级
          reuseExistingChunk: true, // 复用已有的 chunk
        },
        default: {
          minChunks: 2, // 模块至少被引用两次
          priority: -20, // 优先级
          reuseExistingChunk: true, // 复用已有的 chunk
        },
      },
    },
  },
};

自定义配置

如果你需要更细粒度的控制,可以根据项目需求自定义 splitChunks 配置。以下是一个常见的自定义配置示例:

js 复制代码
module.exports = {
  optimization: {
    splitChunks: {
      chunks: 'all', // 优化所有 chunk(包括同步和异步)
      minSize: 30000, // 模块最小大小为 30KB
      minChunks: 1, // 模块至少被引用一次
      maxAsyncRequests: 5, // 异步加载时最大并行请求数
      maxInitialRequests: 3, // 初始加载时最大并行请求数
      automaticNameDelimiter: '~', // 自动生成 chunk 名称时的分隔符
      cacheGroups: {
        vendors: {
          test: /[\/]node_modules[\/]/, // 匹配 node_modules 中的模块
          priority: -10, // 优先级
          filename: 'vendors.js', // 提取到 vendors.js 文件中
        },
        common: {
          name: 'common', // 固定 chunk 名称
          minChunks: 2, // 模块至少被引用两次
          priority: -20, // 优先级
          reuseExistingChunk: true, // 复用已有的 chunk
        },
      },
    },
  },
};

示例场景

场景 1:提取第三方库

node_modules 中的模块提取到单独的 vendors.js 文件中:

js 复制代码
module.exports = {
  optimization: {
    splitChunks: {
      cacheGroups: {
        vendors: {
          test: /[\/]node_modules[\/]/,
          name: 'vendors',
          chunks: 'all',
        },
      },
    },
  },
};

场景 2:提取公共模块

将项目中共享的模块提取到单独的 common.js 文件中:

js 复制代码
module.exports = {
  optimization: {
    splitChunks: {
      cacheGroups: {
        common: {
          name: 'common',
          minChunks: 2,
          chunks: 'all',
        },
      },
    },
  },
};

场景 3:多入口优化

针对多入口项目,提取公共模块和第三方库:

js 复制代码
module.exports = {
// 多入口
  entry: {
    app: './src/app.js',
    admin: './src/admin.js',
  },
  optimization: {
    splitChunks: {
      chunks: 'all',
      cacheGroups: {
        vendors: {
          test: /[\/]node_modules[\/]/,
          name: 'vendors',
          chunks: 'all',
        },
        common: {
          name: 'common',
          minChunks: 2,
          chunks: 'all',
        },
      },
    },
  },
};

树摇

splitChunks.usedExports 是 Webpack 中 SplitChunksPlugin 的一个配置选项,主要用于优化树摇(Tree Shaking)效果。它的作用是在拆分代码时,允许 Webpack 识别哪些导出的模块实际上被使用,从而进一步减少生成的 bundle 大小。

具体作用 & 注意事项

  1. 提取未使用的导出 : 当设置 usedExportstrue 时,Webpack 会分析模块的导出内容,确定哪些导出项实际上在代码中被使用。未使用的导出不会被包含在最终的 chunk 中,这样可以有效减小文件的体积。(作用)
  2. 提高树摇效率 : 开启 usedExports 可以提高树摇的效率,使得未使用的代码在打包过程中被排除,从而减少最终生成的 JavaScript 文件的大小,提升加载性能。(作用)
  3. 只适用于 ES moduleunusedExports 依赖于 ES6 模块语法来识别导出项,因此不能在 CommonJS 模块中有效工作。(注意事项)
  4. 需要正确的 Babel 配置:如果你使用 Babel 进行转译,需要确保 Babel 配置是支持 ES6 模块的,以保证 Webpack 能够正确分析代码。(注意事项)
js 复制代码
module.exports = {
  optimization: {
    splitChunks: {
      chunks: 'all',
      usedExports: true, // 启用用于优化树摇
      cacheGroups: {
        default: {
          minChunks: 2,
          reuseExistingChunk: true,
        },
      },
    },
  },
};

ProvidePlugin

  • 作用 : 自动加载模块,而不需要显式地 importrequire

  • 内置插件,无需安装。

  • 配置:

    js 复制代码
    const webpack = require('webpack');
    
    module.exports = {
      plugins: [
        new webpack.ProvidePlugin({
          $: 'jquery', // 自动加载 jquery
          React: 'react', // 自动加载 react
        }),
      ],
    };

ProgressPlugin

  • 作用: 显示构建进度,帮助开发者了解构建状态。

  • 内置插件,无需安装。

  • 配置:

    js 复制代码
    const webpack = require('webpack');
    
    module.exports = {
      plugins: [new webpack.ProgressPlugin()],
    };

loader 和 plugin 区别

1. Loader(加载器)

功能

  • 转换模块:Loaders 主要用于对模块的转换。例如,它可以将 TypeScript 转换为 JavaScript,将 SCSS 转换为 CSS,或者将图像文件转换为 Base64 字符串。
  • 对单个文件进行处理:Loaders 是针对每个单独的模块进行工作的,可以定义如何处理特定类型的文件。

工作机制

  • Loaders 在模块被加载时被调用,执行顺序是由文件扩展名和配置中的规则决定的。可以通过 module.rules 配置来指定。

2. Plugin(插件)

功能

  • 扩展 Webpack 功能:Plugins 用于增强 Webpack 的功能,可以对 Webpack 的构建过程进行更深入的控制。例如,可以用来优化输出文件、创建 HTML 文件、设置环境变量等等。
  • 全局处理:Plugins 可以在整个构建过程中运行,可以访问构建生命周期的不同阶段。

工作机制

  • Plugins 是通过 plugins 数组在 Webpack 配置中定义的。它们可以灵活地处理构建中的各种任务。

小结

  • Loader:用于处理和转换模块,针对单个文件进行工作,通常在模块加载时执行。
  • Plugin:用于扩展 Webpack 的功能,可以在整个构建过程中运行,适用于更高层次的操作和自定义构建流程。
相关推荐
前端小巷子1 分钟前
Web开发中的文件上传
前端·javascript·面试
上单带刀不带妹1 小时前
手写 Vue 中虚拟 DOM 到真实 DOM 的完整过程
开发语言·前端·javascript·vue.js·前端框架
前端风云志1 小时前
typescript结构化类型应用两例
javascript
acstdm2 小时前
DAY 48 CBAM注意力
人工智能·深度学习·机器学习
gnip2 小时前
总结一期正则表达式
javascript·正则表达式
澪-sl2 小时前
基于CNN的人脸关键点检测
人工智能·深度学习·神经网络·计算机视觉·cnn·视觉检测·卷积神经网络
爱分享的程序员2 小时前
前端面试专栏-算法篇:18. 查找算法(二分查找、哈希查找)
前端·javascript·node.js
羊小猪~~2 小时前
数据库学习笔记(十七)--触发器的使用
数据库·人工智能·后端·sql·深度学习·mysql·考研
翻滚吧键盘2 小时前
vue 条件渲染(v-if v-else-if v-else v-show)
前端·javascript·vue.js
你这个年龄怎么睡得着的2 小时前
为什么 JavaScript 中 'str' 不是对象,却能调用方法?
前端·javascript·面试