美文网首页让前端飞Web 前端开发
前端开发 - 热更新原理

前端开发 - 热更新原理

作者: alanwhy | 来源:发表于2019-04-07 22:08 被阅读5次

    提出问题

    • 文件内容变更了,浏览器是怎么知道的呢?
    • css 文件内容变更了,没有刷新页面 怎么加载最新的内容呢?

    结论

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

    实现思维

    • 服务器和浏览器通过 websocket 建立链接。
    • 服务器和浏览器规定好消息的规则,是刷新页面还是更新 css。

    1.服务端使用 node 创建一个 websocket 服务。
    2.浏览器使用 websocket 创建一个链接和服务器进行链接。
    3.双方通过对应的 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 = '';
        }
    

    代码地址:https://github.com/bigerfe/hotUpdate-demo

    原文链接: 简单聊聊前端开发中的热更新原理

    相关文章

      网友评论

        本文标题:前端开发 - 热更新原理

        本文链接:https://www.haomeiwen.com/subject/zpveiqtx.html