前端项目开发过程当中热更新的机制你们都知道,不知道你在开发的时候是否作了这方面的配置。javascript
相信接触最多的就是 webpack 的热更新,文件保存后页面自动刷新,或者 css 自动更新,页面的样式在不刷新页面的状况下就会更新。css
还有就是模块热替换。html
热更新机制很好玩,能提高很多开发效率,可是只是处于会用的阶段不是咱们的目的,咱们应该适当的深刻学习下,看看他背后的原理,一个是否思考过,一个是否能本身实现。前端
我们这里主要说下怎样本身实现一个热更新,也就是文件更改了会自动刷新页面,能够同步 pc 和 移动端,css 更改了能够不刷新页面就应用最新的 css。java
其实热更新的原理并不复杂,或者说很简单。node
我们一步一步的分析下。webpack
本文不是要告诉你一些 api如何使用,而是利用架构的思惟去分析和解决问题。git
【分析】github
只要解决了上面两个问题,咱们就算是完成了。由于剩下得就是编码了,这都好说。web
【结果】
文件变动了,我怎样通知浏览器?
链接确定是长链接,否则怎么实时通讯。
保持长链接有哪些方法呢? 轮询?eventSorce? 都不够好。
有么有更好的方案呢?那就是 - websocket
浏览器和服务器先创建好连接,服务器就能够直接通知到客户端了。这个时候不管是 pc 上仍是手机上均可以随时根据须要刷新或者加载资源。
我们在从新捋捋这个架构。
基本架构有了,其余的就是编码实现了。
服务端使用 node 建立一个 ws 服务。
浏览器使用 websocket 建立一个连接和服务器进行连接。
双方经过对应的 api 进行数据的操做。
本文只是讲解下思路,并无实现文件的监听,文件监听后面会介绍。咱暂时先肯定好两个消息规则:
浏览器收到 命令为:htmlFileChange ,此时浏览器刷新;
浏览器收到命令为:cssFileChange,此时不刷新页面,自动加载 css 文件;
具体代码以下:
//web-socket.js 建立 ws 服务 var ws = require("nodejs-websocket");//须要安装这个包 module.exports = function(){ return function () { console.log("重度前端提醒,开始创建链接...") var sessions = [];//存放每个连接对象 var server = ws.createServer(function (conn) { sessions.push(conn);//将新的连接对象存放在数组中 conn.on("text", function (str) { console.log("收到的信息为:" + str) sessions.forEach(item=>{ item.sendText(str) //全部客户端都发送消息 }); }); conn.on("close", function (code, reason) { console.log("关闭链接") }); conn.on("error", function (code, reason) { console.log("异常关闭") }); }).listen(6152) console.log("WebSocket创建完毕") } }
//server.js http 服务代码
let http = require('http'); let fs = require('fs'); let webSocket = require('./node/web-socket'); const BASEROOT = process.cwd();//得到当前的执行路径 //读取 index.html内容 let getPageHtml = function () { let data = fs.readFileSync(BASEROOT+'/html/index.html'); return data.toString(); } //读取 index.css内容 let getPageCss = function () { let data = fs.readFileSync(BASEROOT + '/html/index.css'); return data.toString(); } //node 端 开启 ws 服务 webSocket()(); http.createServer(function (req, res) {//建立 http 服务 let body = '',url = req.url; req.on('data', function (chunk) { body += chunk; }); req.on('end', function () { //路由简单处理 根据不一样路径输出不一样内容给浏览器 if(url.indexOf('/index.css')>-1){ res.write(getPageCss()); }else{ res.write(getPageHtml()); } res.end(); }); }).listen(6151); console.log('重度前端提醒...... server start');
//index.html 布局代码省略 const nick = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'aa', 'cc']; let index = 0; // Create WebSocket connection. const socket = new WebSocket('ws://10.70.69.191:6152'); // Connection opened socket.addEventListener('open', function (event) { socket.send(navigator.userAgent); }); // 监听服务器推送的消息 socket.addEventListener('message', function (event) { if (index > nick.length) { index = 0;//只是为了每次输出不一样的昵称,没实际意义 } var ele = document.createElement('div'); ele.innerHTML = nick[index] + ':' + event.data; if (event.data === 'htmlFileChange') { //html 文件更新了 刷新当前页面 location.reload(); } if (event.data === 'cssFileChange') { //css 文件更新了 刷新当前页面 reloadCss(); } document.getElementById('content').append(ele); index += 1; }); //从新加载 css function reloadCss() { var cssUrl = [], links = document.getElementsByTagName('link'), len = links.length; for (var i = 0; i < len; i++) { var url = links[i].href; document.getElementsByTagName('head')[0].appendChild(getLinkNode(url)); //建立新的 css 标签 document.getElementsByTagName('head')[0].removeChild(links[i]); //移除原有 css } console.log(document.getElementsByTagName('head')[0]) function getLinkNode(cssUrl) { var node = document.createElement('link'); node.href = cssUrl; node.rel = 'stylesheet'; return node; } } document.getElementById('btn1').onclick = function () { socket.send(document.getElementById('message').value); document.getElementById('message').value = ''; }
index.css 内容
input { outline: none; } #content { height: 400px; width: 400px; border: solid 1px #ccc; color: red; }
代码却是次要的。解决问题的思路才重要。有了解决问题的架构思惟,代码实现都好说。
写到这里我们还能顺便实现一个群聊。
本质就是服务器和浏览器怎样实时通讯,解决了这个问题,其余的都是小事儿。
这个技术实现仍是比较简单的。
另外对模块热更新和 websocket 原理有兴趣的能够研究下,后面可能也会介绍。
本文主要介绍
简易版热更新的原理;
热更新实现思路和代码实现;
架构思惟:简单的带出架构思惟的做用;
但愿本文对你有用。
原创不易、请多鼓励
自家观点、欢迎打脸
https://github.com/bigerfe/ho...
做者:微信公众号 - 重度前端 主笔:八门欢迎关注 重度前端-每周5原创全栈干货+每周三深度技术文章