webpack热更新原理 http和https的默认端口号

我们大致了解了webpack HMR 原理 。可以看出以下几点核心思想:
1、监听文件变化
2、服务器与客户端通信
3、替换流程
4、降级操作
当然 。由于 webpack 本身有个很成熟的模块思想和生态 。因此整个架构设计会比我们实现的 HMR 复杂很多 。在模块热替换中 。是由 webpack 的全部流程出力来完成这一操作的 。而并没有局限于 webpack-dev-server 和 webpack 以及业务代码本身 。实际上 。起到更重要作用的是各类 loader 。它们需要使用 HMR API 来实现 Hot Reload 的逻辑 。决定什么时候注册模块、什么时候卸载模块;如何注册和卸载模块 。而 webpack 本身更像是一个调用方的角色 。不需要考虑具体的注册和反注册逻辑 。
HMR 的核心组织
经过了上面的分析 。我们基本上确认了一个思路 。也就是分析 webpack HMR 得出的结论 。但是由于我们只有 runtime 。所以实现 Hot Reload 变成了一个下图的简单流程:
1、Server 启动一个 HTTP 服务器 。并且注册和启动 WebSocket 服务 。用于届时与客户端通信
2、在启动 Static 服务器后返回页面前注入 HMR 的客户端代码 。业务方无需关心 HMR 的具体实现和添加对应的支持代码服务端监听磁盘文件的变更 。将文件变更通过 WebSocket 发送给客户端
3、客户端收到文件变更消息后进行对应的模块处理
4、(模块处理失败 。降级为 Live Reload)
live reload?
在实现 HMR 之前 。我们可以先实现一个简单的 Live Reload 来保证我们 1-3 步的实现没有异常 。
constKoa=require('koa')constWebSocket=require('ws')constchokidar=require('chokidar')constapp=newKoa()constfs=require('fs').promisesconstwss=newWebSocket.Server({port:8000})constdir='./static'constwatcher=chokidar.watch('./static',{ignored:/node_modules|.git|[/\]./})wss.on('connection',(ws)=>{watcher.on('add',path=>console.log(`File${path}added`)).on('change',path=>console.log(`File${path}hasbeenchanged`)).on('unlink',path=>console.log(`File${path}hasbeenmoved`)).on('all',async(event,path)=>{//SimpleLiveReloadws.send('reload')})ws.on('message',(message)=>{console.log('received:%s',message)})ws.send('HMRClientisReady')})constinjectedData=https://www.wangchuang8.com/``app.use(async(ctx,next)=>{letfile=ctx.pathif(ctx.path.endsWith('/')){file=ctx.path+'index.html'}letbodytry{body=awaitfs.readFile(dir+file,{encoding:'utf-8'})}catch(e){ctx.status=404returnnext()}if(file.endsWith('.html'))body=body.replace('',`${injectedData}`)if(file.endsWith('.css'))ctx.type='text/css'ctx.body=bodynext()})app.listen(3001)console.log('listenonport3001')
手机看代码不方便 。我把代码截图贴这里了

webpack热更新原理 http和https的默认端口号

文章插图

webpack热更新原理 http和https的默认端口号

文章插图
上述代码中 。简单的使用了 chokidar 这个文件监听库 。它极大的减轻了我们的工作量;而 WebSocket 和服务器的实现上暂不赘述 。之所以不直接使用 koa-static 的原因是因为我们需要对于 HTML 文件进行一些注入操作 。以上 Live Reload 的实现非常简单 。基本可以总结为一句话:得知文件变化后向客户端发送 reload 消息 。客户端收到消息执行页面刷新操作 。
实现了一个 Live Reload 之后 。接下来我们只需要变更注入的代码和发送到客户端的消息两个部分即可 。其实 Hot Reload 和 Live Reload 最大的区别也就是「最小模块替换」与「刷新页面」的区别 。因此其他部分都是不用变动的 。
替换 HTML 和 CSS 则是其中最简单的两项任务 。
HTML
通常来说 。我们要覆盖 HTML 中的内容 。除了刷新这一操作外 。还有一个就是 document.write() 。实际上我们也是通过这个函数来实现 HTML 的 Hot Reload 的:
//监听.on('all',async(event,path)=>{if(path.endsWith('.html')){body=awaitfs.readFile(path,{encoding:'utf-8'})constmessage=jsON.stringify({type:'html',content:body})ws.send(message)}})//注入letdata=https://www.wangchuang8.com/{}try{data=JSON.parse(event.data)}catch(e){//return}console.log(data)if(data.type==='html'){document.write(data.content);document.close();console.log('[HMR]updatedHTML');}
webpack热更新原理 http和https的默认端口号

文章插图

推荐阅读