从0开始认识Webpack

  • Webpack 中 一切(JS, 图片…)皆为模块。
  • Webpack 配置灵活 & 具备强大的插件化扩展能力。
  • Webpack 需要了解诸多概念
    1. entry
    2. output
    3. mode
    4. loaders
    5. plugins
    6. 热更新
    7. code spliting
    8. tree shaking
  • Webpack 的学习曲线
    1. Webpack 打包速度
    2. Webpack 打包体积
    3. 页面加载时性能优化

本文档分为四大章节

1. 基础篇

掌握 Webpack 的核心概念和开发必备技巧

2. 进阶篇

编写 Webpack 的构建配置并掌握优化策略

3. 原理篇

剖析内部运行原理并编写自定义Loader & 插件

4. 实战篇

通过 Webpack 商城项目实战牢固知识


目录

01 | 基础篇:Webpack 与 构建发展史
02 | 基础篇:Webpack 基础用法
03 | 基础篇:Webpack 进阶用法
04 | 进阶篇:编写可维护的 Webpack 构建配置
05 | 进阶篇:Webpack 构建速度和体积优化策略
06 | 原理篇:通过源码掌握 Webpack 打包原理
07 | 原理篇:编写 Loader 和插件
08 | 实战篇:React 全家桶和 webpack 开发商城项目

01 | 基础篇:Webpack 与 构建发展史

Q: 为什么需要构建工具?
A: 转换 ES6 语法 & 转换JSX & CSS 前缀补全/预处理器 & 压缩混淆 & 图片压缩 …

前端构建演变之路
在这里插入图片描述

Q: 为什么选择Webpack?
A: 在这里插入图片描述
社区生态活跃
配置灵活 & 插件化扩展
官方更迭速度快

初识 Webpack: 配置文件名称
webpack 默认配置文件: webpack.config.js
可以通过 webpack --config 指定配置文件

初始 Webpack:Webpack 配置组成
在这里插入图片描述
Q: 零配置 webpack 包含那些内容?
A:在这里插入图片描述

环境搭建:安装 Node.js 和 NPM

安装 nvm (https://github.com/nvm-sh/nvm)(node版本管理工具)

  • 通过 curl 安装
curl -o- https://raw.gethubsuercontent.com/nvm-sh/nvm/v0.34.0/install.sh | bash
  • 通过 wget 安装
wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.34.0/install.sh | bash

注意配置 nvm 环境变量

安装 Node.js 和 NPM

nvm install v10.15.3
  • 检查是否安装成功
node -v 
npm -v
环境搭建: 安装 webpack 和 webpack-cli

创建空目录和 package.json

mkdir my-project
cd my-project
npm init -y

安装 webpack 和 webpack-cli

npm install webpack webpack-cli --save-dev
// 检查是否安装成功
./node_module/.bin/webpack -v

一个简单的例子
在这里插入图片描述
通过 npm script 运行 webpack

在这里插入图片描述


02 | 基础篇:Webpack 基础用法

介绍 entry output loader plugins mode 在实际中如何使用
介绍 代码压缩 & 代码指纹如何处理
介绍 代码解析 JS JSX less 等如何解析
介绍 如何实现热更新,几种常用的热更新方式以及差异

核心概念之 Entry

  • entry 用来指定 webpack 的打包入口
  • 依赖的入口是 entry
  • 对于非代码(图片/ 字体)也会不断加入到依赖图中

Entry 的用法
在这里插入图片描述
核心概念之 Output

  • Output 用来告诉 webpack 如何将编译后的文件输出到磁盘

Output 的用法:单入口配置
在这里插入图片描述
Output 的用法:多入口配置
在这里插入图片描述
核心概念之 Loaders

  • webpack 开箱即用只支持 JS 和 JSON 两种文件类型, 通过 Loaders 去支持其他文件类型并且把他们转化为有效的模块,并且可以添加到依赖图中。
  • 本身是一个函数,接收源文件作为参数,返回转换的结果。

常见的 Loaders 有哪些?
在这里插入图片描述
Loader 的用法
在这里插入图片描述

核心概念之 Plugins

  • 插件用于 bundle 文件的优化, 资源管理和环境变量注入
  • 作用于整个构建过程

常见的 Plugins 有那些?
在这里插入图片描述
Plugins 的用法
在这里插入图片描述

核心概念之 Mode

  • Mode 用来指定当前构建环境是:production/ development/ none
  • 设置 mode 可以使用 webpack 内置的函数, 默认值为 production

Mode 的内置函数功能
在这里插入图片描述


资源解析: 解析 ES6

使用 babel-loader
babel 的配置文件是:.babelrc

在这里插入图片描述
资源解析: 增加 ES6 的babel preset 配置
在这里插入图片描述
安装 babel

// i: install D: --save-dev
npm i @babel/core @babel/preset-env babel-loader -D

资源解析: 解析React JSX
在这里插入图片描述
安装 react 相关库

npm i react react-dom @babel/preset-react -D

资源解析: 解析 CSS

css-loader 用于加载 .css 文件, 并且转换成 commonjs对象
style-loader 将样式通过<style>标签插入到 head 中

在这里插入图片描述

*要注意 loader调用是链式调用执行顺序是从右到左 因此要将css-loader放在右边,这样css-loader会先执行

安装 css 相关

npm i style-loader css-loader -D

资源解析:解析 Less 和 SaSS

less-loader 将用于将 less 转换成 css

在这里插入图片描述
安装 less 相关

npm i less less-loader -D

资源解析: 解析图片

file-loader 用于处理文件

在这里插入图片描述
安装 file 相关

npm i file-loader -D

资源解析: 解析字体

file-loader 也可以用于处理字体

在这里插入图片描述

资源解析: 使用 url-loader

url-loader 也可以处理图片和字体
可以设置较小资源自动 base64
url-loader 内部用的也是 file-loader

在这里插入图片描述
安装 url-loader

npm i url-loader -D

Webpack 中的文件监听

文件监听是在发现源码发生变化时,自动重新构建出新的输出文件。

webpack 开启监听模式, 有两种办法:

  • 启动 webpack 命令时, 带上 --watch 参数
  • 在配置 webpack.config.js 中设置 watch: true

webpack 中的文件监听使用

唯一的缺陷: 每次需要手动刷新浏览器

在这里插入图片描述

文件监听的原理分析

轮询判断文件的最后编译时间是否发生变化
某个文件发生了变化,并不会立刻告诉监听者,而是先缓存起来,等aggregateTimeout

在这里插入图片描述
热更新: webpack-dev-server

  • WDS 不刷新浏览器
  • WDS 不输出文件,而是放在内存中
  • 使用 HotModuleReplacementPlugin 插件

在这里插入图片描述

安装 webpack-dev-server

npm i webpack-dev-server -D
// 注意版本对应,若执行报错,可能是版本不匹配
// 下面是卸载命令
npm uninstall webpack-dev-server-D

热更新:使用webpack-dev-middleware

WDM 将 webpack 输出的文件传输给服务器
适用于灵活的定制场景

在这里插入图片描述
热更新的原理分析

webpack Compile: 将 JS 编译成 Bundle
HMR Server: 将热更新的文件输出给 HMR Runtime
Bundle server: 提供文件在浏览器访问
HMR Runtime: 会被注入到浏览器,更新文件的变化
bundle.js: 构建输出的文件

在这里插入图片描述


什么是文件指纹?

打包后输出的文件名的后缀
进行版本管理

在这里插入图片描述
文件指纹是如何生成?

  • hash: 和整个项目的构建相关, 只要项目文件有修改,整个项目构建的 hash 值就会更改
  • Chunkhash:和 webpack 打包的 chunk 有关,不同的 entry 会生成不同的 chunkhash 值
  • ContentHash: 根据文件内容来定义 hash , 文件内容不变,则 contenthash 不变 (对于CSS 一般使用 ContentHash)

JS 的文件指纹设置

设置 output 的 filename, 使用[chunkhash]

在这里插入图片描述
CSS 的文件指纹设置

设置 MiniCssExtracPlugin 的 filename, 使用[contenthash]

因为,我们通过css-loader解析后直接通过 style-loader 将css文件插入到style标签并且放到到 head 头部,并没有一个css文件,于是使用 这种方法,将style-loader的css提取出来成一个css文件。

在这里插入图片描述
安装 mini-css-extract-plugin -D

npm i mini-css-extract-plugin -D

注意 mini-css-extract-plugin 和 style-loader 是互斥的,一个是要提取,一个是放在 head 中
将MiniCssExtractPlugin.loader 替换 style-loader

图片的文件指纹设置

设置 file-loader 的 name, 使用 [hash]
这里的 [hash] 和之前 js css 设置文件指纹中的 hash 是不一样的

在这里插入图片描述
在这里插入图片描述

md5 默认 32 位,这里取前 8 位
图片和字体的设置是一样的


代码压缩
  • HTML 压缩
  • CSS 压缩
  • JS 压缩
    在这里插入图片描述
    JS 文件的压缩

内置了 uglifyjs-webpack-plugin

CSS 文件的压缩

使用 optimize-css-assets-webpack-plugin
同时使用 cssnano

在这里插入图片描述
安装 css 压缩相关

npm i optimize-css-assets-webpack-plugin -D
npm i cssnano -D

HTML 文件的压缩

修改 html-webpack-plugin, 设置压缩参数

在这里插入图片描述
安装 html 压缩相关

npm i html-webpack-plugin -D

template:指定模板所在位置
filaname:打包出来后 html 的名称
chunks:指定生成的 html 使用那些 chunk
inject: css js 会自动注入到 html 中


当前构建时的问题

  • 每次构建的时候不会清理目录,造成构建目录的输出目录 output 文件越来越多

通过 npm scripts 清理构建目录

rm -rf ./dist && webpack
rimraf ./dist && webpack

自动清理构建目录

避免构建前每次都需要手动删除 dist
使用 clean-webpack-plugin: 默认会删除 output 指定的输出目录

在这里插入图片描述
安装 clean-webpack-plugin

npm i clean-webpack-plugin -D

CSS3 的属性为什么需要前缀?
在这里插入图片描述
举个例子:
在这里插入图片描述
PostCSS 插件 autoprefixer 自动补齐 CSS3 前缀

使用 autoprefixer 插件
根据 Can I Use 规则 ( https://caniuse.com)

在这里插入图片描述
安装 补全 相关

npm i postcss-loader autoprefixer -D

浏览器的分辨率

在这里插入图片描述
CSS 媒体查询实现响应式布局

缺陷: 需要写多套适配样式代码

在这里插入图片描述

rem 是什么?

W3C 对 rem 的定义: font-size of root element

rem 和 px 的对比

  • rem 是相对单位
  • px 是绝对单位

移动端 CSS px 自动转换成 rem

使用 px2rem-loader

页面渲染时计算根元素的 font-size 值

  • 可以使用手淘的 lib-flexible 库
  • https://github.com/amfe/lib-flexible

在这里插入图片描述
安装 px2rem-loader lib-flexible

npm i px2rem-loader -D
npm i lib-flexible -S // -S: 安装到项目依赖中

资源内联的意义

代码层面:

  • 页面框架的初始化脚本
  • 上报相关打点
  • css 内联避免页面闪动

请求层面: 减少 HTTP 网络请求数

  • 小图片或者字体内联(url-loader)

HTML 和 JS 内联

raw-loader 内联 html
在这里插入图片描述

raw-loader 内联 JS
在这里插入图片描述
CSS 内联

  • 方案1:借助 style-loader
  • 方案2:html-inline-css-webpack-plugin

在这里插入图片描述
安装 raw-loader

npm i raw-loader@0.5.1 -D

多页面应用(MPA)概念

每一次页面跳转的时候,后台服务器都会给返回一个新的 html 文档, 这种类型的网站也就是多页网站,也叫多页应用。
优点: 页面间解耦, SEO更加友好

多页面打包基本思路

每个页面对应一个 entry , 一个 html-webpack-plugin
缺点: 每次新增或删除页面需要改 webpack 配置

在这里插入图片描述
多页面打包通用方案

动态获取 entry 和设置 html-webpack-plugin 数量

利用 glob.sync

  • entry: glob.sync(path.join(__dirname, ‘./src/*/index.js’))

在这里插入图片描述
安装 打包相关

npm i glob -D

使用 source map

作用: 通过 source map 定位到 源代码

开发环境开启,线上环境关闭

  • 线上排查问题的时候可以将 sourcemap 上传到错误监控系统

source map 关键字

  • eval: 使用eval包裹模块代码
  • source map: 产生.map 文件
  • cheap: 不包含列信息
  • inline: 将.map 作为DataURI 嵌入,不单独生成.map文件
  • module: 包含loader的sourcemap

souce map 类型
在这里插入图片描述


基础库分离

思路: 将 react/ react-dom 基础包通过 cdn 引入, 不打入 bundle中
方法: 使用html-webpack-externals-plugin

在这里插入图片描述

利用 SplitChunksPlugin 进行公共脚本分离

Webpack4 内置的, 替代CommonsChunkPlugin 插件

chunks 参数说明:

  • async 异步引入的库进行分离(默认)
  • initial 同步引入的库进行分离
  • all 所有引入的库进行分离(推荐)

在这里插入图片描述
利用 SplitChunksPlugin 分离 基础包

test: 匹配出需要分离的包

在这里插入图片描述

安装 html-webpack-externals-plugin

 npm i html-webpack-externals-plugin -D

利用 SplitChunksPlugin 分离页面公共文件
minChunks: 设置最小引用次数为2次
minuSize:分离的包体积的大小
在这里插入图片描述


tree shaking(摇树优化)

  • 概念:1个模块可能有多个方法,只要其中的某个方法用到了,则整个我呢见都会被打到bundle里面去,tree shaking 就是只把用到的方法打到bundle,没有用到的方法会在uglify 阶段被擦除掉。

  • 使用:webpack默认支持,在.babelrc 里面设置 modules: false 即可production mode 的情况下默认开启

  • 要求:必须是 ES6 的语法, CJS的方式不支持

DCE (Elimination)

  • 代码不会被执行,不可到达
  • 代码执行的结果不会被用到
  • 代码只会影响死变量(只写不读)
    在这里插入图片描述

Tree-shaking 原理

利用 ES6 模块的特点:

  • 只能作为模块顶层的语句出现
  • import 的模块名只能是字符串常量
  • import binding 是 immutable 的
    代码擦除: uglify 阶段删除无用代码

Scope Hoisting 使用和原理分析
现象: 构建后的代码存在大量闭包代码
在这里插入图片描述
在这里插入图片描述
会导致什么问题?

大量函数闭包包裹代码,导致体积增大(模块越多越明显)
运行代码时创建的函数作用域变多,内存开销变大

模块转换分析
在这里插入图片描述
结论:

  • 被 webpack 转换后的模块会带上一层包裹
  • import 会被转换成__webpack_require

进一步分析 webpack 的模块机制

在这里插入图片描述
分析:

  • 打包出来的是一个 IIFE (匿名闭包)
  • modules 是一个数组,每一项是一个模块初始化函数
  • __webpack_require 用来加载模块,返回module.exports
  • 通过 WEBPACK_REQUIRE_METHOD(0) 启动程序

scope hoisting 原理

  • 原理: 将所有模块的代码按照引用顺序放在一个函数作用域里,然后适当的重命名一些变量以放置变量名冲突
  • 对比:通过 scope hoisting 可以减少函数声明代码和内存开销

在这里插入图片描述
scope hoisting 使用

webpack mode 为 production 默认开启
必须是 ES6 语法, CJS 不支持

在这里插入图片描述
代码分割的意义
对于大的 web 应用而言,所有的代码放在一个文件中显然是不够有效的,特别是当你的某些代码块是在某些特殊的情况下才会使用到。webpack提供一个功能就是将你的代码库分割成 chunks ,当代码运行到需要它们的时候再进行加载。
使用场景:

  • 抽离相同代码到一个共享块
  • 脚本懒加载,使得初始下载的代码更小
    懒加载 JS 脚本的方式
    CommonJS: require.ensure
    ES6: 动态 import (目前没有原生支持,需要babel转换)

如何使用动态 import?

  1. 安装babel 插件
npm install @babel/plugin-syntax-dynamic-import -D
  1. ES6 动态 import (目前没有原生支持,需要babel转换)
{
  "plugins": ["@babel/plugin-syntax-dynamic-import"],
}

在这里插入图片描述
在这里插入图片描述
** webpack 如何打包库和组件 **
webpack 除了可以用来打包应用,也可以用来打包 js 组件和库
实现一个大整数加法库的打包

  • 需要打包压缩版和非压缩版
  • 支持 AMD/CJS/ESM模块引入
    在这里插入图片描述
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值