UNPKG

mya-command-release

Version:

mya release command.

196 lines (172 loc) 5.93 kB
/* runtime plugin for mya */ (function(global) { function HotModuleReplacementPlugin(options) { this.require = options.require; this.define = options.define; this.factoryMap = options.factoryMap; this.modulesMap = options.modulesMap; this.hotUpdateMap = {}; this.selfAcceptedMap = {}; this.data = {}; } HotModuleReplacementPlugin.prototype = { apply: function() { }, accept: function(id, callback) { if (typeof callback === 'undefined') { // module.hot.accpet(id) this.selfAcceptedMap[id] = true; } else { this.hotUpdateMap[id] = callback || function () {}; } }, update: function(id, factory) { // remove module from cache: ensure get updated moudle when require delete this.modulesMap[id]; // 重新定义模块 this.define(id, factory); // call accpet handlers this.hotUpdateMap[id] && this.hotUpdateMap[id]() // self accepted // if (this.selfAcceptedMap[id]) { // this.require(id) // } }, // 重新定义模块,用于获取新的引用 reDefineModule: function(id) { id = id.replace(/\.js$/i, ''); delete this.modulesMap[id]; var factory = this.factoryMap[id]; if (factory) { // 重新定义模块 this.define(id, factory) } }, depose: function() { // do nothings } } global.HotModuleReplacementPlugin = HotModuleReplacementPlugin; })(window); /* start websocket connection */ (function(global) { var socket = io.connect('http://{{hostname}}:{{port}}'); var updatedModules = {}; function log() { var args = [].slice.call(arguments); args.unshift('[hmr]'); console.log.apply(console, args); } socket.on('establish', function (data) { global.resMap = data.map; // __M.require.resourceMap(data.map); log('Hmr server has started!'); }); socket.on('update:js', function(data) { // log('update: ', data) var script = document.createElement('script'); script.src = data.uri; document.head.appendChild(script); script.onload = function() { if (data.noReload) { __M.require(data.moduleId); } else { updateFromSelf(data.moduleId); } } }); socket.on('update:css', function(data) { // log(data) // var link = document.createElement('link'); // link.href = data.uri; // link.rel = 'stylesheet'; // link.type = 'text/css'; // document.head.appendChild(link); var style = document.querySelectorAll('[data-id="' + data.moduleId + '"]'); if (style.length) { updateStyleTag(style[0], data.content); } else { var script = document.head.querySelectorAll('script') var style = document.createElement('style'); style.setAttribute('data-id', data.moduleId); updateStyleTag(style, data.content); if (script.length) { document.head.insertBefore(style, script[0]); } else { document.head.appendChild(style); } } }); socket.on('update:map', function(data) { global.resMap = data.map; // __M.require.resourceMap(data.map); log('resource map has updated!'); }); socket.on('update:reload', function(data) { reload(); }); function updateStyleTag(style, content) { try { style.innerHTML = content; } catch(e) { style.styleSheet.cssText = content; } } function getModuleId(id) { return id.replace(/\.js$/i, ''); } function getParentModule(map, id) { var res = map.res; return Object.keys(res).filter(resId => res[resId]['deps'] && ~res[resId]['deps'].indexOf(id)); } // hack for vue // todo: 精准判断 function isTopApp(id, parents) { // return /page\/(\S+\/)*(App\.vue|app\.vue|index\.js)$/.test(id) // return /page\/(\S+\/)*index\.js$/.test(id); return parents.length === 0; } function reload() { log('hmr update failed, page will reload!'); location.reload(); } // todo: 去重 function updateFromSelf(id) { var parents = getParentModule(global.resMap, id); // 清除缓存 __M.hot.data[id] = false; // 顶层模块 if (isTopApp(id, parents)) { log('require: ', id); try { __M.require(id); } catch (e) { var match = typeof e === 'string' && e.match(/\[ModJS\] Cannot find module `(\S+?)`/); if (match) { // todo: 后引入的模块暂时无法更新 // __M.require.async(match[1], function() { // __M.require(id); // }); // return ; return reload(); } console.error(e); } return ; } // 非顶层模块 parents.forEach(resId => { // 当前页面用到的模块 if (__M.hot.factoryMap[getModuleId(resId)]) { log('redefine: ', resId) __M.hot.reDefineModule(resId); } }); parents.forEach(resId => { // 当前页面用到的模块 if (__M.hot.factoryMap[getModuleId(resId)]) { log('updateFromSelf: ', resId) updateFromSelf(resId); } }); } })(window);