实现原理 使用代理的方式让所有类和实例能够在js文件更改后, 对被代理对象进行替换, 实现热更新.
作用 使用这个模块引入的js文件, 在修改后不需要重启服务器, 可以达到下列效果:
- require.cache更新了, 新的require使用新的js
- 原来旧的类对应的实例也更新了 具体就是: 绑定在prototype下的函数, 绑定在类上的函数等也更新了, 旧实例调用的是新的代码.
注意
- 因为代理会消耗一定资源, 所以建议只在逻辑js上使用.
- 目前建议开发环境中用, 因为还在完善
安装
npm install hot-require
引入
// app启动时候引入这个模块, 引入一次即可
require('hot-require');
示例
// 需要热更新js, 用下面方式代替原有的require函数
var yourJs = _require(__dirname, '[your js path]');
源码 github: https://github.com/rayosu/hot-require 欢迎大家给意见, 完善和扩展这个方案.
看上去实现非常简单啊,有不少热更新的框架都比你这个要复杂。。。
支持绑定在prototype下的函数变动的热更新, 并且不影响初始化后的实例对象的属性值
不太懂…
我理解热更新,就是不缓存到Module.cache 那么可以直接在需要的地方删除缓存
var some_thing = require('some_need_hot_require')
// delete cache
var Module = module.constructor
var filename = Module._resolveFilename('some_need_hot_require',module)
delete Module._cache[filename]
可以封装一个方法 module.require
/*
require -> Module.prototype.require -> Module.load(request,module)
require.reslove -> Module._resolveFilename(request, module);
*/
var Module = module.constructor
Module.prototype._require = function(request) {
var res = this.require(request)
// delete cache
var filename = Module._resolveFilename(request, this);
delete Module._cache[filename]
return res;
};
需要热加载,使用 module.require(xxx) 即可,可以使用任何在 require 里面使用的东西 … 完整代码见gist https://gist.github.com/magicdawn/5d6f53e1d3020cec112f
@magicdawn 楼主的意思是只更新代码的逻辑,而不影响正在运行的数据,你的代码运行时至少存在局部变量吧!你不能把局部变量的值搞潮吹了啊!
@hainee 还是不懂 ⊙﹏⊙!
[[[[[[[[@magicdawn](/user/magicdawn)](/user/magicdawn)](/user/magicdawn)](/user/magicdawn)](/user/magicdawn)](/user/magicdawn)](/user/magicdawn)](/user/magicdawn) 我举个例子 有一个js文件user.js如下:
var User = function(cfg){
this.name = cfg.name;
this.age = cfg.age;
};
User.prototype.getName = function(){
return this.name + "A";
};
module.exports = User;
// end user.js
你在程序中引入了user.js, 并实例化一个user对象
var User = require("user.js");
var user = User({"张三", 15});
app.addOnlineUser(user);
并且你将user是来存储起来, 不需要每次都进行实例化.
然后你修改了user.js, 并且删除缓存
假如你将User.prototype.getName
修改为:
User.prototype.getName = function(){
return this.name + "B";;
}
然后你删除了cache, 让require时从新载入新的user.js文件
此时, 你的程序哪怕重新执行var User = require("user.js");
当你执行
var user = app.getOnlineUser("张三");
user.getName(); // "张三A" 而非 "张三B"
时, 依然是就得User类的getName函数.return this.name + "A";
除非你一一找到你旧User生成的user实例, 并且将他们跟新的User类原型进行关联, 否则你的原有user数据依然沿用旧User类的函数处理代码.
新旧User类是同时存在的, 只是你用了同一个引用名字而已. 但对应的内存对象是不同的, 而且user实例当初对应的是旧的User类原型.
简而言之, 按照你的方式, 无论如何, 你也无法改变你之前载入的User类已经生成的user实例, 去关联到你的新User类中. 除非你舍弃所有旧的类产生的实例. 当然, 如果你的服务器程序不存在停留js内存的数据, 你的每一个操作都需要重新调用require, 那我的方案就显得多此一举了, 呵呵.
@rayosu 我原来也想写一个这个… 但是最后只能实现 .json 的更新 (无刷新 reload) … .js 实在无从下手… 因为引用都是缓存的… 就算更新了对象, 原本的还是引用到旧对象上.
有新版本了, 解决了一个bug, 原来以为是对动态return对象的实现有问题, 后来发现是我忘记了对非prototype绑定函数忘记了return~~~