hot load那点事

一、react项目搭建---使用creat-react-creat-react-app脚手架出现的问题 今天开始学习react框架的使用,初探creat-react-app搭建项目,适合新手入门级使用,具体搭建步骤如下: 第一步:安装creat-react-app 建议使用国内淘宝镜像源cnpm进行安装,速度较快,还有要全局安装呀 cnpm icreat-react-app -g 第二步:安装yarn(在这里踩坑一个小时,不知所云的环境bug) cnpm i yarn -g 这个鬼相当... 阅读详情

前言

热加载,最初接触的时候是使用create-react-app的时候,创建一个项目出来,修改一点代码,页面自动刷新了,贫道当时就感叹,这是造福开发者的事情。
再后来编写静态页面的时候使用 VS Code 的插件 Liver Server, 也是及时刷新,平僧幸福感慢慢,什么单不单身,狗不狗的,都不重要了。

Live Server

有一天喝酒回家后,睡的特别好,醒来后突然脑袋一晃,出现一个念头,世界那么大。我想看看 hot load 是咋实现的。

当然这里有两点应该是确认

  1. 肯定是监听文件变化
  2. WebSocket 监听服务端变化的通知,刷新文件

于是打开Live Server 找到源码ritwickdey/vscode-live-server,再通过 lib/live-server/index.js 的标注

#!/usr/bin/env node
 "use strict";

/*
	Taken from https://github.com/tapio/live-server for modification
*/ 

找到live-server,就开始了奇妙的探索之旅。

按照正常流程打开 index.js, 先略去非核心代码:

 chokidar = require('chokidar');

    ......

    // Setup file watcher
	LiveServer.watcher = chokidar.watch(watchPaths, {
		ignored: ignored,
		ignoreInitial: true
	});
	function handleChange(changePath) {
		var cssChange = path.extname(changePath) === ".css" && !noCssInject;
		if (LiveServer.logLevel >= 1) {
			if (cssChange)
				console.log("CSS change detected".magenta, changePath);
			else console.log("Change detected".cyan, changePath);
		}
		clients.forEach(function(ws) {
			if (ws)
				ws.send(cssChange ? 'refreshcss' : 'reload');
		});
	}
	LiveServer.watcher
		.on("change", handleChange)
		.on("add", handleChange)
		.on("unlink", handleChange)
		.on("addDir", handleChange)
		.on("unlinkDir", handleChange)
		.on("ready", function () {
			if (LiveServer.logLevel >= 1)
				console.log("Ready for changes".cyan);
		})
		.on("error", function (err) {
			console.log("ERROR:".red, err);
		});

	return server;
}; 

从上可以得知,通过 chokidar 监听文件或者目录,当 change|add|addDir 等等时调用 handleChange。
handleChange 判断了一下变更的文件是不是 css,然后通过 socket 发送不通的事件。

那么问题来了, 如果客服端要能接受事件,必然要创建 WebSocket 连接。当然有人说,可以轮询或者 SSE 等这种嘛。我就不这么认为。

再看一段代码

 es = require("event-stream")

    var INJECTED_CODE = fs.readFileSync(path.join(__dirname, "injected.html"), "utf8");

......

		function inject(stream) {
			if (injectTag) {
				// We need to modify the length given to browser
				var len = INJECTED_CODE.length + res.getHeader('Content-Length');
				res.setHeader('Content-Length', len);
				var originalPipe = stream.pipe;
				stream.pipe = function(resp) {
					originalPipe.call(stream, es.replace(new RegExp(injectTag, "i"), INJECTED_CODE + injectTag)).pipe(resp);
				};
			}
		}

		send(req, reqpath, { root: root })
			.on('error', error)
			.on('directory', directory)
			.on('file', file)
			.on('stream', inject)
			.pipe(res);
	}; 

可以看到,如果需要注入,就会注入代码, 这里是直接更新了 stream。
插曲, 这个 es 就是那个搞事情的 event-stream, 哈哈。

我们再看看 INJECTED_CODE 的内容

<!-- Code injected by live-server -->
<script type="text/javascript"> // <![CDATA[  <-- For SVG support
    if ("WebSocket" in window) {
        (function() {
            function refreshCSS() {
                var sheets = [].slice.call(
                    document.getElementsByTagName("link")
                );
                var head = document.getElementsByTagName("head")[0];
                for (var i = 0; i < sheets.length; ++i) {
                    var elem = sheets[i];
                    head.removeChild(elem);
                    var rel = elem.rel;
                    if (
                        (elem.href && typeof rel != "string") ||
                        rel.length == 0 ||
                        rel.toLowerCase() == "stylesheet"
                    ) {
                        var url = elem.href.replace(
                            /(&|\?)_cacheOverride=\d+/,
                            ""
                        );
                        elem.href =
                            url +
                            (url.indexOf("?") >= 0 ? "&" : "?") +
                            "_cacheOverride=" +
                            new Date().valueOf();
                    }
                    head.appendChild(elem);
                }
            }
            var protocol =
                window.location.protocol === "http:" ? "ws://" : "wss://";
            var address =
                protocol +
                window.location.host +
                window.location.pathname +
                "/ws";
            var socket = new WebSocket(address);
            socket.onmessage = function(msg) {
                if (msg.data == "reload") window.location.reload();
                else if (msg.data == "refreshcss") refreshCSS();
            };
            console.log("Live reload enabled.");
        })();
    }
    // ]]> </script> 

简单的来讲,如果是 refreshcss 就先删除原来的 css 标签 link, 然后插入新的,并更新 _cacheOverride 的值, 强制刷新。
否则就是 reload 整个页面。

chokidar

到达这里,基本的东西就完了。 我们要好奇心多一点。我们再多看看chokidar

同理,先看 index.js
这个add方法就是添加监听的方法。

var NodeFsHandler = require('./lib/nodefs-handler');
var FsEventsHandler = require('./lib/fsevents-handler');

......

FSWatcher.prototype.add = function(paths, _origAdd, _internal) {

    ......

  if (this.options.useFsEvents && FsEventsHandler.canUse()) {
    if (!this._readyCount) this._readyCount = paths.length;
    if (this.options.persistent) this._readyCount *= 2;
    paths.forEach(this._addToFsEvents, this);
  } else {
    if (!this._readyCount) this._readyCount = 0;
    this._readyCount += paths.length;
    asyncEach(paths, function(path, next) {
      this._addToNodeFs(path, !_internal, 0, 0, _origAdd, function(err, res) {
        if (res) this._emitReady();
        next(err, res);
      }.bind(this));
    }.bind(this), function(error, results) {
      results.forEach(function(item) {
        if (!item || this.closed) return;
        this.add(sysPath.dirname(item), sysPath.basename(_origAdd || item));
      }, this);
    }.bind(this));
  }

  return this;
}; 

可以看到这里有两种handler,NodeFsHandler和FsEventsHandler。 还没没有得到是咋监听的,那么继续go on, 先看看NodeFsHandler._addToNodeFs。
打开chokidar/lib/nodefs-handler.js
_addToNodeFs ==> _handleFile ==> _watchWithNodeFs ==> setFsWatchListener ==> createFsWatchInstance

var fs = require('fs');

......

function createFsWatchInstance(path, options, listener, errHandler, emitRaw) {
  var handleEvent = function(rawEvent, evPath) {
    listener(path);
    emitRaw(rawEvent, evPath, {watchedPath: path});

    // emit based on events occurring for files from a directory's watcher in
    // case the file's watcher misses it (and rely on throttling to de-dupe)
    if (evPath && path !== evPath) {
      fsWatchBroadcast(
        sysPath.resolve(path, evPath), 'listeners', sysPath.join(path, evPath)
      );
    }
  };
  try {
    return fs.watch(path, options, handleEvent);
  } catch (error) {
    errHandler(error);
  }
} 

调用的就是fs模块的watch。 呵呵,感觉自己读书少,还是得多看文档。

我们再看看FsEventsHandler
_addToFsEvents >_watchWithFsEvents> createFSEventsInstance==>setFSEventsListener

 try { fsevents = require('fsevents'); } catch (error) {
  if (process.env.CHOKIDAR_PRINT_FSEVENTS_REQUIRE_ERROR) console.error(error)
}

// Returns new fsevents instance
function createFSEventsInstance(path, callback) {
  return (new fsevents(path)).on('fsevent', callback).start();
} 

那我们再接着看看fsevents

/* jshint node:true */
'use strict';

if (process.platform !== 'darwin') {
  throw new Error(`Module 'fsevents' is not compatible with platform '${process.platform}'`);
}

const { stat } = require('fs');
const Native = require('./fsevents.node');
const { EventEmitter } = require('events');

const native = new WeakMap();
class FSEvents {
  constructor(path, handler) {
    if ('string' !== typeof path) throw new TypeError('path must be a string');
    if ('function' !== typeof handler) throw new TypeError('function must be a function');
    Object.defineProperties(this, {
      path: { value: path },
      handler: { value: handler }
    });
  }
  start() {
    if (native.has(this)) return;
    const instance = Native.start(this.path, this.handler);
    native.set(this, instance);
    return this;
  } 
  • 平台只支持darwin,这是嘛呢,我问node开发,告诉我大致是Mac OS吧,那我就相信吧。
  • require(‘./fsevents.node’) 引用的是c++扩展
  • Native.start(this.path, this.handler) 就是监听,哦哦,原来是这样。

最后我们打开 webpack-dev-server 的/lib/Server.js 文件。

 const watcher = chokidar.watch(watchPath, options);

  watcher.on('change', () => {
    this.sockWrite(this.sockets, 'content-changed');
  }); 

也是这个chokidar, 那么我感觉我能做好多事情了。
亲,你做一个修改后直接发布的应用吧,好歹,好歹。

当然这里,只是弄明白监听和通知的大概。
等有时间,好好研究一下webpack-dev-server.

写在最后

不忘初衷,有所得,而不为所累,如果你觉得不错,你的一赞一评就是我前行的最大动力。

数据库系统实现(数据LOAD) 配置的导入,文件路径,任务数量(特别是有多少HASH INDEX的任务,数据定位的变化,目前的设计不支持动态的变化,会导致数据的迁移,如果设计上增加这样的功能,如何去实现?),数据结构的配置,空间大小的分配(NET PAGEBUFFER, HOT HASHMAP BUFFER, HOT HASH INDEX BUFFER, HOT DATACACHE BUFFER, TREE BUFFER); TREENODE的数量由LEVEL和BUFFERNODE的数据来定。 HOTKEY数... 阅读详情

相关推荐

分类变量编码实战指南:One-Hot、Target Encoding与业务语义对齐

分类变量编码是机器学习特征工程中的基础但关键环节,其本质是在信息保留、模型兼容性与计算效率之间做权衡。从统计原理看,One-Hot编码消除序数干扰却引发维度灾难,Target Encoding利用目标均值建模类别价值但需防范数据泄露与小样本偏差;技术价值体现在避免特征重要性失真、提升线上稳定性及支撑可解释性分析。典型应用场景包括电商类目建模、风控用户分群、推荐系统标签处理等。本文聚焦真实项目中高频踩坑点,深入解析One-Hot精细化控制、Target Encoding工业级平滑与验证机制,并强调业务语义前置

anjueci1221的博客 353

truffle serve 发生异常解决办法

安装步骤前几步都没有问题mkdir demo001 # Create a folder for your new dapp cd demo001 # Move into that folder truffle init # Initialize a default truffle project in that folder truffle migrate # Build, compile, & d

周壹的专栏 7417

【cordova】cordova热更新插件的问题(cordova-hot-code-push)

现在估计没多少用cordova的公司了吧,然而迫于公司老总的要求,非要让用H5(明明不懂android,非要干涉技术,小领导们也是敢怒不敢言,唉,越说越气),在这儿随便记录一下吧,如果恰巧有谁也用这个,并且对你有所帮助,不胜荣幸。cordova热更新用的是一个叫cordova-hot-code-push的插件(github地址: https://github.com/nordnet/cordova-

Z_4545287的博客 3326

[有趣] VS Code -- Live Server的一小段代码注入

有趣的VS Code插件 -- Live Server的一小段代码注入

o__o__o__o的博客 5810

TensorRT-LLM环境配置避坑指南:从安装到实战

本文是一份详尽的TensorRT-LLM环境配置避坑指南。文章重点解析了从Python、CUDA、PyTorch版本选择,到解决mpi4py安装这一核心难题的完整流程,并提供了经过验证的稳定版本组合与实战排错方案,帮助开发者高效部署大语言模型推理优化环境。

a0b1c2d3的专栏 985

赛灵思Xilinx 7系列FPGA硬件设计知识总结

本文讲述了赛灵思7系列FPGA硬件设计的关键点,为使用该系列FPGA提供硬件设计参考。

csdn_dsw的博客 3621

vscode 引入live server报错

错误: 解决: 1.右击插件 2.在setting里选择Root,点下面的edit 3.填写相对目录(也可以理解成是根目录),相对于你要打开页面的项目路径 4.验证 填写只到端口号的路径,查看展示的文件信息里是否包含了你所需要的所有文件。若是包括,就ok ...

lycc_lic的博客 1267

RK3588-NANOPC-T6移植ubuntu+xenomai内核

更具网址下载相应的内核。导入到开发板并执行内核。

qq_42007446的博客 573

iOS 26 beta1 重新禁止 JIT 执行,Flutter 下的 iOS 真机 hot load 暂时无法使用

在之前的我们聊过 iOS 18.4 beta mprotect failed: Permission denied 的问题,在 iOS 18.4 beta1 的时候, debug 运行会有的相关错误提示,问题其实就是 Dart VM 在初始化时,对内核文件「解释运行(JIT)」时出现权限不足的问题。只影响真机调试的 hot load。而这个问题后来在 iOS 18.4 beta2 又可以正常使用了,原因是因为。

恋猫de小郭的博客 2391

Linux 隐藏进程

这种方式属于DKoM(Direct Kernel Object Manipulation)攻击方式了,即直接内核对象操作技术。关于第一种hook方式可以参考上一篇文章。最后推荐一个rootkit工具。

chi's blog 2051

基于IMU的纯惯性导航轨迹绘制实践与优化

本文深入探讨了基于IMU的纯惯性导航轨迹绘制实践。通过修改开源组合导航算法KF-GINS,屏蔽GPS更新并简化地球参数,实现了仅依赖IMU数据的轨迹解算。文章详细介绍了代码改造、轨迹可视化方法,并分析了误差累积的根本原因,为深入理解惯性导航原理与传感器融合的必要性提供了宝贵的实践经验。

ff678的博客 395

hot-lib-reloader-rs宏系统详解:hot_module与hot_functions_from_file!的终极指南

想要在Rust开发中获得即时反馈,避免频繁重启应用吗?🎯 **hot-lib-reloader-rs** 正是你需要的终极热重载解决方案!这个强大的开发工具让你在运行时重新加载Rust代码,实现真正的"实时编程"体验。通过巧妙结合`#[hot_module]`属性宏和`hot_functions_from_file!`宏,它为你打开了Rust热重载的神秘大门。 ## 🔥 什么是hot-lib

gitblog_00776的博客 401

嵌入式存储入门:Emmc控制器与设备工作原理全解析(附Synopsys/Arasan架构图)

本文深入解析了嵌入式系统中Emmc控制器与设备的工作原理,重点剖析了其作为CPU与存储设备桥梁的核心架构。通过对比Synopsys和Arasan两家主流IP厂商的控制器设计,详细阐述了DMA引擎与FIFO缓冲模块如何协同工作以提升数据传输效率,并提供了从硬件PCB布局到驱动调试的实战指南,帮助硬件工程师与开发者优化系统性能。

weixin_29248653的博客 146

深入解析Aceso核心原理:从Instant Run Hot Swap到Android热修复的完整实现

Aceso作为一款专注于Android平台的热修复库,能够帮助开发者在无需重新发布应用的情况下快速修复线上bug,极大提升应用的稳定性和用户体验。本文将带你深入了解Aceso的核心原理,从Instant Run Hot Swap技术到Android热修复的完整实现过程。 ## Aceso热修复的核心功能与优势 Aceso热修复库为Android应用提供了强大的动态修复能力,其核心功能在于能够在

gitblog_00197的博客 712

从理论到代码:手把手教你用Matlab复现MMC的HSS阻抗模型(附避坑指南)

本文详细介绍了如何使用Matlab复现MMC的HSS阻抗模型,涵盖谐波状态空间(HSS)理论、代码实现步骤及常见问题解决方案。通过谐波线性化和序阻抗建模技术,帮助工程师准确分析MMC的阻抗特性,并提供避坑指南以解决矩阵维度错误、收敛性问题和频域转换陷阱等难点。

weixin_42561040的博客 357

基于rms包的限制性立方样条回归(RCS)R代码实现

RCS

2301_79584199的博客 2万+

FNF2Hot技术解析:从游戏引擎整合到高性能Mod开发框架

游戏引擎是现代游戏开发的核心技术框架,它通过整合图形渲染、物理模拟、音频处理等底层系统,为开发者提供高效的创作工具。其工作原理在于将硬件资源抽象为统一的API接口,并通过脚本层实现游戏逻辑的动态控制,从而提升开发效率与跨平台兼容性。在技术价值层面,引擎架构的优化直接影响游戏性能表现与内容扩展性,尤其在独立游戏和模组开发领域,灵活的框架设计能极大激发社区创作活力。当前,随着开源引擎生态的成熟,基于现有游戏进行引擎移植和架构重构已成为热门实践方向,例如在音乐节奏游戏社区中,通过整合Raylib、Love2D等轻

weixin_34252686的博客 1195

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

torch保存模型参数、one-hot标签、读取weights等记录-20200415

在pytorch save: torch.save(model.state_dict(), PATH) 在保存模型进行推理时,只需要保存训练过的模型的学习参数即可。一个常见的PyTorch约定是使用.pt或.pth文件扩展名保存模型。 load: model = TheModelClass(*args, **kwargs) model.load_state_dict(torch.load(PATH...

csdnxiekai的博客 7323

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

One-Hot in python

Dataset wget https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data Code # DataFlair Iris Flower Classification # Import Packages import numpy as np import pandas as pd from sklearn.preprocessing import OneHotEncoder # Step 1: Load data

计算机视觉领域 570

对load_mnist(normalize=False, flatten=True, one_hot_label=True)参数的深入理解

这肯能是效率最高的学习别人的代码的方式了。

weixin_44943389的博客 775

5 分钟装好 OpenMausBot:新手跨平台安装与上手指南

把 Claude、Codex、Grok 变成聊天软件里能干活的"联系人",OpenMausBot 帮你做到。跟着本文走一遍,5 分钟完成 Mac、Windows、Ubuntu 的跨平台安装,并创建你的第一个机器人。 ## 项目定位:聊天软件里的一支 AI 智能体团队 OpenMausBot 是一款开源的 Grok Bot 替代品,侧边栏里的每个 Bot 背后都是一个真实运行在本地的 Agent

gitblog_01042的博客 614

OFBiz的主要配置文件说明——component-load.xml

OFBiz的主要配置文件说明——component-load.xml      component-load.xml:    component-load.xml文件非常重要,引文没有它,OFBiz不能加载任何应用,除非该应用放置在hot-deploy文件夹下。无论何时创建新的应用时,都需要新建一个除“party, order”等这些OFBiz已提供的文件夹外的新文件夹,然后告诉OFB...

freeazy的专栏 271

hot-lib-reloader-rs高级配置:多库管理与自定义加载策略

hot-lib-reloader-rs 是一个强大的 Rust 热重载工具,它允许你在不重启应用程序的情况下动态更新代码。对于复杂项目来说,掌握其高级配置和多库管理策略至关重要。本文将深入探讨如何优化 hot-lib-reloader-rs 的使用,实现高效的多库管理和自定义加载策略,为你的开发流程带来革命性的提升!🚀 ## 为什么需要多库管理? 在大型 Rust 项目中,通常会将功能模块化

gitblog_00923的博客 503

修复:"Failed to start Load Kernel Modules"

使用非默认内核而出现的错误。 [zsj@arch ~]$ systemctl --state=failed UNIT LOAD ACTIVE SUB DESCRIPTION● systemd-modules-load.service loaded failed failed Load Kernel ModulesLOAD = Ref...

weixin_34315189的博客 2200

Codex 上的 PR Babysitter:基于 Loop Engineering 的 PR 看护与自动修复实践

PR Babysitter(PR 看护循环)是 loop-engineering 仓库中一个典型的 L2(Assisted)修复型模式:它按照固定节奏扫描仓库中所有待合并的 PR,对 CI 失败和可执行的评审意见发起最小的修复提案,并在人类最终裁决前绝不越权合并。本文以 [examples/codex/pr-babysitter.md](https://link.gitcode.com/i/01e

gitblog_00380的博客 455
上一篇: h5网页唤醒app的方案
下一篇: JavaScript 迭代器(Iterator)和生成器(Generator)
梅花十三儿
博客等级 码龄5年 1038粉丝 444原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值