Dan*_*iel 6 javascript node.js livereload
我一直试图在Node.js上弄清楚这个"Hot Code Push".基本上,我的主文件(在您键入时运行node app.js)包含一些设置,配置和初始化.在那个文件中,我有一个文件观察者,使用chokidar.当我添加文件时,我只是require文件.如果文件已被更改或更新,我将删除缓存delete require.cache[path],然后重新要求它.所有这些模块都不会导出任何内容,它只适用于单个全局Storm对象.
Storm.watch = function() {
var chokidar, directories, self = this;
chokidar = require('chokidar');
directories = ['server/', 'app/server', 'app/server/config', 'public'];
clientPath = new RegExp(_.regexpEscape(path.join('app', 'client')));
watcher = chokidar.watch(directories, {
ignored: function(_path) {
if (_path.match(/\./)) {
!_path.match(/\.(js|coffee|iced|styl)$/);
} else {
!_path.match(/(app|config|public)/);
}
},
persistent: true
});
watcher.on('add', function(_path){
self.fileCreated(path.resolve(Storm.root, _path));
//Storm.logger.log(Storm.cliColor.green("File Added: ", _path));
//_console.info("File Updated");
console.log(Storm.css.compile(' {name}: {file}', "" +
"name" +
"{" +
"color: white;" +
"font-weight:bold;" +
"}" +
"hr {" +
"background: grey" +
"}")({name: "File Added", file: _path.replace(Storm.root, ""), hr: "=================================================="}));
});
watcher.on('change', function(_path){
_path = path.resolve(Storm.root, _path);
if (fs.existsSync(_path)) {
if (_path.match(/\.styl$/)) {
self.clientFileUpdated(_path);
} else {
self.fileUpdated(_path);
}
} else {
self.fileDeleted(_path);
}
//Storm.logger.log(Storm.cliColor.green("File Changed: ", _path));
console.log(Storm.css.compile(' {name}: {file}', "" +
"name" +
"{" +
"color: yellow;" +
"font-weight:bold;" +
"}" +
"hr {" +
"background: grey" +
"}")({name: "File Changed", file: _path.replace(Storm.root, ""), hr: "=================================================="}));
});
watcher.on('unlink', function(_path){
self.fileDeleted(path.resolve(Storm.root, _path));
//Storm.logger.log(Storm.cliColor.green("File Deleted: ", _path));
console.log(Storm.css.compile(' {name}: {file}', "" +
"name" +
"{" +
"color: red;" +
"font-weight:bold;" +
"}" +
"hr {" +
"background: grey" +
"}")({name: "File Deleted", file: _path.replace(Storm.root, ""), hr: "=================================================="}));
});
watcher.on('error', function(error){
console.log(error);
});
};
Storm.watch.prototype.fileCreated = function(_path) {
if (_path.match('views')) {
return;
}
try {
require.resolve(_path);
} catch (error) {
require(_path);
}
};
Storm.watch.prototype.fileDeleted = function(_path) {
delete require.cache[require.resolve(_path)];
};
Storm.watch.prototype.fileUpdated = function(_path) {
var self = this;
pattern = function(string) {
return new RegExp(_.regexpEscape(string));
};
if (_path.match(pattern(path.join('app', 'templates')))) {
Storm.View.cache = {};
} else if (_path.match(pattern(path.join('app', 'helpers')))) {
self.reloadPath(path, function(){
self.reloadPaths(path.join(Storm.root, 'app', 'controllers'));
});
} else if (_path.match(pattern(path.join('config', 'assets.coffee')))) {
self.reloadPath(_path, function(error, config) {
//Storm.config.assets = config || {};
});
} else if (_path.match(/app\/server\/(models|controllers)\/.+\.(?:coffee|js|iced)/)) {
var isController, directory, klassName, klass;
self.reloadPath(_path, function(error, config) {
if (error) {
throw new Error(error);
}
});
Storm.serverRefresh();
isController = RegExp.$1 == 'controllers';
directory = 'app/' + RegExp.$1;
klassName = _path.split('/');
klassName = klassName[klassName.length - 1];
klassName = klassName.split('.');
klassName.pop();
klassName = klassName.join('.');
klassName = _.camelize(klassName);
if (!klass) {
require(_path);
} else {
console.log(_path);
self.reloadPath(_path)
}
} else if (_path.match(/config\/routes\.(?:coffee|js|iced)/)) {
self.reloadPath(_path);
} else {
this.reloadPath(_path);
}
};
Storm.watch.prototype.reloadPath = function(_path, cb) {
_path = require.resolve(path.resolve(Storm.root, path.relative(Storm.root, _path)));
delete require.cache[_path];
delete require.cache[path.resolve(path.join(Storm.root, "server", "application", "server.js"))];
//console.log(require.cache[path.resolve(path.join(Storm.root, "server", "application", "server.js"))]);
require("./server.js");
Storm.App.use(Storm.router);
process.nextTick(function(){
Storm.serverRefresh();
var result = require(_path);
if (cb) {
cb(null, result);
}
});
};
Storm.watch.prototype.reloadPaths = function(directory, cb) {
};
Run Code Online (Sandbox Code Playgroud)
一些代码是不完整的/不使用,因为我正在尝试很多不同的方法.
对于以下代码:
function run() {
console.log(123);
}
Run Code Online (Sandbox Code Playgroud)
完美的工作.但任何异步代码都无法更新.
app.get('/', function(req, res){
// code here..
});
Run Code Online (Sandbox Code Playgroud)
如果我在nodejs进程运行时更新文件,则没有任何反应,但它会通过文件观察程序并删除缓存,然后重新建立.另一个不起作用的例子是:
// middleware.js
function hello(req, res, next) {
// code here...
}
// another file:
app.use(hello);
Run Code Online (Sandbox Code Playgroud)
由于app.use仍将使用该方法的旧版本.
我怎么能解决这个问题?有什么我想念的吗?
请不要提出建议,以便永远使用第三方模块.我正在尝试将功能合并到单个实例中.
在研究了流星代码库之后(在node.js或浏览器中"热代码推送"的资源非常少.)并且修改了我自己的实现,我成功地制定了一个可行的解决方案.https://github.com/TheHydroImpulse/Refresh.js.这仍处于发展的早期阶段,但现在似乎很稳固.我也将实现一个浏览器解决方案,只是为了完成.
删除 的require缓存实际上并不会“卸载”旧代码,也不会撤消该代码所做的操作。
以下面的函数为例:
var callbacks=[];
registerCallback = function(cb) {
callbacks.push(cb);
};
Run Code Online (Sandbox Code Playgroud)
现在假设您有一个调用该全局函数的模块。
registerCallback(function() { console.log('foo'); });
Run Code Online (Sandbox Code Playgroud)
您的应用程序启动后,callbacks将有一项。现在我们将修改该模块。
registerCallback(function() { console.log('bar'); });
Run Code Online (Sandbox Code Playgroud)
您的“热补丁”代码运行,删除 require.cached 版本并重新加载模块。
您必须意识到现在callbacks有两项。首先,它有一个对记录 foo 的函数(在应用程序启动时添加)的引用和对记录 bar 的函数(刚刚添加)的引用。
即使您删除了对该模块的缓存引用exports,您也无法实际删除该模块。 就 JavaScript 运行时而言,您只需从众多引用中删除一个即可。应用程序的任何其他部分仍然可以保留对旧模块中某些内容的引用。
这正是您的 HTTP 应用程序所发生的情况。当应用程序首次启动时,您的模块会将匿名回调附加到路由。当您修改这些模块时,它们会将新的回调附加到相同的路由;旧的回调不会被删除。我猜您正在使用 Express,它会按照添加的顺序调用路由处理程序。因此,新的回调永远没有机会运行。
老实说,我不会使用这种方法在修改时重新加载您的应用程序。大多数人在干净的环境的假设下编写应用程序初始化代码;通过在肮脏的环境(即已经启动并运行的环境)中运行初始化代码,您违反了这一假设。
尝试清理环境以允许初始化代码运行几乎肯定是麻烦大于其价值。当您的底层文件发生更改时,我只需重新启动整个应用程序即可。
| 归档时间: |
|
| 查看次数: |
2223 次 |
| 最近记录: |