diff --git a/lib/HotModuleReplacementPlugin.js b/lib/HotModuleReplacementPlugin.js index b0a3a77fb..84fc6444b 100644 --- a/lib/HotModuleReplacementPlugin.js +++ b/lib/HotModuleReplacementPlugin.js @@ -181,53 +181,6 @@ var hotInitCode = function() { } } - function hotUpdateDownloaded() { - var outdatedDependencies = hotUpdateOutdatedDependencies = {}; - var outdatedModules = hotUpdateOutdatedModules = Object.keys(hotUpdate).map(function(id) { - return +id; - }); - var queue = outdatedModules.slice(); - while(queue.length > 0) { - var moduleId = queue.pop(); - var module = installedModules[moduleId]; - if(!module || module.hot._selfAccepted) - continue; - if(module.hot._selfDeclined) { - hotSetStatus("abort"); - return hotCallback(new Error("Aborted because of self decline: " + moduleId)); - } - if(moduleId === 0) { - hotSetStatus("abort"); - return hotCallback(new Error("Aborted because of bubbling")); - } - for(var i = 0; i < module.parents.length; i++) { - var parentId = module.parents[i]; - var parent = installedModules[parentId]; - if(parent.hot._declinedDependencies[moduleId]) { - hotSetStatus("abort"); - return hotCallback(new Error("Aborted because of declined dependency: " + moduleId + " in " + parentId)); - } - if(outdatedModules.indexOf(parentId) >= 0) continue; - if(parent.hot._acceptedDependencies[moduleId]) { - if(!outdatedDependencies[parentId]) outdatedDependencies[parentId] = []; - if(outdatedDependencies[parentId].indexOf(moduleId) >= 0) continue; - outdatedDependencies[parentId].push(moduleId); - continue; - } - delete outdatedDependencies[parentId]; - outdatedModules.push(parentId); - queue.push(parentId); - } - } - - hotSetStatus("ready"); - if(hotApplyOnUpdate) { - hotApply(hotCallback); - } else { - hotCallback(null, outdatedModules); - } - } - var hotApplyOnUpdate = true; var hotCurrentHash = $hash$; var hotCurrentModuleData = {}; @@ -244,11 +197,12 @@ var hotInitCode = function() { return $require$(request); }; fn.e = function(chunkId, callback) { - if(hotStatus === "ready") throw new Error("Cannot load chunks when update is ready"); + if(hotStatus === "ready") + hotSetStatus("prepare"); hotChunksLoading++; $require$.e(chunkId, function() { try { - callback(fn); + callback.call(null, fn); } catch(e) { finishChunkLoading(); throw e; @@ -312,6 +266,9 @@ var hotInitCode = function() { // Management API check: hotCheck, apply: hotApply, + setApplyOnUpdate: function(applyOnUpdate) { + hotApplyOnUpdate = applyOnUpdate; + }, status: function(l) { if(!l) return hotStatus; hotStatusHandlers.push(l); @@ -319,7 +276,7 @@ var hotInitCode = function() { addStatusHandler: function(l) { hotStatusHandlers.push(l); }, - removeDisposeHandler: function(l) { + removeStatusHandler: function(l) { var idx = hotStatusHandlers.indexOf(l); if(idx >= 0) hotStatusHandlers.splice(idx, 1); } @@ -329,15 +286,23 @@ var hotInitCode = function() { var hotStatusHandlers = []; var hotStatus = "idle"; + function hotSetStatus(newStatus) { + var oldStatus = hotStatus; hotStatus = newStatus; - // TODO notify listeners + for(var i = 0; i < hotStatusHandlers.length; i++) + hotStatusHandlers[i].call(null, newStatus); } + // while downloading var hotWaitingFiles = 0; var hotChunksLoading = 0; var hotWaitingFilesMap = {}; var hotCallback; + + // The update info + var hotUpdate, hotUpdateNewHash; + function hotCheck(callback) { callback = callback || function(err) { if(err) throw err }; if(hotStatus !== "idle") throw new Error("check() is only allowed in idle status"); @@ -374,6 +339,7 @@ var hotInitCode = function() { } }; } + function hotDownloadUpdateChunk(chunkId) { hotWaitingFiles++; var head = document.getElementsByTagName('head')[0]; @@ -385,11 +351,62 @@ var hotInitCode = function() { hotWaitingFilesMap[chunkId] = true; } - var hotUpdate, hotUpdateOutdatedDependencies, hotUpdateOutdatedModules, hotUpdateNewHash; + function hotUpdateDownloaded() { + hotSetStatus("ready"); + var callback = hotCallback; + hotCallback = null; + if(!callback) return; + if(hotApplyOnUpdate) { + hotApply(callback); + } else { + var outdatedModules = Object.keys(hotUpdate).map(function(id) { + return +id; + }); + callback(null, outdatedModules); + } + } function hotApply(callback) { - var outdatedModules = hotUpdateOutdatedModules; - var outdatedDependencies = hotUpdateOutdatedDependencies; + callback = callback || function(err) { if(err) throw err }; + if(hotStatus !== "ready") throw new Error("apply() is only allowed in ready status"); + var outdatedDependencies = {}; + var outdatedModules = Object.keys(hotUpdate).map(function(id) { + return +id; + }); + var queue = outdatedModules.slice(); + while(queue.length > 0) { + var moduleId = queue.pop(); + var module = installedModules[moduleId]; + if(!module || module.hot._selfAccepted) + continue; + if(module.hot._selfDeclined) { + hotSetStatus("abort"); + return callback(new Error("Aborted because of self decline: " + moduleId)); + } + if(moduleId === 0) { + hotSetStatus("abort"); + return callback(new Error("Aborted because of bubbling")); + } + for(var i = 0; i < module.parents.length; i++) { + var parentId = module.parents[i]; + var parent = installedModules[parentId]; + if(parent.hot._declinedDependencies[moduleId]) { + hotSetStatus("abort"); + return callback(new Error("Aborted because of declined dependency: " + moduleId + " in " + parentId)); + } + if(outdatedModules.indexOf(parentId) >= 0) continue; + if(parent.hot._acceptedDependencies[moduleId]) { + if(!outdatedDependencies[parentId]) outdatedDependencies[parentId] = []; + if(outdatedDependencies[parentId].indexOf(moduleId) >= 0) continue; + outdatedDependencies[parentId].push(moduleId); + continue; + } + delete outdatedDependencies[parentId]; + outdatedModules.push(parentId); + queue.push(parentId); + } + } + var outdatedSelfAcceptedModules = outdatedModules.filter(function(moduleId) { return installedModules[moduleId] && installedModules[moduleId].hot._selfAccepted; });