hexo
Version:
A fast, simple & powerful blog framework, powered by Node.js.
218 lines (181 loc) • 5.58 kB
JavaScript
var async = require('async'),
fs = require('graceful-fs'),
_ = require('lodash'),
pathFn = require('path'),
util = require('../../../util'),
file = util.file2,
Pool = util.pool,
HexoError = require('../../../error');
module.exports = function(args, callback){
var watchOption = args.w || args.watch,
start = Date.now(),
cache = {},
count = 0;
var log = hexo.log,
config = hexo.config,
route = hexo.route,
publicDir = hexo.public_dir,
sourceDir = hexo.source_dir,
q;
if (config.multi_thread){
var workerPath = require.resolve('./worker');
if (config.multi_thread === true){
q = new Pool(workerPath);
} else {
q = new Pool(workerPath, config.multi_thread);
}
} else {
q = async.queue(function(data, next){
if (data.type === 'copy'){
file.copyFile(data.src, data.dest, next);
} else {
file.writeFile(data.dest, data.content, next);
}
}, config.max_open_file);
}
var pushCallback = function(err){
var data = this.data,
path = data.dest.substring(publicDir.length);
if (err){
if (err.code === 'EMFILE'){
q.push(item, pushCallback);
} else {
callback(HexoError.wrap(err, 'File generate failed: ' + path));
}
return;
}
count++;
log.log('create', 'Public: %s', path);
};
/**
* Fired before generation started.
*
* @event generateBefore
* @for Hexo
*/
hexo.emit('generateBefore');
hexo.post.load({watch: watchOption}, function(err){
if (err) return callback(err);
var list = route.routes,
keys = Object.keys(list),
finish = Date.now(),
elapsed = (finish - start) / 1000;
log.i('Files loaded in %ss', elapsed.toFixed(3));
async.auto({
// Check if the public folder exists
exist: function(next){
fs.exists(publicDir, function(exist){
next(null, exist);
});
},
// Clear the public folder
clear: ['exist', function(next, results){
if (!results.exist){
log.d('Public folder not exists. No need to clear public folder.');
return next();
}
var exclude = _.map(keys, function(item){
return pathFn.normalize(item);
});
file.emptyDir(publicDir, {exclude: exclude}, function(err){
if (err) return callback(HexoError.wrap(err, 'Public folder clear failed'));
log.d('Public folder cleared:', exclude.join(','));
next();
});
}],
// Generate files
generate: ['exist', function(next, results){
var exist = results.exist,
arr = [];
start = Date.now();
async.each(keys, function(i, next){
var item = list[i],
dest = pathFn.join(publicDir, i);
async.waterfall([
function(next){
if (!exist || item.modified) return next(null, true);
fs.exists(dest, function(exist){
next(null, !exist);
});
},
function(push, next){
if (!push) return next();
item(function(err, result){
if (err) return callback(HexoError.wrap(err, 'Render failed: ' + i));
if (typeof result === 'undefined') return next();
if (result.readable){
arr.push({
type: 'copy',
src: result.path,
dest: dest
});
} else {
cache[i] = result;
arr.push({
type: 'normal',
dest: dest,
content: result
});
}
next();
});
}
], next);
}, function(err){
if (err) return callback(err);
q.push(arr, pushCallback);
q.drain = next;
});
}]
}, function(err){
if (err) return callback(err);
var finish = Date.now(),
elapsed = (finish - start) / 1000;
/**
* Fired after generation done.
*
* @event generateAfter
* @for Hexo
*/
hexo.emit('generateAfter');
log.i('%d files generated in %ss', count, elapsed.toFixed(3));
if (watchOption){
q.drain = function(){};
route.on('update', function(path, fn){
if (!fn.modified) return;
var dest = pathFn.join(publicDir, path);
route.get(path)(function(err, result){
if (err) return log.e(HexoError.wrap(err, 'File render failed: ' + path));
if (typeof result === 'undefined') return;
if (result.readable){
q.push({
type: 'copy',
src: result.path,
dest: dest
}, pushCallback);
} else {
if (cache[path] === result) return;
cache[path] = result;
q.push({
type: 'normal',
dest: dest,
content: result
}, pushCallback);
}
});
}).on('remove', function(path){
fs.unlink(pathFn.join(publicDir, path), function(){
log.log('delete', 'Public: %s', path);
});
});
} else {
if (config.multi_thread) q.end();
if (args.d || args.deploy){
hexo.call('deploy', callback);
} else {
callback();
}
}
});
});
};