晒一晒我的简易版热更新

简介: 前端项目开发过程中热更新的机制大家都知道,不知道你在开发的时候是否做了这方面的配置。 相信接触最多的就是 webpack 的热更新,文件保存后页面自动刷新,或者 css 自动更新,页面的样式在不刷新页面的情况下就会更新。 还有就是模块热替换。 热更新机制很好玩,能提升不少开发效率,但是只是处于会用的阶段不是我们的目的,我们应该适当的深入学习下,看看他背后的原理,一个是否思考过,一个是否能自己实现。

背景


前端项目开发过程中热更新的机制大家都知道,不知道你在开发的时候是否做了这方面的配置。

相信接触最多的就是 webpack 的热更新,文件保存后页面自动刷新,或者 css 自动更新,页面的样式在不刷新页面的情况下就会更新。

还有就是模块热替换。

热更新机制很好玩,能提升不少开发效率,但是只是处于会用的阶段不是我们的目的,我们应该适当的深入学习下,看看他背后的原理,一个是否思考过,一个是否能自己实现。



热更新原理

咱们这里主要说下怎样自己实现一个热更新,也就是文件更改了会自动刷新页面,可以同步 pc 和 移动端,css 更改了可以不刷新页面就应用最新的 css。


其实热更新的原理并不复杂,或者说很简单。

咱们一步一步的分析下。

本文不是要告诉你一些 api如何使用,而是利用架构的思维去分析和解决问题。

【分析】

1. 文件内容变更了,浏览器是怎么知道的呢?

2. css 文件内容变更了,没有刷新页面 怎么加载最新的内容呢?

只要解决了上面两个问题,我们就算是完成了。因为剩下得就是编码了,这都好说。


【结果】

文件变更了,我怎样通知浏览器?

1. 浏览器和服务器保持着连接。 服务器有什么事儿直接通过当前的链接告诉浏览器就可以了。

连接肯定是长连接,不然怎么实时通信。

保持长连接有哪些方法呢? 轮询?eventSorce? 都不够好。

有么有更好的方案呢?那就是 - websocket

浏览器和服务器先建立好链接,服务器就可以直接通知到客户端了。这个时候无论是 pc 上还是手机上都可以随时根据需要刷新或者加载资源。


2. css 更新,css 本身是可以通过 dom 去操作的。浏览器只要知道是 css更新了,直接重新加载当前的 css 文件就可以了。


架构思维

咱们在重新捋捋这个架构。

1. 服务器和浏览器通过 websocket 建立链接。

2. 服务器和浏览器规定好消息的规则,是刷新页面还是更新 css。

基本架构有了,其他的就是编码实现了。


服务端使用 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');


页面截图

dedde9cce55d6abe4d9b9ebf90c7b04d_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.jpg

a3566c3671f1aa44c4a3c72dd1384bef_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.jpg

客户端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 原理有兴趣的可以研究下,后面可能也会介绍。


总结


本文主要介绍

简易版热更新的原理;

热更新实现思路和代码实现;

架构思维:简单的带出架构思维的作用;

目录
相关文章
|
7月前
|
缓存 JavaScript 前端开发
从零开始的抢购脚本开发-油猴开发教程(多快好省)
从零开始的抢购脚本开发-油猴开发教程(多快好省)
155 0
|
6月前
|
JavaScript Java 测试技术
基于SpringBoot+Vue+uniapp的研学自习室选座与门禁系统的详细设计和实现(源码+lw+部署文档+讲解等)
基于SpringBoot+Vue+uniapp的研学自习室选座与门禁系统的详细设计和实现(源码+lw+部署文档+讲解等)
|
6月前
|
PHP
PHP开发的爱情盲盒交友系统网站源码 独立后台
PHP开发的爱情盲盒交友系统网站源码 独立后台
53 4
|
7月前
|
数据可视化 小程序 前端开发
【iVX】十五分钟制作一款小游戏,iVX真有怎么神?
【iVX】十五分钟制作一款小游戏,iVX真有怎么神?
200 0
|
自然语言处理 前端开发 JavaScript
重学前端 3 # 前端知识框架图
重学前端 3 # 前端知识框架图
155 0
重学前端 3 # 前端知识框架图
|
前端开发 网络协议 jenkins
三分钟,我让搞后端的学弟爱上了Eolink
突然某一天,一个特别能卷的学弟向我请教接口工具……
三分钟,我让搞后端的学弟爱上了Eolink
|
前端开发 网络协议 JavaScript
我最近在用的一款神器,功能多到炸
今天就给大家分享我最近开发时在用的一款神器,API管理和自动化测试工具Eolink。想要摸鱼,就要提高效率,想要提高效率,就用这款神器!
216 0
我最近在用的一款神器,功能多到炸
|
程序员
讲真,这两款idea插件,能治愈你英语不好的病(2)
讲真,这两款idea插件,能治愈你英语不好的病
410 1
讲真,这两款idea插件,能治愈你英语不好的病(2)
|
缓存 前端开发 JavaScript
前端利器躬行记(7)——自制脚手架
  在学习了Webpack基础后,查看别人写好的脚手架总是会一头雾水,后面就上网查各种资料,一边参考一边修改,整出了一套简易的脚手架(已上传至GiuHub和npm上),借鉴了Create React App(CRA)的目录结构(如下所示),并做成了命令行工具(已上传至GiuHub和npm上)。
前端利器躬行记(7)——自制脚手架
|
前端开发 UED
【青训营】- 前端只是切图仔?来学学给开发人看的UI设计(上)
于开发人来说,不单单要会写代码,有良好的用户体验思想也是非常重要的。毕竟,开发完的内容是要给用户来使用的,而不是自己随心所欲觉得哪里想添加个内容就哪里添加。 因此呢,在下面的这篇文章中,将学习给开发人看的 UI 设计。一起来了解吧~
【青训营】- 前端只是切图仔?来学学给开发人看的UI设计(上)