前端項目開發過程當中熱更新的機制你們都知道,不知道你在開發的時候是否作了這方面的配置。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原創全棧乾貨+每週三深度技術文章