nui-concat
Version:
Nui框架模块文件合并插件
281 lines (249 loc) • 8.57 kB
JavaScript
;
var through = require('through2');
var path = require('path');
var fs = require('fs');
var replacePath = function(path){
// a\b\c => a/b/c
path = path.replace(/\\/g, '/');
// a///b///c => a/b/c
path = path.replace(/([^:])\/{2,}/g, '$1/');
// a/b...../c => a/b../c
path = path.replace(/\.{2,}/g, '..');
// a/b../c => a/c
// a/../c => c
var replace = function(str){
if(/([\w]+\/?)(\.\.\/)/g.test(str)){
str = str.replace(/([\w]+\/?)(\.\.\/)/g, function(a, b, c){
if(a == b+c){
return ''
}
return a
})
return replace(str)
}
return str
}
path = replace(path);
// a/b./c => a/b/c
// a/./c => a/c
return path.replace(/([\w]+)\/?(\.\/)+/g, '$1/')
}
var isEmptyObject = function(obj){
var name;
for(name in obj){
return false;
}
return true;
}
var inArray = function(str, arr){
var len = arr.length;
var i=0;
for(i; i<len; i++){
if(arr[i] == str){
return true
}
}
return false
}
var unique = function(arr){
var newarr = [];
var temp = {};
arr.forEach(function(val, i){
if(!temp[val]){
temp[val] = true
newarr.push(val)
}
})
return newarr
}
module.exports = function(options){
options = options || {};
//路径别名
options.paths = options.paths || {};
//模块别名
options.alias = options.alias || {};
//忽略的模块名,模块不会追加到合并的文件中
options.ignore = options.ignore || ['util', 'template', 'component'];
if(options.paths.base){
for(var i in options.paths){
var _path = options.paths[i];
if(i !== 'base' && !/^[A-Z]:/.test(_path)){
options.paths[i] = options.paths.base + _path;
}
}
}
return through.obj(function(file, enc, cb){
if(file.isNull()){
return cb();
}
var dirname = path.dirname(file.path)+'/';
var content = file.contents.toString();
var matchs = content.match(/Nui.load\(['"][^'"]+['"]/g);
var cacheModules = {};
var cacheStyles = {};
if(!matchs){
return cb();
}
function Module(id, name, deps){
var mod = this;
mod.id = id;
mod.name = name;
mod.deps = deps;
mod.depmodules = {};
mod.filename = mod.id.substr(mod.id.lastIndexOf('/')+1);
mod.uri = mod.id.replace(new RegExp(mod.filename+'$'), '');
}
Module.prototype.load = function(){
var mod = this;
if(!/_module_\d+/.test(mod.name)){
mod.url = mod.id + '.js';
try{
var buffer = fs.readFileSync(mod.url);
var content = buffer.toString();
mod.content = content.replace(/Nui.define\((['"][^'"]+['"]\s*,)?/, "Nui.define('"+ mod.name +"',");
var arrs = mod.getdeps();
mod.deps = arrs[0];
mod.styles = arrs[1];
}
catch(e){}
}
return mod.resolve()
}
Module.prototype.getdeps = function(){
var mod = this;
var content = mod.content;
var deps = [];
var styles = [];
var depsMatchs = content.match(/Nui.define\((['"][^'"]+['"]\s*,)?\s*\[([^\[\]]+)\]/);
var requireMatchs = content.match(/(require|extands|imports)\(['"][^'"]+['"]/g);
if(depsMatchs){
var match = depsMatchs[2].split(',');
match.forEach(function(val, i){
val = val.replace(/^\s+|\s+/g, '').replace(/['"]/g, '');
if(!inArray(val, options.ignore)){
deps.push(val)
}
})
}
if(requireMatchs){
requireMatchs.forEach(function(val, i){
if(/^(require|extands)/.test(val)){
val = val.replace(/(require|extands)|[\('"]/g, '');
if(!inArray(val, options.ignore)){
deps.push(val)
}
}
else{
styles.push(val.replace(/(imports)|[\('"]/g, ''))
}
})
}
return [unique(deps), unique(styles)]
}
Module.prototype.resolve = function(){
var mod = this;
if(isEmptyObject(mod.depmodules)){
mod.deps.forEach(function(val, i){
var module = Module.getModule(val, [], mod.uri);
mod.depmodules[val] = module.load()
})
}
return mod
}
Module.prototype.getContents = function(contents){
var mod = this;
if(!contents){
contents = [];
}
contents.unshift(mod.content)
if(mod.deps.length){
for(var i in mod.depmodules){
contents = mod.depmodules[i].getContents(contents)
}
}
return contents
}
Module.prototype.loadstyles = function(styles){
var mod = this;
if(!styles){
styles = [];
}
var arrs = [];
if(mod.styles && mod.styles.length){
mod.styles.forEach(function(val){
arrs.push(Module.setId(val, mod.uri)[0]+'.css');
})
}
styles = arrs.concat(styles);
if(mod.deps.length){
for(var i in mod.depmodules){
styles = mod.depmodules[i].loadstyles(styles)
}
}
return styles
}
Module.setPath = function(id){
var pathMatch = id.match(/\{([^\{\}]+)\}/);
if(pathMatch){
var _path = options.paths[pathMatch[1]];
if(_path){
id = id.replace(pathMatch[0], _path).replace(/(\.(js|css))?(\?[\s\S]*)?$/g, '');
}
}
return id
}
Module.setId = function(id, uri){
var name = id.replace(/(\.(js|css))?(\?[\s\S]*)?$/g, '');
id = Module.setPath(options.alias[name] || name);
if(!/^[A-Z]:/.test(id)){
id = uri + name;
}
return [replacePath(id), name]
}
Module.getModule = function(id, deps, uri){
var arr = Module.setId(id, uri);
id = arr[0];
return cacheModules[id] || (cacheModules[id] = new Module(id, arr[1], deps))
}
Module.id = 0;
Module.load = function(id, callback){
var mod = Module.getModule('_module_'+Module.id++, [id], dirname);
callback(mod.load())
}
Module.getStyles = function(arr){
var arrs = [];
arr.forEach(function(val){
try{
var buffer = fs.readFileSync(val);
var content = buffer.toString();
arrs.push(content);
}
catch(e){}
})
return arrs
}
matchs.forEach(function(val, i){
var id = matchs[i].replace(/Nui.load\(/, '').replace(/['"]/g, '').replace(/-debug|-min/g, '');
Module.load(id, function(mod){
var contents = unique(mod.getContents()).join('');
var styles = Module.getStyles(unique(mod.loadstyles())).join('');
var url;
for(var i in mod.depmodules){
url = mod.depmodules[i].url;
break;
}
if(url){
if(styles){
var path = url.replace(/\/([^\/]+)\.js$/, '/style/');
if(!fs.existsSync(path)){
fs.mkdirSync(path)
}
fs.writeFileSync(url.replace(/\/([^\/]+)\.js$/, '/style/$1-debug.css'), styles)
}
fs.writeFileSync(url.replace(/(\.js)$/, '-debug$1'), contents)
}
})
})
cb();
})
}