前言
1. 为什么学习 Webpack?
Webpack 是一种用于构建 JavaScript 应用程序的静态模块打包器,它能够以一种相对「一致且开放」的处理方式,加载应用中的所有资源文件(图片、CSS、视频、字体文件等),并将其合并打包成浏览器兼容的 Web 资源文件。


在旧时代,我们只能用原生 JavaScript(ES5)、CSS、HTML 方式编写页面代码,开发与生产环境代码基本一致,开发与运行效率都非常低;其次,页面的图片、代码、CSS 等资源都能且只能通过 img
、 script
、link
等标签插入到页面中,我们需要非常精细地管理、设计各个标签出现的位置、顺序,这也会占用我们非常多的精力与注意力;并且,开发环境和生产环境一致,难以接入 TS 或 JS 新特性,以及CSS预处理工具。如下图代码片段:
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="shortcut icon" type="image/x-icon" href="./images/log.ico" media="screen">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>嗨.音乐</title>
<link rel="stylesheet" type="text/css" href="./fonts/font-awesome-4.7.0/css/font-awesome.min.css">
<link rel="stylesheet" type="text/css" href="./plugins/swiper/swiper-bundle.min.css">
<link rel="stylesheet" type="text/css" href="./css/base.css">
<link rel="stylesheet" type="text/css" href="./css/index.css">
<link rel="stylesheet" type="text/css" href="./css/header.css">
<link rel="stylesheet" type="text/css" href="./css/login.css">
<link rel="stylesheet" type="text/css" href="./css/main_show.css">
<script src="./plugins/swiper/swiper-bundle.min.js"></script>
<script src="./js/flexible.js"></script>
<script src="./js/jquery.min.js"></script>
<script src="./js/index.js"></script>
</head>
<body>
<!--网页logo 介绍 首行-->
<div class="head">
<div class="head_nav">
<a href="index.html">发现音乐</a>
<a href="index.html">我的音乐</a>
<a href="sub/shop.html" target="_blank">商城</a>
</div>
<!--导航部分-->
<div class="nav" id="nav">
2. 为什么是Webpack?

-
深入学习 Webpack,不仅能帮助你更快解决具体的工程技术问题,还能形成属于你个人的,极具区分度的核心竞争力! -
Vite 一类 Unbundle 工具定位于解决特定问题,而 Webpack 则几乎无所不能,功能覆盖小程序、桌面应用、微前端、WASM 等诸多场景,许多情况下 Webpack 依然是最优解。 -
同类工具或多或少都有借鉴 Webpack 之处,虽然具体实现差异很大,但解决工程化问题的思路基本一致,所谓一通百通,深入理解 Webpack 底层逻辑,以及处理具体问题的方式方法后,相同的知识必然也能套用到同类工具中。 -
Webpack 还在持续迭代发展,V5 之后推出的持久化缓存、 lazyCompilation
等特性极大强化了构建性能,未来虽不大可能超越 Unbundle 方案的性能优势,但相信会逐渐缩小差距,直至可被用户接受。
3. Webpack 的优点
-
所有资源都是 Module,所以可以用同一套代码实现诸多特性,包括:代码压缩、Hot Module Replacement、缓存等; -
打包时,资源与资源之间非常容易实现信息互换,例如可以轻易在 HTML 插入 Base64 格式的图片; -
借助 Loader,Webpack 几乎可以用任意方式处理任意类型的资源,例如可以用 Less、Stylus、Sass 等预编译 CSS 代码。 -
Webpack 具有极强的开放性,也让它得以成为前端工程化环境的 「基座」,我们可以围绕 Webpack 轻易接入一系列工程化工具,例如 TypeScript、CoffeScript、Babel 一类的 JavaScript 编译工具;或者 Less、Sass、Stylus、PostCSS 等 CSS 预处理器;或者 Jest、Karma 等测试框架,等等。 -
自 2012 年首次发布至今,Webpack 还处于快速迭代成长阶段,社区依然保持极大活力;Webpack 已经发布了最新的 5.73.0 版本,经过 5 个大版本迭代以及社区的不断努力,现如今的 Webpack 已经非常非常成熟。
4. 如何学习 Webpack?

「1. 入门应用」
-
理解打包流程 -
熟练掌握常用配置项、Loader、插件的使用方法,能够灵活搭建继承 Vue、React、Babel、Eslint、Less、Sass、图片处理等工具的 Webpack 环境。 -
掌握常见脚手架的用法,例如:Vue-cli,create-react-app、@angular/cli
「2. 进阶」
-
理解 Loader、Plugin 机制,能够自行开发 Webpack 组件 -
理解常见性能优化手段、并能解决实际问题 -
理解前端工程化概念与生存现状
「3. 大师级」
-
阅读源码,理解 Webpack 编译、打包原理,甚至参与共建
1、使用 Webpack
1. 第一个 Webpack项目
首先新建文件夹 wepack-test, 通过编辑器打开,文件结构:
├── src
| └── index.js
└── webpack.config.js
填写内容: webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js', //项目入口文件
mode: 'development', //环境
devtool: false,
output: { //输出目录
filename: '[name].js',
path: path.join(__dirname, './dist')
}
}
index.js
document.write("hello Webpack!");
进行项目初始化,安装 Webpack:在项目根目录下,打开终端,执行命令:
npm init # 一路回车
npm i -D webpack webpack-cli

在项目根目录下,打开终端,执行编译命令,构建项目:
npx webpack
执行成功输出生产文件:


2. 理解 Webpack配置项
「核心流程 — 极度简化版」
Webpack 原生提供了上百种配置项,这些配置最终都会作用于 Webpack 打包过程的不同阶段,因此我们可以从Webpack 编译流程来了解各项配置的作用。

-
入口处理:从 entry
配置项开始,启动编译流程 -
从 entry
配置项所指定的入口文件开始,根据require
或import
等语句找到依赖资源 -
根据 moudle
配置项,调用资源转移器,将 png、css 等非标准 JS 资源转译为 JS 内容 -
递归调用 1 2,指定所有引用的文件和非标准 JS 资源处理完毕 -
将转译后的资源内容合并打包为可直接在浏览器运行的 JS 文件
「webpack 特点 模块化 + 一致性」
-
多个文件资源合并成一个,减少 http 请求数 -
支持模块化开发 -
支持高级 JS 特性 -
支持 TypeScript CoffeeScript 方言 -
统一图片、CSS、字体等其他资源的处理模型 -
…
「那么,怎么使用 Webpack?」
Webpack 的使用方法,基本都围绕“配置”展开,而这些配置大致可分为两类:
-
流程类:作用于流程中某个或若干个环节,直接影响打包效果的配置项 -
工具类:主流程之外,提供更多工程化能力的配置项
❝
流程类配置项综述
❞
与打包流程强相关的配置项有:
-
输入输出:
-
entry
:用于定义项目入口文件,Webpack 会从这些入口文件开始按图索骥找出所有项目文件; -
context
:项目执行上下文路径; -
output
:配置产物输出路径、名称等; -
模块处理:
-
resolve
:用于配置模块路径解析规则,可用于帮助 Webpack 更精确、高效地找到指定模块 -
module
:用于配置模块加载规则,例如针对什么类型的资源需要使用哪些 Loader 进行处理 -
externals
:用于声明外部资源,Webpack 会直接忽略这部分资源,跳过这些资源的解析、打包操作 -
后处理:
-
optimization
:用于控制如何优化产物包体积,内置 Dead Code Elimination、Scope Hoisting、代码混淆、代码压缩等功能 -
target
:用于配置编译产物的目标运行环境,支持 web、node、electron 等值,不同值最终产物会有所差异 -
mode
:编译模式短语,支持development
、production
等值,可以理解为一种声明环境的短语
这里的重点是,Webpack 「首先」需要根据输入配置(entry/context
) 找到项目入口文件;「之后」根据按模块处理(module/resolve/externals
等) 所配置的规则逐一处理模块文件,处理过程包括转译、依赖分析等;模块处理完毕后,最后「再根据」后处理相关配置项(optimization/target
等)合并模块资源、注入运行时依赖、优化产物结构等。
这些配置项与打包流程强相关,建议学习时多关注它们对主流程的影响,例如 entry
决定了项目入口,而 output
则决定产物最终往哪里输出;resolve
决定了怎么找到模块,而 module
决定了如何解读模块内容,等等。
❝
工具类配置项综述
❞
除了核心的打包功能之外,Webpack 还提供了一系列用于提升研发效率的工具,大体上可划分为:
-
开发效率类:
-
watch
:用于配置持续监听文件变化,持续构建 -
devtool
:用于配置产物 Sourcemap 生成规则 -
devServer
:用于配置与 HMR 强相关的开发服务器功能 -
性能优化类:
-
cache
:Webpack 5 之后,该项用于控制如何缓存编译过程信息与编译结果 -
performance
:用于配置当产物大小超过阈值时,如何通知开发者 -
日志类:
-
stats
:用于精确地控制编译过程的日志内容,在做比较细致的性能调试时非常有用 -
infrastructureLogging
:用于控制日志输出方式,例如可以通过该配置将日志输出到磁盘文件
逻辑上,每一个工具类配置都在主流程之外提供额外的工程化能力,例如 devtool
用于配置产物 Sourcemap 生成规则,与 Sourcemap 强相关;devServer
用于配置与 HMR 相关的开发服务器功能;watch
用于实现持续监听、构建。
工具类配置内聚性较强,通常一个配置项专注于解决一类工程问题,学习时建议先对配置项按其功能做个简单分类,例如上述开发效率类、性能优化类等,之后再展开研究其可选值与效果。

3. 通过例子了解 Webpack 配置过程
「引入CSS预处理器,处理CSS资源」
首先搭建项目,示例文件结构:
.
├── src
| ├── index.js
| └── index.css
└── webpack.config.js
填写内容
index.js
import styles from './index.css'
index.css
.box{
width: 100px;
height: 100px;
}
初始化项目,安装 Webpack
npm init # 一路回车
npm i -D webpack webpack-cli
安装 CSS 处理器 loader
npm add -D css-loader style-loader
配置 webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
mode: 'development',
devtool: false,
output: {
filename: '[name].js',
path: path.join(__dirname, './dist')
},
module: {
//CSS处理器
rules: [{
test: /.css/i,
use: [
'style-loader',
'css-loader'
]
}]
}
}
在项目根目录下,打开终端,执行编译命令,构建项目:
npx wabpack

❝
问题
❞
-
Loader 有什么作用?为什么这里需要用到 css-loader、style-loader? -
与旧时代 —- 在 HTML 文件中维护 css 相比,这种方式会有什么优劣处? -
有没有接触过 Less、Sass、Stylus 这一类 CSS 预编译框架?如何在 Webpack 接入这些工具?
❝
回答
❞
Loader有什么作用?
Webpack Loader 最核心的只能是实现内容转换器 —— 将各式各样的资源转化为标准 JavaScript 内容格式,例如:
-
css-loader
将 css 转换为__WEBPACK_DEFAULT_EXPORT__ = ".a{ xxx }"
格式 -
html-loader
将 html 转换为__WEBPACK_DEFAULT_EXPORT__ = "<!DOCTYPE xxx"
格式 -
vue-loader
更复杂一些,会将.vue
文件转化为多个 JavaScript 函数,分别对应 template、js、css、custom block
为什么这里需要用到 css-loader、style-loader ?
-
本质上是因为 Webpack 只认识符合 JavaScript 规范的文本(Webpack 5之后增加了其它 parser):在构建(make)阶段,解析模块内容时会调用 acorn
将文本转换为 AST 对象,进而分析代码结构,分析模块依赖;这一套逻辑对图片、json、Vue SFC等场景就不工作了,就需要 Loader 介入将资源转化成 Webpack 可以理解的内容形态。
与旧时代 —- 在 HTML 文件中维护 css 相比,这种方式会有什么优劣处?
-
优点:统一管理 -
缺点:耦合度高
有没有接触过 Less、Sass、Stylus 这一类 CSS 预编译框架?如何在 Webpack 接入这些工具?
-
有,接入 less 示例,在理解loader章节叙述
「引入 Babel 处理 JS 兼容性问题」

Babel 的作用: 用于将 JS 语法降级, 处理兼容性, 如将 ES6 规范,转换为 ES5 规范
为什么这样做:
-
JavaScript 语法标准繁多, 浏览器支持程度不一 -
开发者需要用到高级语法
安装 babel 依赖
npm i -D @babel/core @babel/preset-env babel-loader
配置 webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
mode: 'development',
devtool: false,
output: {
filename: '[name].js',
path: path.join(__dirname, './dist')
},
module: {
rules: [{ //less处理
test: /.less$/i,
use: [
'style-loader',
'css-loader',
'less-loader'
]
},{ //js处理 babel
test: /.js?$/,
use:[{
loader: 'babel-loader',
options:{
presets:[
['@babel/preset-env']
]
}
}]
}]
}
}
执行 npx webpack

❝
问题
❞
-
Babel 具体有什么功能? -
Babel 与 Webpack 分别解决了什么问题? 为何能协作到一起?
❝
回答
❞
Babel 具体有什么功能 ?
-
Babel 插件大致分为两种:语法插件和转换插件。语法插件作用于 @babel/parser,负责将代码解析为抽象语法树(AST)(官方的语法插件以 babel-plugin-syntax 开头);转换插件作用于 @babel/core,负责转换 AST 的形态。
Babel 与 Webpack 分别解决了什么问题? 为何能协作到一起?
-
Babel 解决了项目的兼容性问题 -
Webpack 使项目模块化, 解决依赖问题 -
Webpack 主要是将非标准 JS 资源转译为 JS 内容,进行统一资源管理,而 JS 可能在不同浏览器上存在兼容问题,所以需要 Babel 来进行协作
「引入HTMLWebPackPlugin 生成 HTML」
安装 HTMLWebPackPlugin 插件
npm i -D html-webpack-plugin
配置 webpack.config.js
const path = require('path');
//引入 依赖
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
mode: 'development',
devtool: false,
output: {
filename: '[name].js',
path: path.join(__dirname, './dist')
},
module: {
rules: [{ //less处理
test: /.less$/i,
use: [
'style-loader',
'css-loader',
'less-loader'
]
},{ //js处理
test: /.js?$/,
use:[{
loader: 'babel-loader',
options:{
presets:[
['@babel/preset-env']
]
}
}]
}]
},
//插件
plugins:[new HtmlWebpackPlugin()]
}
执行 npx webpack

❝
问题
❞
-
相比于手工维护 HTML 内容,这种自动生成的方式有什么优缺点?
❝
回答
❞
相比于手工维护 HTML 内容,这种自动生成的方式有什么优缺点?
-
优点:简化了HTML文件的创建,无需手工维护 HTML 文件 -
缺点:配置繁琐
「开启模块热替换工具,进行项目的实时预览」
HMR Hot Moudle Replacement — 模块热替换工具:热更新代码,当你修改代码保存后,会自动更新,实时显示

安装 devserver
npm install -D webpack-dev-server
配置 webpack.config.js
const path = require('path');
//引入 依赖
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
mode: 'development',
devtool: false,
devServer:{
hot: true, //开启热加载
open:true
},
watch:true, //持续监听代码改变生成新版本
output: {
filename: '[name].js',
path: path.join(__dirname, './dist')
},
module: {
rules: [{ //less处理
test: /.less$/i,
use: [
'style-loader',
'css-loader',
'less-loader'
]
},{ //js处理
test: /.js?$/,
use:[{
loader: 'babel-loader',
options:{
presets:[
['@babel/preset-env']
]
}
}]
}]
},
//插件
plugins:[new HtmlWebpackPlugin()]
}
执行命令,运行项目至浏览器
npx webpack serve
「使用 Tree-Shaking 删除没有使用的代码」

❝
Tree-Shaking 树摇 工具
把定义的代码,但没有进行使用,进行删掉
❞
使用 Tree-Shaking, 配置 webpack.config.js
const path = require('path');
//引入 依赖
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
mode: 'production', //使用树摇,注意把 模式改为 生产环境
devtool: false,
devServer:{
hot: true, //开启热加载
open:true
},
optimization:{
usedExports:true //开启 树摇
},
watch:true, //持续监听代码改变生成新版本
output: {
filename: '[name].js',
path: path.join(__dirname, './dist')
},
module: {
rules: [{ //less处理
test: /.less$/i,
use: [
'style-loader',
'css-loader',
'less-loader'
]
},{ //js处理
test: /.js?$/,
use:[{
loader: 'babel-loader',
options:{
presets:[
['@babel/preset-env']
]
}
}]
}]
},
//插件
plugins:[new HtmlWebpackPlugin()]
}
验证: 编写 index.js bar.js
//bar.js
let bar1 = '1';
let bar2 = '2';
export {
bar1,
bar2
}
//index.js
import {
bar,
bar2
} from './bar'
console.log(bar);
注意此时是生产环境,执行 npx webpack

以下效果是开发环境和生产环境的对比

❝
其他工具
❞
-
缓存 -
Sourcemap -
性能监控 -
日志 -
代码压缩 -
分包
3、进阶篇:理解 Loader
1. 概述
❝
问题:Webpack 只认识JS
❞

为了处理非标准 JS 资源,设计出资源翻译模块—Loader,用于将资源翻译为标准JS
2. 使用Loader
文件结构
├── src
| ├── a.less
| ├── b.less
| └── index.js
└── webpack.config.js
引入 less
npm install less less-loader -D
配置 webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
mode: 'development',
devtool: false,
output: {
filename: '[name].js',
path: path.join(__dirname, './dist')
},
module: {
//less处理器
rules: [{
test: /.less$/i,
use: [
'style-loader',
'css-loader',
'less-loader'
]
}]
}
}
index.js
import styles from './a.less'
❝
认识Loader — 链式调用
❞
使用上,可以为某种资源文件配置多个 Loader,Loader 之间按照配置的顺序「从前到后(pitch),再从后到前依次执行」,从而形成一套内容转译工作流,例如对于下面的配置:
module.exports = {
module: {
rules: [
{
test: /.less$/i,
use: [
"style-loader",
"css-loader",
"less-loader",
],
},
],
},
};

上述示例中,三个 Loader 分别起如下作用:
-
less-loader
:实现 less => css 的转换,输出 css 内容,无法被直接应用在 Webpack 体系下 -
css-loader
:将 css 内容包装成类似module.exports = "${css}"
的内容,包装后的内容符合 JavaScript 语法 -
style-loader
:做的事情非常简单,就是将 css 模块包进 require 语句,并在运行时调用 injectStyle 等函数将内容注入到页面的 style 标签
❝
认识Loader :其它特性
❞
-
链式执行 -
支持异步执行 -
分 normal ,pitch 两种模式
2. 编写loader
3. 常见 Loader
站在使用角度,建议掌握这些常见的 Loader 的功能、配置方法

4、进阶篇:理解插件
1. 概述
❝
插件是什么?
❞
-
插件是为了给程序提供一种扩展能力 -
比如 Vs Code、Vue
甚至、Webpack 本身的很多功能都是插件来实现的,我们可以通过下图看出:

2. 使用插件
-
安装插件依赖 npm -
在 webpack 配置,引入插件 -
创建插件实例

3. 写webpack插件
首先:插件围绕 “钩子“ 展开

钩子的核心信息:
-
时机 :编译过程的特点阶段,Webpack 会以钩子形式通知插件此刻正在发生什么事情 -
上下文:通过 tapable 提供的回调机制,以参数形式传递上下文信息 -
交互:在上下文参数对象中附带很多存在 side effect 的交互接口,插件可以通过这些接口改变

时机: compier.hooks.compliation
参数:compliation
交互:dependencyFactories.set

5、总结
我们前面学了:
-
Webpack 的作用 -
理解 Webpack 配置结构,学习关键配置项 -
Loader 的作用与常用 Loader -
插件基本形态与作用
推荐学习网址:
Webpack 官方文档[1]
Babel 官网[2]
深入浅出 Webpack · 深入浅出[3]
Webpack 5 知识体系 – GitMind[4]
Reference
Webpack 官方文档: https://webpack.js.org/configuration/
[2]
Babel 官网: https://babeljs.io/
[3]
深入浅出 Webpack · 深入浅出: https://webpack.wuhaolin.cn/
[4]
Webpack 5 知识体系 – GitMind: https://gitmind.cn/app/doc/fac1c196e29b8f9052239f16cff7d4c7
原文始发于微信公众号(yanghi):Webpack系列之构建Webpack知识体系
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/226965.html