vkitty
Version:
hello kitty
265 lines (243 loc) • 7.39 kB
JavaScript
const Util = require('./util.js');
const querystring = require('querystring');
const path = require('path');
const Parse = require('./parse.js');
const watch = require('gulp-watch');
const extract = require('extract-comments');
const EventEmitter = require('events').EventEmitter;
const Observe = require('./observe.js');
const Dest = require('./dest.js');
function Compile(vinyl,kitty){
var data = this.data = {};
data.vinyl = vinyl;
data.isActive=true;
data.depends =[];
this.kitty = kitty;
this._extendData();
this.filename = data.filename;
this._setType();
data.content = this._getContent();
data.compileContent = data.content;
}
Compile.prototype.init = function(){
Observe.compileContent(this);
this._parseContent();
this._kittySrcDepends();
this._watch();
this.kitty.appendCompiler(this);
};
/**
* 扩展data数据
* @private
*/
Compile.prototype._extendData = function(){
var vinyl = this.data.vinyl;
var filename = vinyl.path;
this.data.filename = filename.replace(/\?.*$/,'');
this.data.ext = path.extname(this.data.filename);
};
/**
* 深度分析内容构成
* @private
*/
Compile.prototype._parseContent = function(){
Parse.start(this);
};
/***
* 获取content
* 如果是图片文件,返回path\mtime和ctime,因为MD5的时候是通过content来的
* 图片不需要toString
* @returns {*}
* @private
*/
Compile.prototype._getContent = function(){
var data = this.data;
var vinyl = data.vinyl;
var contents = vinyl.contents;
if (data.type==='img' || data.type==='media') {
return vinyl.path+vinyl.stat.mtime+vinyl.stat.ctime;
} else {
var content='';
try{
content = contents.toString();//将buffer转为string
}catch (e){
Util.console.error('globs error');
Util.console.error('error from '+data.filename,e);
}
content = Gkitty.loaders.beforeCompile(content, '', this);//beforeCompile处理
if(content===undefined){
Util.console.error('do loaders.beforeCompile must return a string');
Util.console.error('error from '+data.filename,true);
}
content = this._handleContentComments(content);
return content;
}
};
/**
* 处理备注中的include require
* @private
*/
Compile.prototype._handleContentComments = function (content) {
var data = this.data;
var comments = extract(content);
comments.forEach((comment)=> {
var raw = comment.raw;
content = content.replace(raw, function (word) {
return word.replace(/require/g, '__kitty').replace(/_include/g, '___kitty');
});
});
return content;
};
/**
* 解决_srcDepends
* @private
*/
Compile.prototype._kittySrcDepends = function(){
var kitty = this.kitty;
var bufferFiles = kitty.bufferFiles;
this.data.depends.forEach((depend)=>{
var filename = depend.data.filename;
if(filename && !bufferFiles[filename]){
kitty._src(filename,kitty.options,(err)=>{
Util.console.error('error from '+this.filename,err);
});
}
})
};
/**
* 编译依赖
* @returns {string}
* @private
*/
Compile.prototype.compileDepends = function(){
var depends = this.data.depends;
var len = depends.length;
depends.forEach((depend)=>{
len--;
if(len>0){
this.setDependsCompileNotOver();
}
depend.compile();
});
};
/**
* 判断compile.depends是否都编译了
* 通过depend.compileContent判断,如果有undefined值表示没有结束
*/
Compile.prototype.checkDependsCompileIsOver = function(){
var depends = this.data.depends;
var check = true;
depends.forEach((depend)=>{
if(depend.data.compileContent===undefined){
check=false;
}
});
return check;
};
/**
* 强制设置DependsCompileNotOver
* depend.readyCompileContentFromChild会用到
* 主要是防止拉内容的时候造成多次编译,拉内容是不能向上冒泡的
*/
Compile.prototype.setDependsCompileNotOver = function(){
var old = this.checkDependsCompileIsOver;
this.checkDependsCompileIsOver = ()=>{
this.checkDependsCompileIsOver = old;
return false;
}
};
/**
* 拼接depends.content
*/
Compile.prototype.concatDepends = function(){
var depends = this.data.depends;
var result= '';
depends.forEach((depend)=>{
if(depend.data.compileContent){
result += depend.data.compileContent;
}else{
result += depend.data.content;
}
});
this.data.compileContent = result;
};
/**
* 监听compileContent改变后触发
*/
Compile.prototype.bindChangeCompile = function(){
var kitty = this.kitty;
var bufferFiles = kitty.bufferFiles;
Dest.compiler(this);
var filename = this.filename;
var compileContent = this.data.compileContent;
Object.keys(bufferFiles).forEach((key)=>{
var bufferFile = bufferFiles[key];
var depends = bufferFile.data.depends;
depends.forEach((depend)=>{
if(depend.data.filename === filename){
depend.data.content = compileContent;
}
});
})
};
/**
* 设置文件类型
* 文件类型分为js\image\css\txt
* 优先通过loaders来判断,如若还是txt 则通过文件后缀来判断
* 因为require('./xxx.vue')其实也是一个js文件
* @private
*/
Compile.prototype._setType = function(){
var kitty = this.kitty;
var bufferFiles = kitty.bufferFiles;
var filename = this.filename;
this.data.type='txt';
Object.keys(bufferFiles).forEach((key)=>{
var bufferFile = bufferFiles[key];
bufferFile && bufferFile.data.depends.forEach((depend)=>{
if(depend.data.filename === filename && this.data.type==='txt'){
this.data.type = depend.data.type;
}
})
});
if(this.data.type==='txt' && Util.isImg(this.data.ext)){
this.data.type='img';
}else if(this.data.type==='txt' && Util.isMedia(this.data.ext)){
this.data.type='media';
}else if(this.data.type==='txt' && Util.isJs(this.data.ext)){
this.data.type='js';
}else if(this.data.type==='txt' && Util.isCss(this.data.ext)){
this.data.type='css';
}
};
/**
* 自动watch depend.filename
* 配置不需要watch就不要去watch了
* 如果已经watch的文件不需要再次watch
* needCreateDest\relative不能因为重新watch后丢了
* @private
*/
Compile.prototype._watch = function(){
var kitty = this.kitty;
if(!kitty.canWatch){
return;
}
var bufferFiles = kitty.bufferFiles;
var filename = this.filename;
var needCreateDest = this.data.needCreateDest;
var isWatching = this.data._isWatching;
var relative = this.data.vinyl.relative;
!isWatching && watch(filename,kitty.options,function(vinyl){
var event = vinyl.event;
if(event!=='unlink'){
Util.pointVinylRelative(vinyl,relative);
var compiler = new Compile(vinyl,kitty);
compiler.data.needCreateDest = needCreateDest;
compiler.data._isWatching = true;
compiler.init();
}else{
delete bufferFiles[filename];
}
});
};
module.exports = Compile;