diff --git a/hot/dev-server.js b/hot/dev-server.js index ef0874563..1ba27a255 100644 --- a/hot/dev-server.js +++ b/hot/dev-server.js @@ -1,22 +1,31 @@ if(module.hot) { + function check() { + module.hot.check(function(err, updatedModules) { + if(err) { + if(module.hot.status() in {abort:1,fail:1}) + window.location.reload(); + else + console.warn("Update failed: " + err); + return; + } + + if(!updatedModules) + return console.log("No Update found."); + + check(); + + if(!updatedModules || updatedModules.length === 0) + return console.log("Update is empty."); + console.log("Updated modules:"); + updatedModules.forEach(function(moduleId) { + console.log(" - " + moduleId); + }); + + }); + } window.onmessage = function(event) { if(event.data === "webpackHotUpdate" && module.hot.status() === "idle") { - module.hot.check(function(err, updatedModules) { - if(err) { - if(module.hot.status() in {abort:1,fail:1}) - window.location.reload(); - else - console.warn("Update failed: " + err); - return; - } - - if(!updatedModules || updatedModules.length === 0) - return console.log("Update is empty."); - console.log("Updated modules:"); - updatedModules.forEach(function(moduleId) { - console.log(" - " + moduleId); - }); - }); + check(); } }; } \ No newline at end of file diff --git a/lib/HotModuleReplacementPlugin.js b/lib/HotModuleReplacementPlugin.js index 813f2b6df..d9a5ad5c0 100644 --- a/lib/HotModuleReplacementPlugin.js +++ b/lib/HotModuleReplacementPlugin.js @@ -93,6 +93,12 @@ HotModuleReplacementPlugin.prototype.apply = function(compiler) { var mainTemplate = compilation.mainTemplate; compilation.mainTemplate = Object.create(mainTemplate); + + compilation.mainTemplate.updateHash = function(hash) { + hash.update(compilation.records.hash + ""); + mainTemplate.updateHash(hash); + }; + compilation.mainTemplate.renderRequireFunctionForModule = function(hash, chunk, varModuleId) { return "hotCreateRequire(" + varModuleId + ")"; }; @@ -164,49 +170,53 @@ var hotInitCode = function() { hotUpdate[moduleId] = false; } hotUpdateNewHash = newHash; - if(--hotWaitingFiles === 0) { - var outdatedDependencies = hotUpdateOutdatedDependencies = {}; - var outdatedModules = hotUpdateOutdatedModules = Object.keys(hotUpdate).slice(); - var queue = outdatedModules.slice(); - while(queue.length > 0) { - var moduleId = queue.pop(); - var module = installedModules[moduleId]; - if(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); - } - } + if(--hotWaitingFiles === 0 && hotChunksLoading === 0) { + hotUpdateDownloaded(); + } + } - hotSetStatus("ready"); - if(hotApplyOnUpdate) { - hotApply(hotCallback); - } else { - hotCallback(null, outdatedModules); + function hotUpdateDownloaded() { + var outdatedDependencies = hotUpdateOutdatedDependencies = {}; + var outdatedModules = hotUpdateOutdatedModules = Object.keys(hotUpdate).slice(); + var queue = outdatedModules.slice(); + while(queue.length > 0) { + var moduleId = queue.pop(); + var module = installedModules[moduleId]; + if(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); } } @@ -225,9 +235,19 @@ var hotInitCode = function() { return $require$(request); }; fn.e = function(chunkId, callback) { - if(hotStatus !== "idle") throw new Error("TODO: chunk loading while updating"); + if(hotStatus === "ready") throw new Error("Cannot load chunks when update is ready"); + hotChunksLoading++; $require$.e(chunkId, function() { callback(fn); + hotChunksLoading--; + if(hotStatus === "prepare") { + if(!hotWaitingFilesMap[chunkId]) { + hotDownloadUpdateChunk(chunkId); + } + if(hotChunksLoading === 0 && hotWaitingFiles === 0) { + hotUpdateDownloaded(); + } + } }); } fn.cache = $require$.cache; @@ -298,6 +318,8 @@ var hotInitCode = function() { } var hotWaitingFiles = 0; + var hotChunksLoading = 0; + var hotWaitingFilesMap = {}; var hotCallback; function hotCheck(callback) { if(hotStatus !== "idle") throw new Error("check() is only allowed in idle status"); @@ -318,27 +340,32 @@ var hotInitCode = function() { if(request.status !== 200 && request.status !== 304) { hotSetStatus("idle"); - callback(null, []); + callback(null, null); } else { + hotWaitingFilesMap = {}; hotSetStatus("prepare"); hotCallback = callback || function(err) { if(err) throw err }; hotUpdate = {}; var hash = hotCurrentHash; /*foreachInstalledChunks*/ { - hotWaitingFiles++; - var head = document.getElementsByTagName('head')[0]; - var script = document.createElement('script'); - script.type = 'text/javascript'; - script.charset = 'utf-8'; - script.src = modules.c + $hotChunkFilename$; - head.appendChild(script); + hotDownloadUpdateChunk(chunkId); } } }; } + function hotDownloadUpdateChunk(chunkId) { + hotWaitingFiles++; + var head = document.getElementsByTagName('head')[0]; + var script = document.createElement('script'); + script.type = 'text/javascript'; + script.charset = 'utf-8'; + script.src = modules.c + $hotChunkFilename$; + head.appendChild(script); + hotWaitingFilesMap[chunkId] = true; + } var hotUpdate, hotUpdateOutdatedDependencies, hotUpdateOutdatedModules, hotUpdateNewHash; diff --git a/test/hotPlayground/addStyle.js b/test/hotPlayground/addStyle.js new file mode 100644 index 000000000..51c1d0f2c --- /dev/null +++ b/test/hotPlayground/addStyle.js @@ -0,0 +1,18 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +module.exports = function(cssCode) { + var styleElement = document.createElement("style"); + styleElement.type = "text/css"; + if (styleElement.styleSheet) { + styleElement.styleSheet.cssText = cssCode; + } else { + styleElement.appendChild(document.createTextNode(cssCode)); + } + var head = document.getElementsByTagName("head")[0]; + head.appendChild(styleElement); + return function() { + head.removeChild(styleElement); + }; +} \ No newline at end of file diff --git a/test/hotPlayground/index.js b/test/hotPlayground/index.js index cb2fbd61e..f60984277 100644 --- a/test/hotPlayground/index.js +++ b/test/hotPlayground/index.js @@ -38,6 +38,8 @@ window.onload = function() { require("./style.js"); + require("bundle!./style2.js"); + if(module.hot) { module.hot.accept("./html.js", function() { diff --git a/test/hotPlayground/style.js b/test/hotPlayground/style.js index 2df7e4ec0..5c0fd4be5 100644 --- a/test/hotPlayground/style.js +++ b/test/hotPlayground/style.js @@ -1,22 +1,11 @@ // This file can update, because it accept itself. // A dispose handler removes the old