[分享]hot-require, 自己写的一个js热更新实现

使用代理的方式让所有类和实例能够在js文件更改后, 对被代理对象进行替换, 实现热更新.
能够支持直接绑定在function下的函数, 支持绑定在prototype下的函数变动的热更新, 并且不影响初始化后的实例对象的属性值.

暂不支持: 新增函数, 新增属性的热更新

理论上是支持实例化后的pojo对象prototype自动热更新. 但我是用在逻辑的js上面, 对于存储数据的对象我没用这个模块. 欢迎大家给意见, 完善和扩展这个方案.

// 从npm中安装这个模块
npm install hot-require

// app启动时候引入这个模块, 引入一次即可
require('hot-require');

// 需要热更新js, 用下面方式代替原有的require函数
var yourJs = _require(__dirname, '[your js path]');

代码我贴出来:

 /**
 * Created by Surui on 2014/9/26.
 * E-Mail: surui.cc@gmail.com
 * github: https://github.com/rayosu/hot-require
 *
 */
var fs = require('fs');
var _cache = {};
global._require = function (dirname, path) {
    var _path = require.resolve(dirname + '/' + path);
    if(_cache[_path]) return _cache[_path];

    var RealClass = require(_path);
    // constructor[execute property proxy handler when create Object]
    var Proxy = function () {
        var realObj = new RealClass(arguments);
        // proxy all realObj's property[field and method], use getter/setter on field, and use function proxy on function
        for (var propertyName in realObj) {
            var property = realObj[propertyName];
            if (typeof property == "function") {
                this[propertyName] = function (_propertyName) {
                    return function () {
                        console.log('invoke property method: ' + _propertyName);
                        realObj[_propertyName].apply(realObj, arguments);
                    }
                }(propertyName);
            } else {
                Object.defineProperty(this, propertyName, {
                    get: function (_propertyName) {
                        return function () {
                            console.log('getter: ' + _propertyName);
                            return realObj[_propertyName];
                        }
                    }(propertyName),
                    set: function (_propertyName) {
                        return function (value) {
                            console.log('setter: ' + _propertyName + ' ,value: ' + value);
                            realObj[_propertyName] = value;
                        }
                    }(propertyName)
                })
            }
        }
    };
    // proxy static function
    for (var key in RealClass) {
        Proxy[key] = function (_key) {
            return function () {
                console.log('invoke static method: ' + _key);
                RealClass[_key].apply(RealClass, arguments);
            }
        }(key)
    }
    // proxy prototype function
    for (var key in RealClass.prototype) {
        Proxy.prototype[key] = function (_key) {
            return function () {
                console.log('invoke method: ' + _key);
                RealClass.prototype[_key].apply(RealClass, arguments);
            }
        }(key)
    }
    // use 'watchFile' and not 'watch' to keep the callback invoke once one time when the file change.
    fs.watchFile(_path, function () {
        delete require.cache[_path];
        // update new js file
        RealClass = require(_path);
        console.log('update js: ' + _path);
    });

    _cache[_path] = Proxy;
    return Proxy;
};
标签:无
raywithu 在 2014-9-29 13:56发布
raywithu 在 2014-9-29 18:15重新编辑 分享到 weibo
3 回复
#1 zj8487 2014-9-29 15:08 回复

支持,一定试一试

#2 wangxy 2014-9-30 13:02 回复

awesome!

#3 w3hacker 2014-10-2 08:01 回复

我就看看 我不说话

回到顶部