vkitty
Version:
hello kitty
282 lines (261 loc) • 8.19 kB
JavaScript
const Observe = require('./observe.js');
const Util = require('./util.js');
const path = require('path');
const config = Gkitty.config;
function Depend(data,compiler){
this.compiler = compiler;
this.data = data;
this._setType();
this._appendBabelLoaders();
this._appendHookLoaders();
this._readyCompileContent();
Observe.dependContent(this);
}
/**
* 编译depend
*/
Depend.prototype.compile = function(){
var bufferFiles = this.compiler.kitty.bufferFiles;
var filename = this.data.filename;
var bufferFile = bufferFiles[filename];
var data = this.data;
if(filename && !data.content && bufferFile){
data.content = bufferFile.data.compileContent || '';
}else{
data.content = data.content+'';
}
};
/**
* observe depend.content callback
*/
Depend.prototype.bindChangeContent= function(){
this._doLoaders();
if(this.compiler.checkDependsCompileIsOver()){
this.compiler.concatDepends();
}
};
/**
* 准备CompileContent,从 oldBufferFile 拉取
* 主要作用是如果子文件没有变化,就可以直接使用旧的depend.compileContent 提升效率
* 判断标准:filename相同\loaders相同\options相同
* 同时如果depend.filename引入的是共用文件,共用文件很大可能不会变化,需要在queue引用_readyCompileContentFromChild
* 如果有变化queue._resetDependCompileContent 会重置
*/
Depend.prototype._readyCompileContent = function(){
var bufferFiles = this.compiler.kitty.bufferFiles;
var key = this.compiler.filename;
var oldBufferFile = bufferFiles[key];
var data = this.data;
var filename = data.filename;
if(filename){
data.compileContent = undefined;
if(oldBufferFile){
var oldDepends = oldBufferFile.data.depends;
oldDepends.forEach((oldDepend)=>{
if(this._compareWithOldData(oldDepend.data)){
data.compileContent = oldDepend.data.compileContent;
}
})
}
}
};
/**
* 新旧depend.data判断
* @param oldData
* @returns {boolean}
* @private
*/
Depend.prototype._compareWithOldData = function(oldData){
var oldOptions = oldData.options;
var oldOptionsStr = JSON.stringify(oldOptions);
var oldLoaders = oldData.loaders;
var oldLodersStr = JSON.stringify(oldLoaders);
var oldFilename = oldData.filename;
var data = this.data;
var newLoaders = data.loaders;
var newLoadersStr = JSON.stringify(newLoaders);
var newOptions = data.options;
var newOptionsStr = JSON.stringify(newOptions);
var newFilename = data.filename;
return newFilename===oldFilename && newLoadersStr===oldLodersStr && newOptionsStr ===oldOptionsStr;
};
/**
* 从child拉取数据,提供给queue调用
* 要判断child.depends isover
* 同时,如果依赖的文件本来就是isactive 就不用处理了
* @private
*/
Depend.prototype.readyCompileContentFromChild = function(){
var bufferFiles = this.compiler.kitty.bufferFiles;
var filename = this.data.filename;
var compileContent = this.data.compileContent;
if(compileContent===undefined && filename){
var bufferFile = bufferFiles[filename];
if(bufferFile && !bufferFile.data.isActive && bufferFile.checkDependsCompileIsOver()){
this.compiler.setDependsCompileNotOver();
this.data.content = bufferFile.data.compileContent;
}
}
};
/**
* 处理depend.loaders
* @private
*/
Depend.prototype._doLoaders=function(){
var bufferFiles = this.compiler.kitty.bufferFiles;
var data = this.data;
var loaders = data.loaders;
data.compileContent = data.content;
loaders && loaders.forEach((key)=>{
var loader = Gkitty.loaders[key];
if(!loader){
Util.console.error('loaders.'+key+' is not a function');
Util.console.error('error from '+this.compiler.filename);
process.exit();
}
try{
data.compileContent = loader(data.compileContent,this,bufferFiles[data.filename]);
if(data.compileContent===undefined){
throw "loaders."+key+"' must return a string";
}
}catch (err){
Util.console.error('do loaders.'+key+' error!');
Util.console.error('error from '+this.data.filename,err);
}
});
if(this._checkEncodeStr()){
data.compileContent = this._encodeStr(data.compileContent);
}
};
/**
* 处理变量
* @param content
* @param options
* @returns {XML|string|void|*}
* @private
*/
Depend.prototype.handleVarOptions = function(content){
var options = this.data.options;
if (!options || !content) {
return content;
}
var varTag = config.varTag;
var openTag = varTag.open;
var closeTag = varTag.close;
var regexp = new RegExp(openTag + '(.+?)' + closeTag, 'g');
content = content.replace(regexp, function () {
var key = arguments[1] || '';
var val = options;
key.split('.').forEach(function (k) {
val = val[k];
});
return val || '';
});
return content;
};
/**
* loaders增加钩子loader
* @private
*/
Depend.prototype._appendHookLoaders=function(){
var loaders = this.data.loaders;
this.data.loaders = loaders.concat(['afterCompile']);
};
/**
* loaders增加babel处理
* bable只处理js文件
* 1. jstag|jscdn
* 2. tag && depend.data.type===js 或者 cdn && depend.data.type===js
* @private
*/
Depend.prototype._appendBabelLoaders=function(){
return;
var loaders = this.data.loaders;
var type = this.data.type;
var index = loaders.indexOf('jstag');
if(index===-1){
index = loaders.indexOf('jscdn');
}
if(index===-1){
if(type==='js'){
if(loaders.indexOf('tag')>-1){
index = loaders.indexOf('tag');
}else if(loaders.indexOf('cdn')>-1){
index = loaders.indexOf('cdn');
}
}
}
if(index>-1){
if(loaders.indexOf('mini')>-1){
index = loaders.indexOf('mini');
}else if(loaders.indexOf('jsmini')>-1){
index = loaders.indexOf('jsmini');
}
var newLoaders = loaders.splice(0,index).concat('_babel');
loaders = newLoaders.concat(loaders);
}
this.data.loaders = loaders;
};
/**
* 判断是否需要反编译字符串
* 1. compiler必须是js文件
* 2. depend.data.type不是js文件
* @returns {boolean}
* @private
*/
Depend.prototype._checkEncodeStr=function(){
var compiler = this.compiler;
var data = this.data;
if(data.filename && compiler.data.type==='js' && data.type!=='js'){
return true;
}else{
return false;
}
};
/**
* 设置文件类型
* @private
*/
Depend.prototype._setType= function(){
var data = this.data;
var loaders = data.loaders;
var filename = data.filename;
this.data.type='txt';
if(!filename){
return;
}
loaders.forEach((loader)=>{
if(Util.isImgLoader(loader)){
this.data.type='img';
}else if(Util.isJsLoader(loader)){
this.data.type='js';
}else if(Util.isCssLoader(loader)){
this.data.type='css';
}else if(Util.isMediaLoader(loader)){
this.data.type='media';
}
});
var extname = path.extname(filename);
if(this.data.type==='txt' && Util.isImg(extname)){
this.data.type='img';
}if(this.data.type==='txt' && Util.isMedia(extname)){
this.data.type='media';
}else if(this.data.type==='txt' && Util.isJs(extname)){
this.data.type='js';
}else if(this.data.type==='txt' && Util.isCss(extname)){
this.data.type='css';
}
};
/**
* 反编译字符串
* 如果是js _include进来的,需要处理为字符串,如果是require进来的就可以不用了
* @param str
* @returns {string|*}
* @private
*/
Depend.prototype._encodeStr=function(str){
str = str.replace(/\n\/\/.*?\n/g, '').replace(/\n/g, '').replace(/'/g, "\\'").replace(/\//g,'\\/');
str = "'" + str + "'";
return str;
};
module.exports = Depend;