# 🍲 Webpack 学习记录(不同类型模块的打包)
上篇文章主要了解一下什么是 webpack,以及 webpack 的核心概念,并对其基本配置也有了一定的了解。该篇文章主要总结了 webpack 针对不同类型模块的打包。
在 webpack 中,webpack 本身做的事情仅仅只是分析出各个模块之间的依赖关系,然后形成资源列表,最后打包到指定的文件中。在 webpack 看来,任何的文件都是模块,但是 webpack 只支持对 js 和 json 文件打包。像是 css、sass、png 等这些类型的文件,webpack 需要借助对应的 loader 对其进行解析,同时 plugin 插件也可以为 loader 带来更多的特性。下面我们来看一下 webpack 是如何对各类模块进行打包的把~👇

# 一、打包 CSS
# 1. Webpack 打包 CSS
webpack 默认只会处理 JS 文件,这时可以使用相应的 loader 来处理 CSS 文件,这里打包 CSS 需要借助两个 loader 分别是:
- css-loader:将 CSS 文件转换成一个 JS 模块(将 CSS 输出到打包后的 JS 文件中)
- style-loader:把包含 CSS 内容的 JS 代码,挂载到页面的 style 标签中
# 安装
npm i css-loader styly-loader -D
# 配置
// webpack.config.js
module.exports = {
...
entry: './src/main.js',
...
module: {
rules: [
{
test: /.css$/, // 匹配以css结尾的文件
use: [
'style-loader', // 将JS中的样式,挂载到style标签中
'css-loader' // css-loader按照Common JS规范,讲样式文件输出到JS中
]
}
]
}
}
注意:loader 的执行顺序是先下后上,就是 use 数组会逆序执行 loader 们
# 2. Webpack 打包 less
处理 less 文件时,需要先借助 less-loader 将 less 转换成 css,scss 等预编译语言也是一样的逻辑
npm i less less-loader -D
module: {
rules: [
{
test: /\.less$/,
use: [
"style-loader",
"css-loader",
"less-loader", // 将less先转换成css
],
},
];
}
这里需要注意在 use 中插入 loader 的顺序,必须先让 less-loader 执行,将其解析成 css 后再进行后续的操作

# 3. 将 CSS 打包成独立的文件
当处理完 css 和 less 时,不希望样式通过 style 的方式引入到 html 文件中,而是希望其抽离成一个单独的样式文件。这时需要借助mini-css-extract-plugin
插件来完成,该插件可以替换style-loader
npm i mini-css-extract-plugin -D
// webpack.consig.js
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module:{
rules:[
{
test: /\.css$/,
use:[
MiniCssExtractPlugin.loader, //替换style-loader,将css打包成独立的文件
'css-loader' // 加载处理css文件
]
}
]
},
plugins:[
// 实例化插件
new MiniCssExtractPlugin({
filename:'index.css' //重命名输出的css文件,也可不写默认
})
]
# 4. 处理 CSS 兼容性问题
CSS 在不同浏览器上的兼容性不一致,对于一些比较新的 CSS 属性需要针对不同的浏览器添加相应的样式前缀。在 webpack 中可以使用postcss-loader
中的autoprefixer
插件来帮助我们完成这个工作。
【扩展】什么是 PostCSS:
- PostCSS 是一个通过 JavaScript 来转换样式的工具
- 这个工具可以帮助我们进行一些 CSS 的转换和适配,比如自动添加浏览器前缀、css 样式的重置
npm i postcss-loader autoprefixer -D
之后可以在webpack.config.js
文件中引入 postcss-loader
module:{
rules:[
{
test: /\.css$/,
use:[
// 第3步:将css打包成独立的文件
MiniCssExtractPlugin.loader,
// 第2步:将css输出到打包后的js中
'css-loader',
// 第1步:通过postcss-loader给样式属性添加浏览器前缀
'postcss-loader',
]
}
]
},
因为我们只是想要使用postcss-loader
中的autoprefixer
插件来帮助我们添加浏览器前缀,所以可以新建一个postcss.config.js
文件来引入这个插件(基于 Common.js 规范)
module.exports = {
plugins: [require("autoprefixer")],
};
对于上述的配置可以指定需要兼容的浏览器,可以直接在 package.json 文件中直接指定 browserslist,也可以在根目录下新建一个.browserslistrc 文件,这里我直接在 package.json 文件中指定了
"browserslist": [
"last 1 version", // 匹配到浏览器的最后一个版本
"> 1%" // 代表全球超过1%使用的浏览器
]
我们还可以使用另一个插件postcss-preset-env
来帮助我们完成上面的工作,不需要借助 autoprefixer
postcss-preset-env
: 可以帮助我们将一些现代的 CSS 特性,转成大多数浏览器认识的 CSS,并且会根据目标浏览器或者运行时环境添加所需的 polyfill; 也包括会自动帮助我们添加 autoprefixer(所以相当于已经内置了 autoprefixer),比 autoprefixer 插件的功能更加的强大。
npm i postcss-preset-env -D
# 5. 校验 CSS 代码格式
在 webpack 中对 CSS 代码进行格式校验的时候,可以引入三个包来帮助我们进行校验
stylelint
:对 CSS 代码格式进行校验 👉 https://stylelint.io/stylelint-config-standard
:进行 CSS 代码校验的规则集(一些大公司遵循的代码规范) 👉 https://github.com/stylelint/stylelint-config-standardstylelint-webpack-plugin
:允许在 webpack 中使用 stylelint 对 CSS 代码进行格式校验
npm i stylelint stylelint-config-standard stylelint-webpack-plugin -D
在 webpack.config.js 中引入 stylelint-webpack-plugin 插件
// 引入校验css代码格式的插件
const StylelintPlugin = require("stylelint-webpack-plugin");
module.exports = {
// 配置插件
plugins: [
new StylelintPlugin({
// 指定需要进行格式校验的文件
files: ["./src/css/*.{css, less, sass, scss}"],
}),
],
};
在 package.json 文件中配置 stylelint-config-standard
"stylelint": {
"extends": "stylelint-config-standard",
// 可以指定rules属性来对规则集进行扩展
"rules": {}
}
指定规则的配置有三种方式,按照加载的先后顺序,依次是:
- 在 package.json 中的 stylelint 属性指定规则
- 在.stylelintrc 中指定规则
- 在 stylelint.config.js 中指定规则
# 6. 压缩 CSS
当我们希望对打包后的 CSS 进行压缩可以使用 optimize-css-assets-webpack-plugin -D 插件
npm i optimize-css-assets-webpack-plugin -D
之后在 webpack.config.js 中的中引入并且进行初始化后,打包出来的 CSS 就是压缩版的啦
// 引入压缩CSS的插件
const OptimizeCssAssetsPlugin = require("optimize-css-assets-webpack-plugin");
module.exports = {
// 配置插件
plugins: [new OptimizeCssAssetsPlugin()],
};
# 二、打包 HTML
打包完成后我们会手动创建一个 html 文件引入打包后的资源来查看效果,这时可以使用html-webpack-plugin
插件来帮助我们简化 HTML 文件的创建,以便为你的 webpack 包提供服务。
html-webpack-plugin
:
- 自动生成一个 HTML 文件(用于服务器访问),并在 HTML 中加载所有的打包资源
- 指定 HTML 模板、设置 HTML 变量、压缩 HTML
npm i html-webpack-plugin -D
下载后在 webpack.config.js 中引用该插件,在实例化插件的时候,可以指定打包出来的 HTML 文件名称、指定引用的 HTML 模板以及定义 HTML 中使用的变量等操作
const HtmlWebpackConfig = require('html-webpack-plugin')
module.exports = {
// 配置插件
plugins: [
// 配置html
new HtmlWebpackConfig({
// 指定打包出来的html文件名称
filename: 'index.html',
// 指定生成的HTML模板
template: './src/index.html',
// 指定HTML中使用的变量
title: '首页'
]
}
详细配置 👉 https://webpack.docschina.org/plugins/html-webpack-plugin/#configuration
# 三、打包 JavaScript
# 1. Webpack 编译 JS
虽然 webpack 可以直接对 JS 进行打包,但是当我们使用一些 ES6+的新特性时,并不能对其进行转译。如果需要将 ES6+转换成 ES5,从而保证 JS 在低版本的浏览器上也可以兼容。这时可以借助babel-loader
来帮助我们将 ES6+的语法转换成 ES5。为了使对 JS 的转译更加的灵活与强大还可以引入@babel/core
和@babel/preset-env
@babel/core
:包含了一些 JS 转译的核心插件,其作用是是将 JS 代码分析成 ast,方便各个插件分析语法进行相应的处理。
@babel/preset-env
:主要功能有两个:(1) 将尚未被大部分浏览器支援的 JavaScript 语法转换成能被浏览器支援的语法。 (2) 让较旧的浏览器也能支持大部分浏览器能支持的语法 👉 详细讲解
npm i babel-loader @babel/core @babel/preset-env -D
module: {
rules: [
{
test: /\.m?js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
presets: [["@babel/preset-env", { targets: "defaults" }]],
},
},
},
];
}
经过上面的配置已经可以对 ES6+的大部分语法进行转译了,但是@babel/preset-env
只能够转译基本的语法,比如像是 promise 这个新语法就没有办法进行转译。这时可以借助@babel/polyfill
包,这个包可以帮助我们转译所有的 JS 新语法,但是会导致打包出来的文件大了许多,可以配合core-js
(按需转译新语法)一起使用
# 2. 校验 JS 的代码格式
JS 和 CSS 一样,在开发过程中也都需要进行代码格式的校验。一般会引入下面这几个包对 JS 的代码格式进行校验
eslint
:校验 JS 代码格式的工具 👉 https://eslint.org/eslint-config-airbnb-base
:最流行的 JS 代码格式规范 👉 https://www.npmjs.com/package/eslint-config-airbnb-baseeslint-webpack-plugin
:webpack 的 eslint 插件 👉 https://webpack.docschina.org/plugins/eslint-webpack-plugin/#rooteslint-plugin-import
:用于在 package.json 中读取
npm i eslint eslint-config-airbnb-base eslint-webpack-plugin eslint-plugin-import -D
在 webpack.config.js 中引入并实例化eslint-webpack-plugin
// js代码格式校验
const ESlintPlugin = require("eslint-webpack-plugin");
module.expoers = {
plugins: [
// js代码格式校验配置
new ESlintPlugin({
// 自动解决一些常规的代码格式错误
fix: true,
}),
],
};
JS 代码的校验规则基于之前下载的eslint-config-airbnb-base
,可以在 package.json 文件中对其进行扩展
"eslintConfig": {
"extends": "airbnb-base"
}
# 四、打包图片资源
大多数的资源加载器都类似 css-loader,都是将资源模块转化为 js 代码的实现方式去工作。但是还有一些我们经常用到的资源文件,例如项目当中的图片、字体,这些文件没有办法通过 js 的方式表示。对于这一类的资源文件,我们需要用到文件资源加载器,也就是 file-loader。
file-loader
:其作用就是帮助我们处理 import/require()方式引入的一个文件资源,并且会将它放到我们输出的文件夹中。
npm i file-loader -D
默认打包出来的文件名称是一个随机的哈希值,比较难与我们原本的图片文件对应起来。可以在file-laoder
的配置项中指定打包后的图片名称,以及设置输出的文件夹
// webpack.config.js
module: {
rules: [
{
test: /\.(png|jpe?g|gif|svg)/,
use: {
loader: "file-loader",
options: {
name: "[name].[hash:8].[ext]", // [name]图片原来的名称 | [ext]图片原来的后缀名
outputPath: "img", // 打包输出的文件夹
},
},
},
];
}
除了file-loader
还可以使用url-loader
来帮助我们打包图片类型的资源。
url-loader
:相当于file-loader
的升级版本,我们可以指定图片大小的限制,小于该限制的图片不会被单独单包,而是转换成 base64 字符串打包在 JS 文件中。这样图片就会和 JS 文件一起加载,减少了图片的请求次数
npm i url-loader -D
在 webpack 中引入该 loader,并配置其图片大小的限制
module: {
rules: [
{
test: /\.(png|gif|jpe?g)$/i,
use: {
loader: "url-loader",
options: {
// 指定图片大小的限制,小于该限制的图片,会被编译成base64格式
limit: 10 * 1024, // 10kb
name: "img/[name].[ext]",
},
},
},
];
}
【问题优化】每次引入图片的时候,需要在入口文件中以模块的方式引入之后,再挂载到 dom 节点上。有没有什么更好的方式让图片直接在 html 模板中以标签的模式直接引入,之后打包后也可以有正确的路径显示图片
【问题解决】可以使用html-loader
html-loader
:将 HTML 导出成字符串,负责引入 img,从而能被 url-loader 进行处理
npm i html-loader -D
module: {
rules: [
{
test: /\.(htm|html)$/i,
use: {
// html-loader会采用url-loader加载图片,但是url-loader和html-loader使用的默认加载规范不一样
loader: "html-loader",
options: {
// 如果webapck4:只需要在url-loader配置中配置esModule为false
// 如果webpack5: 在url-loader和html-loader中都需要进行配置
esModule: false,
},
},
},
];
}
# 五、资源模块(Asset Module)
在 webpack5 之前,加载资源文件(字体、图片、图标、HTML...)需要使用一些 loader,比如 raw-loader 、url-loader、file-loader。 在 webpack5 开始,我们可以直接使用资源模块类型(asset module type
),来替代上面的这些 loader,而无需配置额外的 loader
资源模块类型(asset module type),通过添加 4 种新的模块类型,来替换所有这些 loader
- Webpack4:
- raw-loader:将文件导入为字符串
- file-loader:将文件发送到输出目录
- url-loader:将文件发送到输出目录,或转为 Data URL 内联到 bundle 中
- Webpack5:
- asset/resource:发送一个单独的文件并导出 URL(相当于之前的 file-loader)
- asset/inline:导出一个资源的 data URL(之前通过使用 url-laoder 实现)
- asset/source:导出资源的源代码(之前通过使用 raw-loader 实现)
- asset:再导出一个 data URL 和发送一个单独的文件之间自动选择(之前通过使用 url-loader,并且配置资源体 积限制实现)
举个 🌰, 以 webpack4 和 webpack5 分别处理字体资源文件举例
// webpack4中处理字体资源文件
module: {
rules: [
{
test: /\.(eot|svg|ttf|woff|woff2)$/i,
use: {
loader: "file-loader",
options: {
name: "fonts/[name].[ext]",
},
},
},
];
}
// webpack5中处理字体资源文件
module: {
rules: [
{
test: /\.(eot|svg|ttf|woff|woff2)$/i,
use: {
loader: "file-loader",
options: {
name: "fonts/[name].[ext]",
},
},
},
];
}