Skip to content

Commit

Permalink
hot module replacement with code splitting webpack#26
Browse files Browse the repository at this point in the history
  • Loading branch information
sokra committed Jun 19, 2013
1 parent 8b23010 commit d8fc847
Show file tree
Hide file tree
Showing 6 changed files with 133 additions and 77 deletions.
41 changes: 25 additions & 16 deletions hot/dev-server.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,31 @@
if(module.hot) {
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;
}
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);
});
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") {
check();
}
};
}
121 changes: 74 additions & 47 deletions lib/HotModuleReplacementPlugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 + ")";
};
Expand Down Expand Up @@ -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) {
if(--hotWaitingFiles === 0 && hotChunksLoading === 0) {
hotUpdateDownloaded();
}
}

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 bubbling"));
return hotCallback(new Error("Aborted because of declined dependency: " + moduleId + " in " + parentId));
}
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(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);
}
hotSetStatus("ready");
if(hotApplyOnUpdate) {
hotApply(hotCallback);
} else {
hotCallback(null, outdatedModules);
}
}

Expand All @@ -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;
Expand Down Expand Up @@ -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");
Expand All @@ -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;

Expand Down
18 changes: 18 additions & 0 deletions test/hotPlayground/addStyle.js
Original file line number Diff line number Diff line change
@@ -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);
};
}
2 changes: 2 additions & 0 deletions test/hotPlayground/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ window.onload = function() {

require("./style.js");

require("bundle!./style2.js");

if(module.hot) {

module.hot.accept("./html.js", function() {
Expand Down
17 changes: 3 additions & 14 deletions test/hotPlayground/style.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,11 @@
// This file can update, because it accept itself.
// A dispose handler removes the old <style> element.

var cssCode = "body { background: green; }";
var addStyle = require("./addStyle");

var head = document.getElementsByTagName("head")[0];

var styleElement = document.createElement("style");
styleElement.type = "text/css";
if (styleElement.styleSheet) {
styleElement.styleSheet.cssText = cssCode;
} else {
styleElement.appendChild(document.createTextNode(cssCode));
}
head.appendChild(styleElement);
var dispose = addStyle("body { background: green; }");

if(module.hot) {
module.hot.accept();
module.hot.dispose(function() {
head.removeChild(styleElement);
});
module.hot.dispose(dispose);
}
11 changes: 11 additions & 0 deletions test/hotPlayground/style2.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// This file can update, because it accept itself.
// A dispose handler removes the old <style> element.

var addStyle = require("./addStyle");

var dispose = addStyle("body { color: blue; }");

if(module.hot) {
module.hot.accept();
module.hot.dispose(dispose);
}

0 comments on commit d8fc847

Please sign in to comment.