UNPKG

feather-postpackager-map-before

Version:
398 lines (319 loc) 11.4 kB
var require, define; (function(window, document, undefined){ //判断是否为数组 function isArray(array){ return Object.prototype.toString.call(array) == '[object Array]'; } //转换数组 function makeArray(array){ return array ? isArray(array) ? array : [array] : []; } //简单迭代数组 function each(obj, callback){ if(isArray(obj)){ for(var i = 0; i < obj.length; i++) callback(obj[i], i); }else{ for(var i in obj) callback(obj[i], i); } } //查找元素是否在数组中 function inArray(array, item){ array = makeArray(array); if(array.indexOf){ return array.indexOf(item) > -1; }else{ for( var i = 0; i < array.length; i++){ if(array[i] == item) return true; } return false; } } //是否函数 function isFunction(callback){ return typeof callback == 'function'; } //模块主类 //modulename 模块名 //callback 执行的函数 //depth 依赖的js文件 ==> 可为数组 function Module(modulename, callback, depth, use){ if(Module.cache[modulename]){ console && console.log('module ' + modulename + ' is exists!'); return; } var self = this; //模块名 self.modulename = modulename; //回调 self.callback = callback; //获取真实的依赖文件列表 self.depths = Module.getDeps(depth); //所需要加载的依赖的模块数 self.needLoadDepth = self.depths.length; //当模块所有依赖以及本身全部加载完后, 所通知的主模块列表 self.notices = (Module.noticesCache[modulename] || {}).notices || []; //公开出的成员 self.exports = {}; //是否执行过,延迟执行的标志 self.execed = false; //是否是require.async self.use = use; self.init(); } Module.prototype = { init: function(){ var self = this; //当模块类被实例话后表示该模块本身的js已经被成功加载 删除loading表中自身所对应的js Module.cache[self.modulename] = self; //如果没有依赖 直接complete self.needLoadDepth ? self.loadDepths() : self.complete(); }, //加载依赖 loadDepths: function(){ var self = this; self.status = Module.loadStatus.LOADDEPTH; each(self.depths, function(modulename){ Module.load(modulename, self.modulename); }); }, //接受通知 //此处当依赖本模块的模块加载完后 会执行 receiveNotice: function(){ if(!--this.needLoadDepth) { this.complete(); } }, //当本身加载完后 通知所依赖本模块的模块 noticeModule: function(notice){ var self = this; //手动通知某个模块 if(notice){ //如果该模块自己的依赖还没加载完,将需要通知的模块添加至通知队列 if(self.status != Module.loadStatus.LOADED){ return self.notices.push(notice); } //通知所依赖本模块的模块 Module.cache[notice].receiveNotice(); }else{ //通知所有模块 each(self.notices, function(item){ Module.cache[item].receiveNotice(); }); self.notices.length = 0; } }, //完成所有依赖加载后 执行回调 complete: function(){ var self = this; self.status = Module.loadStatus.LOADED; //如果是require.async 立即执行 self.use && self.exec(); self.noticeModule(); }, exec: function(){ var self = this; if(self.execed) return; self.execed = true; if(isFunction(self.callback)){ var exports; if(exports = self.callback.call(window, Module.require, self.exports, self)){ self.exports = exports; } } } }; //模块的加载状态 Module.loadStatus = { LOADDEPTH: 1, //正在努力加载依赖文件 LOADED: 2 //已全部加载完毕 }; Module.cache = {}; //当模块的js文件加载完后 会存放在此处 不管依赖是否加载完 这里是存放实例module Module.noticesCache = {}; //缓存每个模块所需要通知被依赖模块的实例 Module.loadingSource = {}; //正在加载中的资源 Module.loadedSource = {}; //已经加载的资源 Module.mapSource = {}; //加载一个模块的js文件 Module.load = function(modulename, notice){ var cache, module; //如果该路径已经加载,则表示模块已经初始化,通知依赖本模块的模块即可 if(cache = Module.cache[modulename]) return cache.noticeModule(notice); //如果该路径没有初始化,即没有new,也就是没有加载完毕,则缓存通知模块 if(module = Module.noticesCache[modulename]) return module.notices.push(notice); //如果没有缓存,则创建 Module.noticesCache[modulename] = {notices: [notice]}; //获取该模块的全路径 var realpath = Module.getRealPath(modulename), map; //模块有可能被合并至一个大文件中,即一个文件中可能包含多个模块,或者非模块。 if(!(map = Module.mapSource[realpath])){ map = Module.mapSource[realpath] = []; } //将该模块放置map中,等待之后的通知 map.push(modulename); //如果文件没有加载 if(!Module.loadingSource[realpath]){ Module._load(realpath, modulename); }else if(Module.loadedSource[realpath]){ //如果加载完毕,尝试初始化。 Module.init(modulename); } }; Module._load = function(realpath, modulename){ Module.loadingSource[realpath] = 1; var isCss = /\.css$/.test(modulename), isLoaded = 0, isOldWebKit = +navigator.userAgent.replace(/.*(?:Apple|Android)WebKit\/(\d+).*/, "$1") < 536, type = isCss ? 'link' : 'script', source = document.createElement(type), supportOnload = 'onload' in source; //支持css加载 if(isCss){ source.rel = 'stylesheet'; source.type = 'text/css'; source.href = realpath; }else{ source.type = 'text/javascript'; source.src = realpath; } each(require.config.attrs || {}, function(v, k){ if(isFunction(v)){ v = v({ type: type, realpath: realpath, modulename: modulename }); } v !== undefined && source.setAttribute(k, v); }); function onload(){ //这边放置css中存在@import import后会多次触发onload事件 if(isLoaded) return; if(!source.readyState || /loaded|complete/.test(source.readyState)){ source.onload = source.onerror = source.onreadystatechange = null; //已加载 Module.loadedSource[realpath] = isLoaded = 1; //手动触发已加载方法,防止文件是非模块,require.async之类,导致无法通知依赖模块执行,也有可能是多个文件合并,需要挨个通知 Module.loaded(realpath); } } source.onload = source.onerror = source.onreadystatechange = onload; source.charset = require.config.charset; document.getElementsByTagName('head')[0].appendChild(source); //有些老版本浏览器不支持对css的onload事件,需检查css的sheet属性是否存在,如果加载完后,此属性会出现 if(isCss && (isOldWebKit || !supportOnload)){ var id = setTimeout(function(){ if(source.sheet){ clearTimeout(id); return onload(); } setTimeout(arguments.callee); }); } }; //此方法,用于兼容多个文件合并,或者非模块文件的加载,非模块文件不会define而导致的无法通知依赖模块的情况 Module.loaded = function(path){ var map = Module.mapSource[path]; each(map, function(p){ Module.init(p); }); map.length = 0; }; //尝试初始化 Module.init = function(path){ !Module.cache[path] && new Module(path); }; //require Module.require = function(modulename){ var cache = Module.cache[Module.getModuleName(modulename)]; cache.exec(); return cache.exports; }; //或者模块真实的路径 Module.getModuleName = function(path){ if(/:\/\//.test(path)) return path; var config = require.config, baseurl = config.baseurl || ''; each(config.rules || [], function(item){ path = path.replace(item[0], item[1]); }); if(baseurl && path.charAt(0) != '/') path = baseurl.replace(/\/+$/, '') + '/' + path; return path.replace(/\/+/g, '/'); }; //获取全路径 Module.getRealPath = function(path){ var config = require.config, map = config.map || {}, domain = config.domain || ''; for(var i in map){ if(map.hasOwnProperty(i) && inArray(map[i], path)){ path = i; break; } } return !/:\/\//.test(path) ? domain + path : path; }; //获取依赖 Module.getDeps = function(deps){ var d = []; each(makeArray(deps), function(dep){ dep = Module.getModuleName(dep); d.push(dep); d.push.apply(d, Module.getDeps(require.config.deps[dep])); }); return d; }; var requireid = 0; //require, 可直接获取已加载完的模块 require = Module.require; require.version = '1.0.2'; require.config = { domain: '', baseurl: '', rules: [], charset: 'utf-8', deps: {}, map: {}, attrs: {} }; require.async = function(paths, callback){ new Module('_r_' + requireid++, function(){ var depthmodules = []; each(makeArray(paths), function(path){ depthmodules.push(Module.require(path)); }); isFunction(callback) && callback.apply(window, depthmodules); }, paths, true); }; require.mergeConfig = function(config){ var _config = require.config; each(config, function(c, i){ var tmp = _config[i]; if(i == 'map'){ each(c, function(map, name){ var yMap = tmp[name]; if(!yMap){ yMap = map; }else{ each(makeArray(map), function(item){ !inArray(yMap, item) && yMap.push(item); }); } tmp[name] = yMap; }); }else if(i == 'deps'){ each(c, function(dep, name){ tmp[name] = dep; }); }else if(isArray(c)){ tmp.push.apply(tmp, c); }else{ tmp = c; } _config[i] = tmp; }); }; //define方法 define = function(modulename, callback, depth){ modulename = Module.getModuleName(modulename); depth = depth || require.config.deps[modulename]; new Module(modulename, callback, depth); }; })(window, document);