gulp-build-html
Version:
Used to process html files to automatically concat css and js files, and meanwhile update html references.
345 lines (289 loc) • 9.31 kB
JavaScript
var path = require("path"),
fs = require("fs"),
utils = require("wzh.node-utils"),
lib = require("./lib");
var logger = lib.logger;
var prefix = utils.string.randomString("@FileContent@_");
/**
* @constructor
* 构建块
*/
var BuildBlock = function(){
var
/* 构建类型。js:脚本;css:样式 */
type,
/* 目标文件名称 */
targetFileName,
/**
* 要构建的文件路径或正文列表
* 正文统一含有前缀[prefix]
* @type {String[]}
*/
referencedFilePathsOrContents = [],
/* 声明了该构建块的html文件路径 */
containingHtmlFilePath,
/* 构建块的开始索引,亦即第一个字符在html中的索引位置 */
beginIndex,
/* 构建块的结束索引,亦即最后一个字符在html中的索引位置 */
endIndex,
/* 构建选项 */
buildOptions = {};
/**
* 获取构件类型
* @return {String}
*/
this.getType = function(){
return null == type? type: String(type).toLowerCase();
};
/**
* 设置构建类型
* @param {String} v 构建类型。js:脚本;css:样式
* @returns {String}
*/
this.setType = function(v){
type = v;
return this;
};
/**
* 获取要构建的目标文件名称
* @param {Boolean} [ifResolvePath=false] 是否将解析路径(相对于“声明了该构建块的html文件路径”)
* @returns {String}
*/
this.getTargetFileName = function(ifResolvePath){
if(arguments.length < 1)
ifResolvePath = false;
if(null == containingHtmlFilePath || null == targetFileName)
return "";
return !ifResolvePath? targetFileName: path.resolve(path.dirname(containingHtmlFilePath), targetFileName);
};
/**
* 获取要构建的目标文件名称对应的HTML引用代码
* @returns {String}
*/
this.getTargetFileReferringHtml = function(){
if(utils.string.isEmptyString(targetFileName, true))
return "";
var _type = this.getType();
if(utils.string.isEmptyString(_type, true)){
logger.warn("Empty file type to generate html reference for file: {}", targetFileName);
return "";
}
switch(_type){
case "js":
return '<script data-auto-generated-by = "gulp-build-html" type = "text/javascript" src = "' + targetFileName + '"></script>';
case "css":
return '<link data-auto-generated-by = "gulp-build-html" rel = "stylesheet" href = "' + targetFileName + '" />';
default:
logger.error("Unknown file type: {} to generate html reference for file: {}", _type, targetFileName);
return "";
}
};
/**
* 获取要构建的目标正文对应的HTML引用代码
* @param {String} content 正文
* @returns {String}
*/
this.getTargetContentReferringHtml = function(content){
var _type = this.getType();
if(utils.string.isEmptyString(_type, true)){
logger.warn("Empty file type to generate html reference");
return "";
}
switch(_type){
case "js":
return '<script data-auto-generated-by = "gulp-build-html" type = "text/javascript">' + content + '</script>';
case "css":
return '<style data-auto-generated-by = "gulp-build-html">' + content + '</style>';
default:
logger.error("Unknown file type: {} to generate html reference", _type);
return "";
}
};
/**
* 设置要构建的目标文件名称
* @param {String} v 要构建的目标文件名称
* @returns {BuildBlock}
*/
this.setTargetFileName = function(v){
targetFileName = v;
return this;
};
/**
* 获取要构建的文件路径或正文列表。
* @param {Boolean} [ifResolvePath=false] 是否将解析路径(相对于“声明了该构建块的html文件路径”)
* @returns {String[]}
*/
this.getReferencedFilePathsOrContents = function(ifResolvePath){
if(arguments.length < 1)
ifResolvePath = false;
var dir = path.dirname(containingHtmlFilePath);
return !ifResolvePath? referencedFilePathsOrContents: referencedFilePathsOrContents.map(function(p){
if(p.startsWith(prefix))
return p;
return path.resolve(dir, p);
});
};
/**
* 设置要构建的文件路径或正文列表。如果是正文,则需要在调用该方法前统一添加prefix前缀
* @param {String[]} v 要构建的文件路径列表
* @returns {BuildBlock}
*/
this.setReferencedFilePaths = function(v){
referencedFilePathsOrContents = v;
return this;
};
/**
* 添加要构建的文件路径或正文至列表中。如果是正文,则需要在调用该方法前统一添加prefix前缀
* @param {String} p 要构建的文件路径或文件正文
* @param {Boolean} [isInlineContentRatherThanFilePath=false] 是否为文件正文。true:文件路径;false:文件正文
* @returns {BuildBlock}
*/
this.addReference = function(p, isInlineContentRatherThanFilePath){
if(arguments.length < 2)
isInlineContentRatherThanFilePath = false;
if(isInlineContentRatherThanFilePath)
p = prefix + p;
referencedFilePathsOrContents = referencedFilePathsOrContents || [];
if(referencedFilePathsOrContents.indexOf(p) === -1)
referencedFilePathsOrContents.push(p);
return this;
};
/**
* 获取声明了该构建块的html文件路径
* @returns {String}
*/
this.getContainingHtmlFilePath = function(){
return containingHtmlFilePath;
};
/**
* 设置声明了该构建块的html文件路径
* @param {String} v 声明了该构建块的html文件路径
* @returns {BuildBlock}
*/
this.setContainingHtmlFilePath = function(v){
containingHtmlFilePath = v;
return this;
};
/**
* 获取构建块的开始索引
* @returns {Number}
*/
this.getBeginIndex = function(){
return beginIndex;
};
/**
* 设置构建块的开始索引
* @param {String} v 构建块的开始索引
* @returns {BuildBlock}
*/
this.setBeginIndex = function(v){
beginIndex = v;
return this;
};
/**
* 获取构建块的结束索引
* @returns {Number}
*/
this.getEndIndex = function(){
return endIndex;
};
/**
* 设置构建块的结束索引。亦即构建块最后一个字符所在的索引
* @param {String} v 构建块的结束索引。亦即构建块最后一个字符所在的索引
* @returns {BuildBlock}
*/
this.setEndIndex = function(v){
endIndex = v;
return this;
};
/**
* 获取构建选项集合
* @returns {Object}
*/
this.getBuildOptions = function(){
var ops = {};
for(var p in buildOptions)
ops[p] = buildOptions[p];
return ops;
};
/**
* 获取特定的构建选项
* @param {String} name 选项key
* returns {String|null}
*/
this.getBuildOption = function(name){
return name in buildOptions? buildOptions[name]: null;
};
/**
* 设置构建选项
* @param {String} name 选项key
* @param {String} value 选项取值
* @returns {BuildBlock}
*/
this.setBuildOption = function(name, value){
buildOptions[name] = value;
return this;
};
/**
* 设置构建选项集合
* @param {Object} ops 构建选项集合
* @returns {BuildBlock}
*/
this.setBuildOptions = function(ops){
if(null != ops && typeof ops === "object")
for(var p in ops)
buildOptions[p] = ops[p];
return this;
};
/**
* 根据既有的引用拼合内容
* @param {String[]} [filePathsOrContents] 引用列表。如果为空,则使用自身已经存在的引用
* @param {String} referringFileFolderAbsolutePath 最终引用资源的文件所在目录的绝对路径
* @returns {string}
*/
this.concatReferenceContent = function(filePathsOrContents, referringFileFolderAbsolutePath){
var concatContent = "";
filePathsOrContents = filePathsOrContents || this.getReferencedFilePathsOrContents(true);
for(var i = 0; i < filePathsOrContents.length; i++){
var p = filePathsOrContents[i];
var content = "";
if(BuildBlock.isReferenceContent(p)){/* 文件正文 */
content = BuildBlock.getReference(p);
}else{/* 文件路径 */
try{
content = fs.readFileSync(p, 'utf8');
}catch(e){
logger.error("Error occurred while reading content from file: {}. {}", p, e);
console.error(e);
continue;
}
/* 对于CSS文件中的资源引用,需要调整引用路径,保证合并后资源可以正常饮用得到 */
if("css" === this.getType())
content = lib.updateReferenceAsRelativeTo(content, p, referringFileFolderAbsolutePath);
}
concatContent +=
"\r\n" + "/* [gul-build-html] merged from: " + path.relative(referringFileFolderAbsolutePath, p) + " */"
+ "\r\n" + content;
}
return concatContent;
};
};
/**
* 判断给定的内容时否是正文,而非路径
* @param {String} tar 要判断的字符串
* @returns {boolean}
*/
BuildBlock.isReferenceContent = function(tar){
return tar.startsWith(prefix);
};
/**
* 根据给定的字符串获取引用的正文或引用的路径
* @param {String} src 源字符串
* @returns {String}
*/
BuildBlock.getReference = function(src){
if(!BuildBlock.isReferenceContent(src))
return src;
return src.substring(prefix.length);
};
module.exports = BuildBlock;