摘要:背景前端項(xiàng)目開(kāi)發(fā)過(guò)程中熱更新的機(jī)制大家都知道,不知道你在開(kāi)發(fā)的時(shí)候是否做了這方面的配置。其實(shí)熱更新的原理并不復(fù)雜,或者說(shuō)很簡(jiǎn)單。服務(wù)器和瀏覽器規(guī)定好消息的規(guī)則,是刷新頁(yè)面還是更新。另外對(duì)模塊熱更新和原理有興趣的可以研究下,后面可能也會(huì)介紹。
背景
前端項(xiàng)目開(kāi)發(fā)過(guò)程中熱更新的機(jī)制大家都知道,不知道你在開(kāi)發(fā)的時(shí)候是否做了這方面的配置。
相信接觸最多的就是 webpack 的熱更新,文件保存后頁(yè)面自動(dòng)刷新,或者 css 自動(dòng)更新,頁(yè)面的樣式在不刷新頁(yè)面的情況下就會(huì)更新。
還有就是模塊熱替換。
熱更新機(jī)制很好玩,能提升不少開(kāi)發(fā)效率,但是只是處于會(huì)用的階段不是我們的目的,我們應(yīng)該適當(dāng)?shù)纳钊雽W(xué)習(xí)下,看看他背后的原理,一個(gè)是否思考過(guò),一個(gè)是否能自己實(shí)現(xiàn)。
熱更新原理咱們這里主要說(shuō)下怎樣自己實(shí)現(xiàn)一個(gè)熱更新,也就是文件更改了會(huì)自動(dòng)刷新頁(yè)面,可以同步 pc 和 移動(dòng)端,css 更改了可以不刷新頁(yè)面就應(yīng)用最新的 css。
其實(shí)熱更新的原理并不復(fù)雜,或者說(shuō)很簡(jiǎn)單。
咱們一步一步的分析下。
本文不是要告訴你一些 api如何使用,而是利用架構(gòu)的思維去分析和解決問(wèn)題。
【分析】
文件內(nèi)容變更了,瀏覽器是怎么知道的呢?
css 文件內(nèi)容變更了,沒(méi)有刷新頁(yè)面 怎么加載最新的內(nèi)容呢?
只要解決了上面兩個(gè)問(wèn)題,我們就算是完成了。因?yàn)槭O碌镁褪蔷幋a了,這都好說(shuō)。
【結(jié)果】
文件變更了,我怎樣通知瀏覽器?
瀏覽器和服務(wù)器保持著連接。 服務(wù)器有什么事兒直接通過(guò)當(dāng)前的鏈接告訴瀏覽器就可以了。
連接肯定是長(zhǎng)連接,不然怎么實(shí)時(shí)通信。
保持長(zhǎng)連接有哪些方法呢? 輪詢(xún)?eventSorce? 都不夠好。
有么有更好的方案呢?那就是 - websocket
瀏覽器和服務(wù)器先建立好鏈接,服務(wù)器就可以直接通知到客戶(hù)端了。這個(gè)時(shí)候無(wú)論是 pc 上還是手機(jī)上都可以隨時(shí)根據(jù)需要刷新或者加載資源。
css 更新,css 本身是可以通過(guò) dom 去操作的。瀏覽器只要知道是 css更新了,直接重新加載當(dāng)前的 css 文件就可以了。
架構(gòu)思維咱們?cè)谥匦罗坜圻@個(gè)架構(gòu)。
服務(wù)器和瀏覽器通過(guò) websocket 建立鏈接。
服務(wù)器和瀏覽器規(guī)定好消息的規(guī)則,是刷新頁(yè)面還是更新 css。
基本架構(gòu)有了,其他的就是編碼實(shí)現(xiàn)了。
服務(wù)端使用 node 創(chuàng)建一個(gè) ws 服務(wù)。
瀏覽器使用 websocket 創(chuàng)建一個(gè)鏈接和服務(wù)器進(jìn)行鏈接。
雙方通過(guò)對(duì)應(yīng)的 api 進(jìn)行數(shù)據(jù)的操作。
代碼實(shí)現(xiàn)本文只是講解下思路,并沒(méi)有實(shí)現(xiàn)文件的監(jiān)聽(tīng),文件監(jiān)聽(tīng)后面會(huì)介紹。咱暫時(shí)先確定好兩個(gè)消息規(guī)則:
瀏覽器收到 命令為:htmlFileChange ,此時(shí)瀏覽器刷新;
瀏覽器收到命令為:cssFileChange,此時(shí)不刷新頁(yè)面,自動(dòng)加載 css 文件;
具體代碼如下:
服務(wù)端://web-socket.js 創(chuàng)建 ws 服務(wù) var ws = require("nodejs-websocket");//需要安裝這個(gè)包 module.exports = function(){ return function () { console.log("重度前端提醒,開(kāi)始建立連接...") var sessions = [];//存放每一個(gè)鏈接對(duì)象 var server = ws.createServer(function (conn) { sessions.push(conn);//將新的鏈接對(duì)象存放在數(shù)組中 conn.on("text", function (str) { console.log("收到的信息為:" + str) sessions.forEach(item=>{ item.sendText(str) //所有客戶(hù)端都發(fā)送消息 }); }); conn.on("close", function (code, reason) { console.log("關(guān)閉連接") }); conn.on("error", function (code, reason) { console.log("異常關(guān)閉") }); }).listen(6152) console.log("WebSocket建立完畢") } }
//server.js http 服務(wù)代碼
let http = require("http"); let fs = require("fs"); let webSocket = require("./node/web-socket"); const BASEROOT = process.cwd();//獲得當(dāng)前的執(zhí)行路徑 //讀取 index.html內(nèi)容 let getPageHtml = function () { let data = fs.readFileSync(BASEROOT+"/html/index.html"); return data.toString(); } //讀取 index.css內(nèi)容 let getPageCss = function () { let data = fs.readFileSync(BASEROOT + "/html/index.css"); return data.toString(); } //node 端 開(kāi)啟 ws 服務(wù) webSocket()(); http.createServer(function (req, res) {//創(chuàng)建 http 服務(wù) let body = "",url = req.url; req.on("data", function (chunk) { body += chunk; }); req.on("end", function () { //路由簡(jiǎn)單處理 根據(jù)不同路徑輸出不同內(nèi)容給瀏覽器 if(url.indexOf("/index.css")>-1){ res.write(getPageCss()); }else{ res.write(getPageHtml()); } res.end(); }); }).listen(6151); console.log("重度前端提醒...... server start");頁(yè)面截圖 客戶(hù)端
//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); }); // 監(jiān)聽(tīng)服務(wù)器推送的消息 socket.addEventListener("message", function (event) { if (index > nick.length) { index = 0;//只是為了每次輸出不同的昵稱(chēng),沒(méi)實(shí)際意義 } var ele = document.createElement("div"); ele.innerHTML = nick[index] + ":" + event.data; if (event.data === "htmlFileChange") { //html 文件更新了 刷新當(dāng)前頁(yè)面 location.reload(); } if (event.data === "cssFileChange") { //css 文件更新了 刷新當(dāng)前頁(yè)面 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)); //創(chuàng)建新的 css 標(biāo)簽 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 內(nèi)容
input { outline: none; } #content { height: 400px; width: 400px; border: solid 1px #ccc; color: red; }
代碼倒是次要的。解決問(wèn)題的思路才重要。有了解決問(wèn)題的架構(gòu)思維,代碼實(shí)現(xiàn)都好說(shuō)。
寫(xiě)到這里咱們還能順便實(shí)現(xiàn)一個(gè)群聊。
本質(zhì)就是服務(wù)器和瀏覽器怎樣實(shí)時(shí)通信,解決了這個(gè)問(wèn)題,其他的都是小事兒。
這個(gè)技術(shù)實(shí)現(xiàn)還是比較簡(jiǎn)單的。
另外對(duì)模塊熱更新和 websocket 原理有興趣的可以研究下,后面可能也會(huì)介紹。
總結(jié)本文主要介紹
簡(jiǎn)易版熱更新的原理;
熱更新實(shí)現(xiàn)思路和代碼實(shí)現(xiàn);
架構(gòu)思維:簡(jiǎn)單的帶出架構(gòu)思維的作用;
希望本文對(duì)你有用。
原創(chuàng)不易、請(qǐng)多鼓勵(lì)
自家觀點(diǎn)、歡迎打臉
https://github.com/bigerfe/ho...
作者:微信公眾號(hào) - 重度前端 主筆:八門(mén)
歡迎關(guān)注 重度前端-每周5原創(chuàng)全棧干貨+每周三深度技術(shù)文章
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/101478.html
摘要:從事開(kāi)發(fā)的程序員,對(duì)于前后端分離模式多半不陌生,這也是目前主流的開(kāi)發(fā)模式,具體關(guān)于前后端分離的模式可以參看文章你不得不了解的前后端分離原理,在這里寫(xiě)者不進(jìn)行說(shuō)明。原理圖如下,前后端在一個(gè)進(jìn)程同一個(gè)端口中,通過(guò)熱替換更新的,而不是全量重啟。 從事 Web 開(kāi)發(fā)的程序員,對(duì)于前后端分離模式多半不陌生,這也是目前主流的 Web 開(kāi)發(fā)模式,具體關(guān)于前后端分離的模式可以參看文章《你不得不了解的前...
摘要:聯(lián)想到我在微信小程序上的開(kāi)發(fā)體驗(yàn),真心覺(jué)得如果有熱更新機(jī)制的話(huà),開(kāi)發(fā)效率要高很多。熱更新示例下面通過(guò)例子來(lái)進(jìn)一步解釋熱更新機(jī)制。 想必作為前端大佬的你,工作中應(yīng)該用過(guò) webpack,并且對(duì)熱更新的特性也有了解。如果沒(méi)有,當(dāng)然也沒(méi)關(guān)系。 下面我要講的,是我對(duì) Webpack 熱更新機(jī)制的一些認(rèn)識(shí)和理解,不足之處,歡迎指正。 首先: 熱更新是啥? 熱更新,是指 Hot Module Re...
摘要:如果你的項(xiàng)目中使用了的話(huà),你會(huì)很幸運(yùn),借助插件可以實(shí)現(xiàn)項(xiàng)目的熱更新。對(duì)模板更新的處理目前項(xiàng)目中使用的是的模板引擎。 showImg(https://segmentfault.com/img/bVrAa7);這個(gè)是組內(nèi)一位同學(xué)在平時(shí)開(kāi)發(fā)中,發(fā)現(xiàn)調(diào)試不便,為團(tuán)隊(duì)開(kāi)發(fā)的熱更新工具。很厲害,文章中的技術(shù)實(shí)現(xiàn)內(nèi)容也是我了解了他的具體實(shí)現(xiàn)思路后,整理出來(lái)的。 工具源碼EHU(esl-hot-upd...
閱讀 2731·2023-04-26 02:28
閱讀 2565·2021-09-27 13:36
閱讀 3134·2021-09-03 10:29
閱讀 2762·2021-08-26 14:14
閱讀 2111·2019-08-30 15:56
閱讀 842·2019-08-29 13:46
閱讀 2616·2019-08-29 13:15
閱讀 461·2019-08-29 11:29