Skip to content

fis 生成mainfest #6

@superquestion

Description

@superquestion

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

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions