webpack 热更新原理

-
当修改了一个或多个文件; -
文件系统接收更改并通知 webpack
; -
webpack
重新编译构建一个或多个模块,并通知 HMR 服务器进行更新; -
HMR Server
使用webSocket
通知HMR runtime
需要更新,HMR
运行时通过HTTP
请求更新jsonp
-
HMR
运行时替换更新中的模块,如果确定这些模块无法更新,则触发整个页面刷新
3 webpack Loader
由于 Webpack 是基于 Node,因此 Webpack 其实是只能识别 js 模块,比如 css / html / 图片等类型的文件并无法加载,因此就需要一个对 不同格式文件转换器。其实 Loader 做的事,也并不难理解: 对 Webpack 传入的字符串进行按需修改。例如一个最简单的 Loader:
// html-loader/index.js
module.exports = function(htmlSource) {
// 返回处理后的代码字符串
// 删除 html 文件中的所有注释
return htmlSource.replace(/<!--[wW]*?-->/g, '')
}
当然,实际的 Loader 不会这么简单,通常是需要将代码进行分析,构建 AST (抽象语法树), 遍历进行定向的修改后,再重新生成新的代码字符串。如我们常用的 Babel-loader 会执行以下步骤:
-
babylon
将ES6/ES7
代码解析成AST
-
babel-traverse
对AST
进行遍历转译,得到新的 AST -
新 AST
通过babel-generator
转换成ES5
Loader 特性:
-
链式传递,按照配置时相反的顺序链式执行; -
基于 Node 环境,拥有 较高权限,比如文件的增删查改; -
可同步也可异步;
常用 Loader:
-
file-loader
: 加载文件资源,如 字体 / 图片 等,具有移动/复制/命名等功能; -
url-loader
: 通常用于加载图片,可以将小图片直接转换为 Date Url,减少请求; -
babel-loader
: 加载 js / jsx 文件, 将 ES6 / ES7 代码转换成 ES5,抹平兼容性问题; -
ts-loader
: 加载 ts / tsx 文件,编译 TypeScript; -
style-loader
: 将 css 代码以<style>
标签的形式插入到 html 中; -
css-loader
: 分析@import 和 url(),引用 css 文件与对应的资源; -
postcss-loader
: 用于 css 的兼容性处理,具有众多功能,例如 添加前缀,单位转换 等; -
less-loader / sass-loader
: css 预处理器,在 css 中新增了许多语法,提高了开发效率;
编写原则:
-
单一原则: 每个 Loader 只做一件事; -
链式调用: Webpack 会按顺序链式调用每个 Loader; -
统一原则: 遵循 Webpack 制定的设计规则和结构,输入与输出均为字符串,各个 Loader 完全独立,即插即用;
4 webpack Plugin
插件系统是 Webpack 成功的一个关键性因素。在编译的整个生命周期中,Webpack 会触发许多事件钩子,Plugin 可以监听这些事件,根据需求在相应的时间点对打包内容进行定向的修改。
一个最简单的 plugin 是这样的:
class Plugin{
// 注册插件时,会调用 apply 方法
// apply 方法接收 compiler 对象
// 通过 compiler 上提供的 Api,可以对事件进行监听,执行相应的操作
apply(compiler){
// compilation 是监听每次编译循环
// 每次文件变化,都会生成新的 compilation 对象并触发该事件
compiler.plugin('compilation',function(compilation) {})
}
}
注册插件:
// webpack.config.js
module.export = {
plugins:[
new Plugin(options),
]
}
事件流机制:
Webpack 就像工厂中的一条产品流水线。原材料经过 Loader 与 Plugin 的一道道处理,最后输出结果。
-
通过链式调用,按顺序串起一个个 Loader; -
通过事件流机制,让 Plugin 可以插入到整个生产过程中的每个步骤中;
Webpack 事件流编程范式的核心是基础类 Tapable,是一种 观察者模式 的实现事件的订阅与广播:
const { SyncHook } = require("tapable")
const hook = new SyncHook(['arg'])
// 订阅
hook.tap('event', (arg) => {
// 'event-hook'
console.log(arg)
})
// 广播
hook.call('event-hook')
Webpack
中两个最重要的类Compiler
与Compilation
便是继承于Tapable
,也拥有这样的事件流机制。
-
Compiler: 可以简单的理解为 Webpack 实例,它包含了当前 Webpack 中的所有配置信息,如 options, loaders, plugins 等信息,全局唯一,只在启动时完成初始化创建,随着生命周期逐一传递; -
Compilation
: 可以称为 编译实例。当监听到文件发生改变时,Webpack 会创建一个新的 Compilation 对象,开始一次新的编译。它包含了当前的输入资源,输出资源,变化的文件等,同时通过它提供的 api,可以监听每次编译过程中触发的事件钩子; -
区别: -
Compiler
全局唯一,且从启动生存到结束; -
Compilation
对应每次编译,每轮编译循环均会重新创建; -
常用 Plugin: -
UglifyJsPlugin: 压缩、混淆代码; -
CommonsChunkPlugin: 代码分割; -
ProvidePlugin: 自动加载模块; -
html-webpack-plugin: 加载 html 文件,并引入 css / js 文件; -
extract-text-webpack-plugin / mini-css-extract-plugin: 抽离样式,生成 css 文件; DefinePlugin: 定义全局变量; -
optimize-css-assets-webpack-plugin: CSS 代码去重; -
webpack-bundle-analyzer: 代码分析; -
compression-webpack-plugin: 使用 gzip 压缩 js 和 css; -
happypack: 使用多进程,加速代码构建; -
EnvironmentPlugin: 定义环境变量; -
调用插件 apply
函数传入compiler
对象 -
通过 compiler
对象监听事件
loader 和 plugin 有什么区别?
webapck 默认只能打包 JS 和 JOSN 模块,要打包其它模块,需要借助 loader,loader 就可以让模块中的内容转化成 webpack 或其它 laoder 可以识别的内容。
-
loader
就是模块转换化,或叫加载器。不同的文件,需要不同的loader
来处理。 -
plugin
是插件,可以参与到整个 webpack 打包的流程中,不同的插件,在合适的时机,可以做不同的事件。
webpack 中都有哪些插件,这些插件有什么作用?
-
html-webpack-plugin
自动创建一个 HTML 文件,并把打包好的 JS 插入到 HTML 文件中 -
clean-webpack-plugin
在每一次打包之前,删除整个输出文件夹下所有的内容 -
mini-css-extrcat-plugin
抽离 CSS 代码,放到一个单独的文件中 -
optimize-css-assets-plugin
压缩 css
实现一个编译结束退出命令的插件
apply (compiler) {
const afterEmit = (compilation, cb) => {
cb()
setTimeout(function () {
process.exit(0)
}, 1000)
}
compiler.plugin('after-emit', afterEmit)
}
}
module.exports = BuildEndPlugin
<script>
export default {
mounted () {
var isGithub = location.href.indexOf('FE-Interview-Questions')!==-1
var sId = isGithub ? '59154049' : '66575297'
var script = document.createElement("script");
script.type = "text/javascript"
script.charset="UTF-8"
script.src = `http://tajs.qq.com/stats?sId=${sId}`
document.body.appendChild(script);
}
}
</script>
原文始发于微信公众号(消失的程序员):前端自动化工程化–webpack 热更新原理、Loader、Plugin
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/250757.html