webpack 基础
什么是 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.js
、 webpack.config.js
需要根据特定情况使用不同的配置文件,则可以通过在命令行中使用 --config
标志修改
json
"scripts": {
"build": "webpack --config prod.config.js"
}
常用loader
style-loader 和 css-loader
-
css-loader: (解析 CSS 文件)
- 作用 :
css-loader
负责解析 CSS 文件,处理其中的@import
和url()
等语法,并将这些依赖关系转换为 Webpack 可以理解的模块。 - 功能: 它可以将 CSS 文件中的内容转换为 JavaScript 模块,使得 CSS 可以被 JavaScript 动态加载和使用。
- 作用 :
-
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-loader
或 url-loader
。Webpack 5 引入了 Asset Modules 的概念,可以直接通过配置 type
属性来处理这些资源。
Webpack 5 中处理图片和字体的方式
在 Webpack 5 中,可以使用以下 type
值来处理图片和字体文件:
-
asset/resource
:-
作用:将文件作为资源输出到输出目录,并返回文件的 URL。
-
类似于
file-loader
的功能。 -
示例:
js{ test: /.(png|jpe?g|gif|svg)$/i, type: "asset/resource", }
-
-
asset/inline
:-
作用:将文件作为 Data URL 内联到打包后的文件中。
-
类似于
url-loader
的功能。 -
示例:
js{ test: /.(png|jpe?g|gif|svg)$/i, type: "asset/inline", }
-
-
asset/source
:-
作用:将文件内容作为字符串导入。
-
类似于
raw-loader
的功能。 -
示例:
js{ test: /.txt$/i, type: "asset/source", }
-
-
asset
:
-
作用:根据文件大小自动选择
asset/resource
或asset/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。
-
安装:
shnpm 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 Sass 或 Node Sass(可以在这两个链接中找到更多的资料)。这可以控制所有依赖的版本, 并自由的选择使用的 Sass 实现。
这样可以控制所有依赖项的版本,并选择要使用的 Sass 实现。
ℹ️ 推荐使用 Dart Sass。
less-loader
-
作用:将 less 文件编译为 CSS。
-
安装:
shnpm 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
文件)。 -
安装:
shnpm install --save-dev vue-loader vue-template-compiler
-
配置:
jsconst { VueLoaderPlugin } = require('vue-loader'); module.exports = { module: { rules: [ { test: /.vue$/, use: 'vue-loader', }, ], }, plugins: [new VueLoaderPlugin()], };
html-loader
-
作用:解析 HTML 文件中的
<img>
标签等资源。 -
安装:
shnpm install --save-dev html-loader
-
配置:
js{ test: /.html$/, use: 'html-loader', }
ts-loader
-
作用:将 TypeScript 编译为 JavaScript。
-
安装:
shnpm 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
的主要功能是:
- 自动生成 HTML 文件。
- 自动注入打包后的资源文件(核心的核心)。
- 支持自定义模板和多页面应用。
- 在生产模式下自动压缩 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 的注入顺序,例如 auto 、manual 等。 |
MiniCssExtractPlugin
建议 mini-css-extract-plugin
与 css-loader
一起使用
-
作用: 将 CSS 提取到单独的文件中,而不是内联到 JavaScript 中。
-
安装:
shnpm install --save-dev mini-css-extract-plugin
-
配置:
jsconst MiniCssExtractPlugin = require('mini-css-extract-plugin'); module.exports = { module: { rules: [ { test: /.css$/, use: [MiniCssExtractPlugin.loader, 'css-loader'], }, ], }, plugins: [new MiniCssExtractPlugin()], };
CleanWebpackPlugin
-
作用: 在每次构建前清理输出目录,确保没有旧文件残留。
-
安装:
shnpm install --save-dev clean-webpack-plugin
-
配置:
jsconst { CleanWebpackPlugin } = require('clean-webpack-plugin'); module.exports = { plugins: [new CleanWebpackPlugin()], };
DefinePlugin
-
作用: 在编译时定义全局常量,通常用于注入环境变量。
-
内置插件,无需安装。
-
配置:
jsconst webpack = require('webpack'); module.exports = { plugins: [ new webpack.DefinePlugin({ 'process.env.NODE_ENV': JSON.stringify('production'), }), ], };
CopyWebpackPlugin
-
作用: 将文件或目录复制到输出目录中,通常用于复制静态资源。
-
安装:
shnpm install --save-dev copy-webpack-plugin
-
配置:
jsconst 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
-
作用: 生成打包文件的体积分析报告,帮助优化代码。
-
安装:
shnpm install --save-dev webpack-bundle-analyzer
-
配置:
jsconst BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; module.exports = { plugins: [new BundleAnalyzerPlugin()], };
CompressionPlugin
-
作用 : 生成压缩文件(如
.gz
),用于优化资源加载性能。 -
安装:
shnpm install --save-dev compression-webpack-plugin
-
配置:
jsconst CompressionPlugin = require('compression-webpack-plugin'); module.exports = { plugins: [ new CompressionPlugin({ algorithm: 'gzip', // 使用 gzip 压缩 打包后生成gz文件 }), ], };
HotModuleReplacementPlugin
-
作用: 启用模块热替换(HMR),在不刷新页面的情况下更新模块。
-
内置插件,无需安装。
-
配置:
jsconst webpack = require('webpack'); module.exports = { devServer: { hot: true, // 启用 HMR }, plugins: [new webpack.HotModuleReplacementPlugin()], };
TerserPlugin
-
作用: 压缩 JavaScript 代码,移除未使用的代码和注释。
-
安装:
shnpm install --save-dev terser-webpack-plugin
-
配置:
jsconst 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,避免重复打包。
-
内置插件,无需安装。
-
配置:
jsmodule.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 大小。
具体作用 & 注意事项
- 提取未使用的导出 : 当设置
usedExports
为true
时,Webpack 会分析模块的导出内容,确定哪些导出项实际上在代码中被使用。未使用的导出不会被包含在最终的 chunk 中,这样可以有效减小文件的体积。(作用) - 提高树摇效率 : 开启
usedExports
可以提高树摇的效率,使得未使用的代码在打包过程中被排除,从而减少最终生成的 JavaScript 文件的大小,提升加载性能。(作用) - 只适用于 ES module :
unusedExports
依赖于 ES6 模块语法来识别导出项,因此不能在 CommonJS 模块中有效工作。(注意事项) - 需要正确的 Babel 配置:如果你使用 Babel 进行转译,需要确保 Babel 配置是支持 ES6 模块的,以保证 Webpack 能够正确分析代码。(注意事项)
js
module.exports = {
optimization: {
splitChunks: {
chunks: 'all',
usedExports: true, // 启用用于优化树摇
cacheGroups: {
default: {
minChunks: 2,
reuseExistingChunk: true,
},
},
},
},
};
ProvidePlugin
-
作用 : 自动加载模块,而不需要显式地
import
或require
。 -
内置插件,无需安装。
-
配置:
jsconst webpack = require('webpack'); module.exports = { plugins: [ new webpack.ProvidePlugin({ $: 'jquery', // 自动加载 jquery React: 'react', // 自动加载 react }), ], };
ProgressPlugin
-
作用: 显示构建进度,帮助开发者了解构建状态。
-
内置插件,无需安装。
-
配置:
jsconst 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 的功能,可以在整个构建过程中运行,适用于更高层次的操作和自定义构建流程。