nyx_server
Version:
Node内容发布
236 lines (207 loc) • 6.71 kB
JavaScript
/* global process */
;
var fs = require('fs');
var path = require('path');
var crypto = require('crypto');
var patterns = [
/<link[^\>]+href=['"]([^"']+)["']/gi,
/<img[^\>]+src=['"]?([^"']+)["']?/gi,
/url\(\s*([^\(\)]+)\s*\)/gi,
/<script[^\>]+src=['"]([^"']+)["']/gi,
/\(\s*src=['"]([^"']+)["']/gi
]
function ResFetch(options){
this.filePaths = options.filePaths; //需要提取资源的文件完整路径
this.distPath = options.distPath || 'dist';
if(!/\/$/i.test(this.distPath)){
this.distPath += '/';
}
if(typeof this.filePaths != 'undefined' && this.filePaths.length>0){
for(var i=0; i < this.filePaths.length; i++){
var filePath = this.filePaths[i];
var content = this.resloveFile(this.filePaths[i]);
var finalPath = this.distPath + path.basename(filePath);
mkdir(path.dirname(finalPath));
fs.writeFileSync(finalPath , content);
}
}
}
/**
* 分析文件
* @filePath 需要分析的文件路径
* @
*/
ResFetch.prototype.resloveFile = function(filePath){
var _self = this;
var content = null;
try{
content = fs.readFileSync(filePath);
}catch(error){
return content;
}
if((!isHtml(filePath)) && (!isCss(filePath)) && (!isEjs(filePath))){
return content;
}
content = content.toString();
var basePath = path.dirname(filePath);
for(var i=0 ; i<patterns.length; i++){
var regex = patterns[i];
content = content.replace(regex , function(match , url , offset, string){
if(!isRemoteResource(url)){ //如果是远程资源则不需要处理
var fullPath = reslovePath(basePath , url);
var _content = _self.resloveFile(fullPath);
if(_content == null){
return match;
}
var converPath = converFilePath(fullPath , _content);
var finalPath = _self.distPath + converPath;
mkdir(path.dirname(finalPath));
fs.writeFileSync(finalPath , _content);
if(isCss(filePath)){
return match.replace(url , '../'+converPath);
}
return match.replace(url , converPath);
}else{
return match;
}
});
}
if(isHtml(filePath)){
content = this.requireReplace(basePath , content);
}
return content;
}
ResFetch.prototype.requireReplace = function(basePath , content){
var _self = this;
var contentBlocks = content.match(/requirejs.config(?:\r|\n|\s|\(\s*{)*paths(?:\r|\n|\s)*:(?:\r|\n|\s)*{([^}]*)}/gi); //得到paths的内容
if(!contentBlocks){
return content;
}
for(var i=0 ; i<contentBlocks.length ; i++){
var block = contentBlocks[i];
var arr = block.match(/["']+[^"']*["']+[\s]*:[\s]*["']+([^"']*)["']+/gi);
if(typeof arr !== 'undefined'){
for(var j=0 ; j<arr.length ; j++){
var c = arr[j]
var m = /["']+[^"']*["']+[\s]*:[\s]*(["']+([^"']*)["'])+/gi.exec(c);
var path1 = m[1]; //带引号的地址
var path2 = m[2]; //地址
if(isRemoteResource(path2)){
continue;
}
var fullPath = reslovePath(basePath , path2+'.js');
var _content = _self.resloveFile(fullPath);
if(_content == null){
return content;
}
var converPath = converFilePath(fullPath , _content);
var finalPath = _self.distPath + converPath;
mkdir(path.dirname(finalPath));
fs.writeFileSync(finalPath , _content);
content = content.replace(path1, '"'+path.dirname(converPath)+ '/' +path.basename(converPath,'.js')+'"');
}
}
}
return content;
}
function converFilePath(filePath , content){
var options = {
algorithm: 'md5',
length: 8
};
var hash = md5(content, options.algorithm, 'hex');
var suffix = hash.slice(0, options.length);
var extname = path.extname(filePath);
var fname = '';
if(extname == '.css'){
fname = 'styles/'+ path.basename(filePath , extname)+'_'+ suffix + extname;
}else if(extname == '.js'){
fname = 'scripts/'+ path.basename(filePath , extname)+'_'+ suffix + extname;
}else{
fname = 'images/'+ path.basename(filePath , extname)+'_'+ suffix + extname;
}
return fname;
}
/**
* 解析文件路径
* @param basePath 文件根路径
* @param filePath 文件路径
* @return 完整文件路径
*/
function reslovePath(basePath , filePath){
if(!/\/$/i.test(basePath)){
basePath += "/";
}
return basePath+filePath
}
function md5(content, algorithm, encoding) {
var hash = crypto.createHash(algorithm);
hash.update(content);
return hash.digest(encoding);
}
/**
* 判断是否是网络资源
*/
function isRemoteResource(url){
if(!/^http:\/\//i.test(url)){
return false
}
return true;
}
/**
* 判断是否是css资源文件
* @param url 文件路径
*/
function isCss(url){
if(path.extname(url) == '.css'){
return true
}
return false;
}
/**
* 判断是否是js文件
* @param url 文件
*/
function isJs(url){
if(path.extname(url) == '.js'){
return true;
}
return false;
}
function isHtml(url){
if(path.extname(url) == '.html' || path.extname(url) == '.htm'){
return true;
}
return false;
}
function isEjs(url){
if(path.extname(url) == '.ejs'){
return true;
}
return false;
}
var pathSeparatorRe = /[\/\\]/g;
/**
* 递归创建目录
* @param dirpath 目录路径
* @param mode 读取模式 默认0777
* @return
*/
function mkdir(dirpath, mode) {
if (mode == null) {
mode = parseInt('0777', 8) & (~process.umask());
}
dirpath.split(pathSeparatorRe).reduce(function(parts, part) {
parts += part + '/';
var subpath = path.resolve(parts);
if (!fs.existsSync(subpath)) {
try {
fs.mkdirSync(subpath, mode);
} catch(e) {
throw new Error('Unable to create directory "' + subpath + '" (Error code: ' + e.code + ').', e);
}
}
return parts;
}.bind(this), '');
};
module.exports = ResFetch;