webpack原理(1):Webpack热更新实现原理代码分析

科技资讯 投稿 6600 0 评论

webpack原理(1):Webpack热更新实现原理代码分析

服务单与客户端通信方式有:ajax 轮询,EventSource、websockt。

  • 整体页面刷新,不保留页面状态,就是简单粗暴,直接window.location.reload(。

  • 模块热替换,只需要局部刷新页面上发生变化的模块,同时可以保留当前的页面状态,比如复选框的选中状态、输入框的输入等。

模块热替换(Hot Module Replacement 或 HMR是 webpack 提供的最有用的功能之一。它允许在运行时更新各种模块,而无需进行完全刷新。

webpack基本概念复习

 

webpack中的module,chunk 和 bundle

  • module 就是一个js模块,就是被require或export的模块,例如 ES模块,commonjs模块,AMD模块

  • chunk 是 代码块,是进行依赖分析的时候,代码分割出来的代码块,包括一个或多个module,是被分组了的module集合,code spliting之后的就是chunk

  • bundle 是 文件,最终打包出来的文件,通常一个bundle对应一个chunk

webpack中loader和plugin在作用

  • loader是文件转换器,将webpack不能处理的模块转换为webpack能处理的模块,就是js模块

  • plugin是功能扩展,干预webpack的打包过程,修改编译结果或打包结果

Webpack插件机制之Tapable

Webpack本质上是一种事件流的机制,它的工作流程就是将各个插件串联起来,而实现这一切的核心就是Tapable。tapable的核心思路有点类似于node.js中的events,最基本的发布/订阅模式。回顾grunt gulp  任务队列,省去一般的操作。

webpack-dev-server热更新分析

内置了webpack-dev-middleware和express服务器,利用webpack-dev-middleware提供文件的监听和编译,利用express提供http服务,底层利用websocket代替EventSource实现了webpack-hot-middleware提供的客户端和服务器之间的通信机制。

webpack-dev-server代码分析

// webpack.config.server.js const webpack = require('webpack'; const WebpackDevServer = require('webpack-dev-server'; const config = require('./webpack.config'; config.plugins.push(     new webpack.HotModuleReplacementPlugin(,//热替换     new webpack.NoEmitOnErrorsPlugin(,//去除系统抛出的错误消息 ; // node_modules/webpack-dev-server/lib/Server.js // 绑定监听事件 setupHooks( {     const {done} = compiler.hooks;     // 监听webpack的done钩子,tapable提供的监听方法     done.tap('webpack-dev-server', (stats => {         this._sendStats(this.sockets, this.getStats(stats;         this._stats = stats;     }; }; // 通过websoket给客户端发消息 _sendStats( {     this.sockWrite(sockets, 'hash', stats.hash;     this.sockWrite(sockets, 'ok'; }

每次修改代码保存后(gulp grunt 通过watch 监听),控制台都会出现 Compiling…字样,触发新的编译中...可以在控制台中观察到:

  • 新的json文件: a93fd735d02d98633356.hot-update.json

每次修改代码,就会触发编译。说明我们还需要监听本地代码的变化,主要是通过setupDevMiddleware方法实现的。这个方法主要执行了webpack-dev-middleware库。

webpack-dev-middleware

webpack-dev-middleware 是一个 express 中间件,核心实现两个功能:

  • 第二是通过watch监听文件的变化,动态编译。

// node_modules/webpack-dev-middleware/index.js
compiler.watch(options.watchOptions, (err => {
    if (err { /*错误处理*/ }
};
// 通过“memory-fs”库将打包后的文件写入内存
setFs(context, compiler;
    • 调用了compiler.watch方法,在第 1 步中也提到过,compiler的强大。这个方法主要就做了 2 件事:

      • 其次编译结束后,开启对本地文件的监听,当文件发生变化,重新编译,编译完成之后继续监听。

  • 执行setFs方法,这个方法主要目的就是将编译后的文件打包到内存。这就是为什么在开发的过程中,你会发现dist目录没有打包后的代码,因为都在内存中。原因就在于访问内存中的代码比访问文件系统中的文件更快,而且也减少了代码写入文件的开销,这一切都归功于memory-fs。

webpack --watch 

webpack第一次编译项目,并将结果存储在内存文件系统,相比较磁盘文件读写方式内存文件管理速度更快,内存webpack服务器通知浏览器加载资源,浏览器获取的静态资源除了JS code内容之外,还有一部分通过 webpack-dev-server 注入的的 HMR runtime代码,作为浏览器和webpack服务器通信的客户端( webpack-hot-middleware 提供类似的功能)。

  • webpack监听到文件变化对文件重新编译打包,每次编译生成唯一的hash值,根据变化的内容生成两个补丁文件:

    • chunk js(hash.hot-update.js)模块。

  • 浏览器接受到最新的 hotCurrentHash,触发 hotDownloadManifest 函数,获取manifest json 文件。

  • HMR runtime 调用window["webpackHotUpdate"] 方法,调用hotAddUpdateChunk

服务端流程

  1. 使用express框架启动本地server,让浏览器可以请求本地的静态资源。

  2. 浏览器接收到热更新的通知,当监听到一次webpack编译结束,_s

编程笔记 » webpack原理(1):Webpack热更新实现原理代码分析

赞同 (33) or 分享 (0)
游客 发表我的评论   换个身份
取消评论

表情
(0)个小伙伴在吐槽