有了这些方法,webpack你也可以自己配
前言
通过上篇文章——弄懂这几个概念后,我对webpack有了更新的理解 的讲解,我们大致了解了:
- 使用
webpack过程中出现的一些概念 - 结合打包过程中出现的概念,浅析了
webpack打包流程,让大家对打包流程有个大致的理解
我们都知道,我们在实际开发过程中,使用webpack无非就是为了最后输出浏览器能运行的css、img、js、html等前端资源。
那么,为了更贴近实际,我们这篇文章,就以如何输出css、img、js、html等前端资源为目的,学习一下如何配置webpack。
学习大纲
这篇文章主要讲解以下基础配置:
- 处理
css、less文件 - 处理图片(
img)、字体(font)、音乐(audio)等前端资源文件 - 编译
es6+语法及API - 处理
html文件
webpack文档对配置写的算挺详细了,所以这里我也不想复制粘贴又写一遍,这样不如大家直接看文档。
授人以鱼不如授人以渔,学习不能硬学,应该要有一些方法跟技巧。因此,我更想在讲解配置的过程中,总结一些方法,让我们更好的理解webpack的配置项。这样,一些类似的一些配置,我们照葫芦画瓢,看文档就可以配出来。
备注
文章涉及到的案例已经上传到 github:
- 为了阅读方便,文章只贴了相关代码,建议
fork一下,看看完整代码;或者跟着文章一起边看边敲,这样印象会更深刻一些 - 创作不易,如果觉得有帮助的话,欢迎
star🌟
处理css、less文件
我们先用 learn-03 这个案例来看看webpack如何处理样式文件。
我们安装相应的loader解析:
less-loader:解析less为csscss-loader:将css解析为webpack能识别的有效模块style-loader:将解析出来的css插入到<header />中
npm install less less-loader css-loader style-loader -D
然后配置一下:
// webpack.config.js
module.exports = {
...,
module: {
rules: [
{
test: /.(css|less)$/,
use: [
'style-loader',
'css-loader',
'less-loader',
],
},
]
}
}
loader的解析是逆序执行(或从右到左),因此这个配置会按照(less-loader → css-loader → style-loader)以下顺序执行:
- 将
less解析成css - 再将结果传给
css-loader,解析成webpack认识的有效模块 - 再将结果传给
style-loader,将解析出来的样式插入到<header />)的顺序执行。
less、css、入口文件代码为:
// index.less
*{
margin: 0;
padding: 0;
}
h1{
color: red;
margin-top: 20px;
}
/* index.css */
h2{
color: green;
}
// index.js
import './assets/index.less';
import './assets/index.css';
输出:

我们会发现我们写的样式处理成功,并且被插入到<head/>中。
总结
我们 上篇文章 说过:
- 我们通过
import或require进来的资源文件,或我们项目中的每个文件,都可以看作为一个独立的模块 Loader的作用就是把这些模块(module)转换成webpack能够识别的有效模块
webpack人性化的暴露了module配置项,就是专门用来配置相关loader,以此解析相应的module。因此,如果我们想解析我们源码中使用的某些模块,我们就应该:
- 先下载相应的
loader - 直接找到
module配置项,根据loader使用方法直接配置
所以,我们按照上面总结的方法跟思想,可以试试自己配置处理一下.scss或者.txt文件
ok,我们成功得到了我们项目需要的样式(css),接下来我们再看看如何处理图片(img)等前端资源文件
处理前端资源文件
前端资源文件很多,在这里,我们粗略的把它们先分成两类:
- 常用类:一般就是
img、font、video等文件 - 特殊类:
.csv、.xml等文件
这些资源只要import或者require进我们的源码,那么它一样也是模块。既然是模块,我们就需要安装相应的loader进行解析,然后在module配置项配置。
在wepack5之前,对于常用类的资源,我们一般需要安装以下loader来解析:
raw-loader:将文件解析成字符串file-loader:将import/require()进来的文件,解析为一个完整引用的url,并将文件发送到输出目录中url-loader:可以把文件转成base64
我们经常用到的是file-loader、url-loader这两个。因为常用类资源,经常以url形式引入到我们项目中;或者为了减少http请求,直接转换成base64
但是在webpack5后,webpack已经内置上述几个loader的功能,所以我们可以不用再安装以上的loader了;我们可以直接使用webpack自带的 asset module。
webpack5之后内置的资源模块:
asset/source:等同于raw-loaderasset/resource: 等同于file-loaderasset/inline:等同于url-loaderasset:比较灵活,同时拥有asset/resource与asset/inline的功能。如果设置了文件大小限制,文件没有超出这个大小的话,会转为base64;如果没设置大小限制,则功能跟file-loader一样
这是我十分爱
webpack5的原因,因为我们不要安装那么多乱七八糟的loader
我们用 learn-04 这个案例,看看怎么使用资源模块来解析我们的前端资源。
我们把上一章解析样式的配置一起加进来,在less跟js中分别使用图片资源。
我们有两个图片:
preview.gif:大小为349kbecj-cli.png:大小为4kb
// webpack.config.js
module.exports = {
...,
module: {
rules: [
{
test: /.(css|less)$/,
use: [
'style-loader',
'css-loader',
'less-loader',
],
},
{
test: /\.(png|svg|jpg|jpeg|gif)$/i,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 1024 * 10 // 当图片 < 10kb 转成base64
}
},
generator: {
filename: '[name][ext]' // 设置输出的文件名字
}
}
]
}
}
入口文件:
// index.js
import './assets/index.less';
const img = new Image();
img.src = require('./assets/ecj-cli.png');
img.width = 500;
document.querySelector('#js_logo').append(img);
样式:
.bg_logo{
width: (1434/3px);
height: (1212/3px);
background-image: url('./preview.gif');
background-size: 100%;
}
输出结果:

我们会发现样式跟js都处理图片成功:
preview.gif大于10kb,所以没有被转为base64,而是返回了一个完整的引用路径(相当于file-loader的功能)ejc-cli.png小于10kb的则被转为了base64(相当于url-loader的功能)。
上面的gif图,是我开发的一个在日常项目中十分实用的命令行工具 ejc-cli 。它可以将对接人员收集的
Excel数据,按一定格式转成我们代码所需要的json数据。它十分方便我们开发维护数据,并且还有跟其他人员对接数据。感兴趣的朋友可以看看 👉🏻 了解 ejc-cli
总结
通过import或者require进我们源码的资源,一样是一种模块。所以需要下载相应的loader,然后到module配置项进行配置。
对于常用类资源(img、font、video、audio等等):
- 因为常用,所以
webpack5把处理它们的功能内置了,这样我们不用额外安装loader,我们直接使用asset module来管理 - 我们一般都使用
asset/resource、asset/inline、asset这几个模块来管理常用类资源。因为我们常用类的资源,经常会在我们项目中引入使用,我们需要把它们解析成引入完整的url,或者为了减少http请求,直接转换成base64
对于特殊类资源(.csv、.xml等等):
- 我们可以理解为,因为不常用,所以
webpack没有把它们的功能内置 - 因此,我们需要安装相应的
loader来解析。例如我们想解析.csv文件,我们需要安装csv-loader来解析
按照上面总结的方法,可以试试自己配置处理一下video或者font等文件
好,到目前,我们已经得到了css、img。我们接下来看看,如何通过webpack处理得到我们的js
编译es6+
时至今日,js发展迅速,为了提高开发效率和代码质量,每年都会有一些新的语法或者新的API出现。
例如,在语法方面出现了:
- 箭头函数:
()=> - 类语法糖:
class People {} - 解构赋值:
const [x, y] = [1, 2]; - ...
在API方面又有:
PromiseArray.prototype.includes()Object.keys()- ...
但是这些新的内容在一些低版本浏览器上是不支持的,所以我们需要通过webpack来将我们的es6+编译成这些低版本浏览器能支持的版本。
我们先用 learn-05 这个案例,看看我们怎么配置webpack编译es6+。
我们安装相关依赖:
...
"devDependencies": {
"@babel/core": "^7.22.8",
"@babel/plugin-transform-runtime": "^7.22.7",
"@babel/preset-env": "^7.22.7",
"babel-loader": "^9.1.3",
"webpack": "^5.88.1",
"webpack-cli": "^5.1.4"
},
"dependencies": {
"core-js": "^3.31.1"
},
入口文件。使用了class、Promise、()=>{}等es6+语法及API:
// index.js
class People {
constructor(name) {
this.name = name;
}
sayHi() {
return Promise.resolve(this.name);
}
}
const Lee = new People('Lee');
Lee.sayHi().then(name => console.log(`Hi, I am ${name}.`));
配置webpack:
// webpack.config.js
module.exports = {
...,
module: {
rules: [
{
test: /\.m?js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader'
}
}
]
}
}
配置Babel。在项目根目录新建babel.config.js文件:
// babel.config.js
const presets = [
[
'@babel/preset-env',
{
useBuiltIns: 'usage',
corejs: {
version: require('core-js/package.json').version,
proposals: true
}
}
]
];
const plugins = [
'@babel/plugin-transform-runtime',
];
module.exports = {presets, plugins}
设置要兼容的目标浏览器。在package.json添加browserslist字段:
"browserslist": [
"ie 11"
]
在ie 11运行的结果:

我们会发现:
- 我们写的
es6+在ie 11运行成功 Promise这个es6+API,也被添加到了ie 11里
说明我们编译的es6+是成功的。
关于Babel
在上面配置中,大家会发现,如果我们想用webpack编译es6+,我们还需要在根目录添加babel.config.js文件,步骤比处理其他模块要复杂麻烦的多。这是因为,编译es6+的核心,是需要Babel来配合的。Babel是编译es6+的一个工具。
由于本篇文章主要是讲解webpack,所以在这里,我们对Babel就大概提一下。以下是Babel常用的一些配置。
- 如果我们开发的项目是应用程序或大型的项目,我们可以这么配置:
const presets = [ [ '@babel/preset-env', { modules: false, useBuiltIns: 'entry', // or useBuiltIns: 'usage', corejs: { version: '3.27.2', proposals: true } } ] ]; const plugins = [ '@babel/plugin-transform-runtime' ]; module.exports = {plugins, presets}; // index.js // If use useBuiltIns: 'entry' import 'core-js/stable' - 如果我们是想开发一个第三方库,我们可以这么配置:
// Babel配置 const presets = [ [ '@babel/preset-env', { modules: false } ] ]; const plugins = [ [ '@babel/plugin-transform-runtime', { corejs: { version: 3, proposals: true } } ] ]; module.exports = {plugins, presets};
如果你想对Babel已经有个了解,但处于懵懵懂懂的状态;又或者你想学习Babel,可以看看我之前写的关于Babel的专栏 👉🏻 Babel专栏。
相信我,看完你一定会有所收获。
总结
-
js一样是import或者require进我们的源码,那么它也是模块。所以我们也要下载对应的loader(babel-loader)并且在module配置项配置它。 -
此外,我们除了配置
babel-loader,最重要的是还需要配置Babel(babel.config.js)。
所以,如果想要“编译es6+”,我们除了要配置webapck,最重要的是我们还要配置babel.config.js。如果你不想只是一味的复制粘贴Babel配置,你还必须得学习Babel相关知识。
还记得我们使用webpack的目的吗?输出浏览器能运行的css、img、js、html等前端资源。
OK,到目前我们已经通过webpack处理了css、img、js。我们再来看看如何通过webpack处理得到我们的html
处理html文件
在上面的例子中,我们想在浏览器看效果,我们需要:
- 在根目录新建一个
html文件 - 在新建的
html文件中,手动引入打包出来的资源文件
这个过程太麻烦了,有没有一种办法,我们只用提供一个html模板文件,然后通过webpack编译后,它自动帮我们把打包后的文件都引入好。这样,我们打包完直接运行html就能在浏览器看效果就好了呢?
webpack这么人性化的东西,当然是有的。
我们先用 learn-06 这里例子看看如何利用webpack达到我们上述的效果。
安装相关插件:
npm i html-webpack-plugin -D
这次webpack配置来点不一样的:
我们设置打包后的js储存目录为js文件夹;为打包后的js名字增加5个长度的hash值。
// webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
module.exports = {
entry: {
index: './src/index.js'
},
output: {
path: path.resolve(__dirname, './dist'),
filename: './js/[name]-[chunkhash:5].js',
clean: true
},
plugins: [
new HtmlWebpackPlugin({
filename: path.resolve(__dirname, './dist/[name].html'),
template: path.resolve(__dirname, './index.html'),
title: 'HtmlWebpackPlugin',
})
],
}
打包后的文件结构为:
dist
├── index.html
└── js
└── index-efbfd.js
打包后的html如下:

我们会发现:
- 我们的
html、js都被打包输出到dist文件夹下,这十分方便我们部署(之前我们是在根目录下新建index.html,因此打包后dist文件夹内只有img、js等文件) - 打包后的
html会帮我们自动引入好我们打包后的js文件
分析
从上面的例子我们可以看出,想要webpack处理html文件,我们是需要在webpack提供的plugins配置项来配置的。可能有些人会疑惑html也是一个模块,为什么是在plugins配置,而不是在module里面配置?我们来分析一下。
我们项目所有文件当然可以看作是一个模块,但是在module里面配置还是在plugins里面配置,取决于我们对这些模块的使用目的。一般我们在自己的源码中使用到这个模块,则需要相应的Loader来解析。
在上文讲解如何处理img、js时,我们的目的是为了在源码中解析这些文件:
img,我们需要将它转化成base64js,我们需要将es6+的东西编译成es5及以下
并且,我们的文件都是通过import或是require()的方式,引入到我们的项目中,因此这时候当然需要相应的Loader来转换这些模块。
但是在处理html文件时,我们的目的并不是为了要解析html,我们只是想让打包出来的html自动引用我们的js、img,这更像是使用自动引入的功能;而且,我们也没有把我们的html引入进我们的项目,因此我们当然不需要相应的Loader来解析。
还记得我们 上篇文章 我们讲解过:Loader用于转化模块,Plugin则用来加强webpack打包编译时的功能。
在此处我们处理html文件,目的更多侧重的是想要让打包出来的html自动引用我们的js、img这个功能。因此我们需要在plugins配置项来配置,增强webpack打包编译时的功能。
同理,假设我们想要在项目中解析某个html文件(在我们项目中,import html from './x.html'),那我们就得安装相应的loader(html-loader),并且在module配置项目中配置。
总结
在module还是plugins配置项里配置,取决于我们对这些模块的使用目的。
至此,我们已经成功通过配置webpack拿到了一个项目中需要的css、img、js、html;这也相当于学会了webpack的一些基本配置。
大家可以通过上面总结的一些方法,自己完成对sass、font、video等资源的处理,加深一下印象。
学习总结
通过上面对一些配置项的讲解,我们可以有以下总结:
- 想要解析
css,需要安装相应的loader,并且在module里配置 - 想要解析
img、font、video等常用类资源,我们不用安装loader(webpack已经内置解析他们的功能)。我们一般在module配置项里,使用asset/resource、asset/inline、asset这三个内置模块来解析 - 想要解析
js,我们除了要安装相应的loader(babel-loader),在module配置项里配置,最重要的是我们还要学习Babel的相关知识(感兴趣可以看看我的 👉 Babel专栏) - 想要解析
html文件,我们需要在plugins配置项里配置html-webpack-plugin插件 - 在
module还是plugins配置项里配置,取决于我们对这些模块的使用目的
通过上面的学习,我们整理一下,输出一个完整的webpack基础配置,让大家加深印象:
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
module.exports = {
entry: {
index: './src/index.js'
},
output: {
path: path.resolve(__dirname, './dist'),
filename: './js/[name]-[chunkhash:5].js',
clean: true
},
module: {
rules: [
{
test: /.(css|less)$/,
use: [
'style-loader',
'css-loader',
'less-loader',
],
},
{
test: /\.(png|svg|jpg|jpeg|gif)$/i,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 1024 * 10 // When the image size is < 10kb it will be converted to base64
}
},
generator: {
filename: '[name]-[hash:5][ext]' // Set the name of the output file
}
},
{
test: /\.m?js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader'
}
}
]
},
plugins: [
new HtmlWebpackPlugin({
filename: path.resolve(__dirname, './dist/[name].html'),
template: path.resolve(__dirname, './src/index.html'),
title: 'Webpack Basic Configuration',
})
],
}
完整的基础配置在 learn-07 ,建议大家看看完整版,这里只贴了webpack.config.js
最后
- 希望这篇文章的一些方法总结,学习目的能让大家更好的学会如何配置
webapck - 后面的文章将会深入配置。现实项目中,大多分开发环境、生产环境,因此我们将学习如何针对开发环境、生产环境不同的环境,进行不同
webpack的配置,这更贴近我们现实项目。如果感兴趣的话可以关注一下这个 👉 专栏 - 文章涉及到的
Babel知识,如果你感兴趣,想学习,也可以看看 👉 Babel专栏 - 文章涉及到的案例已经上传到 github,欢迎
star或fork学习
最后的最后,如果大家觉得文章有帮助到,创作不易,还请大家多点赞收藏评论,如果有异同点,欢迎评论讨论。
转载自:https://juejin.cn/post/7254067101451141177