-
Notifications
You must be signed in to change notification settings - Fork 0
Open
Description
webapp 中为了节省用户流量,经常会用到离线缓存,但是每次发布新版本,都需要添加新的缓存对象,比较麻烦,如是就用nodejs 配合 fis 写了个工具:
var fs = require('fs');
var crypto = require('crypto');
var path = require('path');
var defaultConfig = {
'prefix': '/',
'suffix': '.manifest',
'dest': './',
'cache': [],
'network': [
'*'
],
'fallback': [ ]
};
var manifest = [];
var _isArray = Array.isArray || function (obj) {
return Object.prototype.toString.call(obj) == '[object Array]';
};
var _isObject = function (obj) {
return obj === Object(obj);
};
var _isFunction = function (obj) {
return Object.prototype.toString.call(obj) === '[object Function]';
};
var _isUndefined = function (obj) {
return Object.prototype.toString.call(obj) === '[object Undefined]';
};
var _merge = function (baseObj, extendObj1, extendObj2/*, extnedObj3...*/) {
var argu = arguments;
var extendObj;
for (var i = 1; i < argu.length; i++) {
extendObj = argu[i];
for (var j in extendObj) {
if (_isArray(extendObj[j])) {
baseObj[j] = extendObj[j].concat();
} else if (_isObject(extendObj[j])) {
if (baseObj[j] && _isArray(baseObj[j])) {
baseObj[j] = _merge({}, extendObj[j]);
} else {
baseObj[j] = _merge({}, baseObj[j], extendObj[j]);
}
} else {
baseObj[j] = extendObj[j];
}
}
}
return baseObj;
};
var _searchInConfig = function (cacheList, cacheName) {
var key = null;
for (var name in cacheList) {
if (name == cacheName) {
key = name;
}
}
return key;
}
var _getName = function (cacheList, cacheName) {
var key = null;
for (var name in cacheList) {
if (name == cacheName) {
key = cacheList[name];
}
}
//console.log(key)
return key;
};
var _mergeArray = function (origin, list) {
for (var i = 0, item; item = list[i]; i++) {
if (origin.indexOf(item) === -1) {
origin.push(item);
}
}
}
var _isExit = function (array, item) {
if (array.length < 1) {
return;
}
var flag = false;
for (var i = 0, len = array.length; i < len; i++) {
if (array[i] == item) {
flag = true;
}
}
return flag;
};
var _pickUpScripts = function (html) {
var html = html.replace(/\r\n/, '\n')
var regex = /<script\s+.*?src="?([^"]+)"?[^>]+>/gi;
// html.match(regex)
// console.log(RegExp.$1)
var scripts = [];
html.replace(regex, function (m, ul) {
if (ul.indexOf('?noCache') == -1 && !_isExit(scripts, ul)) {
scripts.push(ul);
}
})
return scripts;
};
var _pickUpStyles = function (html) {
//var html = html.replace(/\r\n/,'\n')
var regex = /<link\s+.*?href="?([^"]+)"?[^>]+>/gi;
//var regex = /<link\s+(?:[^>]+\s+)*type=(?:"\s*|'\s*)?text\/css[^>]*>/ig
var attReg = /rel="?\bstylesheet\b"?/i;
var styles = [];
html.replace(regex, function (m, ul) {
if (attReg.test(m) && ul.indexOf('?noCache') == -1 && !_isExit(styles, ul)) {
styles.push(ul);
}
})
return styles;
};
var _pickUpLocalStyles = function (html) {
//var html = html.replace(/\r\n/,'\n')
var regex = /<link\s+.*?href="?([^"]+)"?[^>]+>/gi;
//var regex = /<link\s+(?:[^>]+\s+)*type=(?:"\s*|'\s*)?text\/css[^>]*>/ig
var attReg = /rel="?\bstylesheet\b"?/i;
var styles = [];
html.replace(regex, function (m, ul) {
//console.log(ul);
if (/(http:\/\/|https:\/\/)((\w|=|\?|\.|\/|&|-)+)/g.test(ul)) {
return;
}
if (attReg.test(m) && ul.indexOf('?noCache') == -1 && !_isExit(styles, ul)) {
styles.push(ul);
}
})
return styles;
};
var _pickupImg = function (content) {
var html = content.replace(/\r\n/, '\n')
var regex = /<img\s+.*?src="?([^"]+)"?[^>]+>/gi;
var images = [];
html.replace(regex, function (m, ul) {
if (ul.indexOf('?noCache') == -1 && !_isExit(images, ul)) {
images.push(ul);
}
})
return images;
}
var _pickupCssImg = function (content) {
var html = content.replace(/\r\n/, '\n')
var regex = /url\(["']?([^"')]+)["']?\)/gi
var images = [];
html.replace(regex, function (m, ul) {
if (ul.indexOf('?noCache') == -1 && !_isExit(images, ul)) {
images.push(ul);
}
})
return images;
}
var mkdirsSync = function (dirpath, mode) {
// console.log(dirpath);
dirpath = path.resolve(dirpath);
// console.log(dirpath);
if (fs.existsSync(dirpath)) {
return;
}
var dirs = dirpath.split(path.sep);
// console.log(dirs);
var dir = '';
for (var i = 0; i < dirs.length; i++) {
dir += path.join(dirs[i], path.sep);
// console.log(dir);
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, mode);
}
}
};
var writeFileSync = function (filenName, content, overwrite) {
mkdirsSync(path.dirname(filenName));
if (fs.existsSync(filenName)) {
if (!overwrite) {
throw 'File ' + filenName + ' is exists.';
} else {
fs.unlinkSync(filenName);
}
}
fs.writeFileSync(filenName, content);
}
var _writeManifest = function (dest, list, config) {
var record = [];
record.push('CACHE MANIFEST');
record.push('#' + new Date);
record.push('CACHE:');
record = record.concat(list);
record.push('NETWORK:');
record = record.concat(config.network);
record.push('FALLBACK:');
record = record.concat(config.fallback);
var content = record.join('\n');
// var tempname = config.dest + + name;
// var filename = tempname + config.suffix;
writeFileSync(dest, content, true);
}
var imgFile = {};
var _getCssImg = function (ret, conf, settings, opt) {
var options = fis.config.get('manifest');
var config = _merge({}, defaultConfig, options);
var cache = config.cache;
var manifestName;
fis.util.map(ret.src, function (subpath, file) {
if (file.ext == '.html' && (manifestName = _searchInConfig(cache, file.id)) != null) {
var list = [];
//console.log()
var content = fs.readFileSync('.' + file.subpath).toString();
var css = _pickUpLocalStyles(content);
for (var i = 0, len = css.length; i < len; i++) {
var c = fs.readFileSync('./' + file.subdirname + '/' + css[i]).toString();
//var img = ;
//console.log(img)
var img = _pickupCssImg(c);
for (var j in img) {
if (/^(\.\.).*/gi.test(img[j])) {
var name = img[j].substr(2);
if (!_isExit(list, name)) {
list.push(file.subdirname + name);
}
} else {
var name = img[j];
if (!_isExit(list, name)) {
list.push(name);
}
}
}
}
imgFile[manifestName] = list;
}
})
//console.log(imgFile)
return imgFile;
}
var _getMd5 = function (imgList, ret, conf, settings, opt) {
var list = [];
//console.log(imgList)
fis.util.map(ret.src, function (subpath, file) {
if (/^\.(jpg|png|gif)$/gi.test(file.ext)) {
if (_isExit(imgList, file.subpath)) {
list.push(file.getUrl(opt.md5, opt.domain));
}
}
})
//console.log(list)
return list;
}
exports.generator = function (ret, conf, settings, opt) {
var options = fis.config.get('manifest');
var config = _merge({}, defaultConfig, options);
var cache = config.cache;
var manifestName;
//var imgFile = {};
var cssImg = _getCssImg(ret, conf, settings, opt);
fis.util.map(ret.src, function (subpath, file) {
if (file.ext == '.html' && (manifestName = _searchInConfig(cache, file.id)) != null) {
//var content = file.getContent();
var rlist = new Array();
var html = file.getContent();
//console.log(html);
//rlist .push[html];
var styles = _pickUpStyles(html);
_mergeArray(rlist, styles);
var scripts = _pickUpScripts(html);
_mergeArray(rlist, scripts);
var htmlImages = _pickupImg(html);
_mergeArray(rlist, htmlImages);
var imgIncss = _getMd5(cssImg[file.id], ret, conf, settings, opt);
_mergeArray(rlist, imgIncss);
var name = _getName(cache, file.id);
var url = name + config.suffix;
var attr = ' manifest="' + url + '" '
html = html.replace(/(<html)([^>]*>)/i, '$1' + attr + '$2');
file.setContent(html);
var dest = config.dest + '/' + file.subdirname + '/' + name + config.suffix;
_writeManifest(dest, rlist, config);
// var content = fs.readFileSync('./' + file.basename).toString();
// var css = _pickUpStyles(content);
// console.log(css);
}
// }else if(/^\.(jpg|png|gif)$/.test(file.ext)){
// console.log(file)
// }
})
}
配置
fis.config.set('modules.postpackager', [concat, unline.generator]);
fis.config.set('manifest', {
'dest': '../build/website',
'suffix': '.manifest',
'cache': {
'lucky/index.html': ['lucky'],
'happy2014/index.html': ['happy2014'],
'top2013/index.html': ['top2013-index'],
'top2013/singer.html': ['singer'],
'weixin/index.html': ['weixin-index'],
'index.html': ['index']
}
});
Metadata
Metadata
Assignees
Labels
No labels