hot module replacement with code splitting #26

This commit is contained in:
Tobias Koppers 2013-06-19 16:09:46 +02:00
parent 8b2301056d
commit d8fc8472f6
6 changed files with 136 additions and 80 deletions

View File

@ -1,6 +1,5 @@
if(module.hot) { if(module.hot) {
window.onmessage = function(event) { function check() {
if(event.data === "webpackHotUpdate" && module.hot.status() === "idle") {
module.hot.check(function(err, updatedModules) { module.hot.check(function(err, updatedModules) {
if(err) { if(err) {
if(module.hot.status() in {abort:1,fail:1}) if(module.hot.status() in {abort:1,fail:1})
@ -10,13 +9,23 @@ if(module.hot) {
return; return;
} }
if(!updatedModules)
return console.log("No Update found.");
check();
if(!updatedModules || updatedModules.length === 0) if(!updatedModules || updatedModules.length === 0)
return console.log("Update is empty."); return console.log("Update is empty.");
console.log("Updated modules:"); console.log("Updated modules:");
updatedModules.forEach(function(moduleId) { updatedModules.forEach(function(moduleId) {
console.log(" - " + moduleId); console.log(" - " + moduleId);
}); });
}); });
} }
window.onmessage = function(event) {
if(event.data === "webpackHotUpdate" && module.hot.status() === "idle") {
check();
}
}; };
} }

View File

@ -93,6 +93,12 @@ HotModuleReplacementPlugin.prototype.apply = function(compiler) {
var mainTemplate = compilation.mainTemplate; var mainTemplate = compilation.mainTemplate;
compilation.mainTemplate = Object.create(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) { compilation.mainTemplate.renderRequireFunctionForModule = function(hash, chunk, varModuleId) {
return "hotCreateRequire(" + varModuleId + ")"; return "hotCreateRequire(" + varModuleId + ")";
}; };
@ -164,7 +170,12 @@ var hotInitCode = function() {
hotUpdate[moduleId] = false; hotUpdate[moduleId] = false;
} }
hotUpdateNewHash = newHash; hotUpdateNewHash = newHash;
if(--hotWaitingFiles === 0) { if(--hotWaitingFiles === 0 && hotChunksLoading === 0) {
hotUpdateDownloaded();
}
}
function hotUpdateDownloaded() {
var outdatedDependencies = hotUpdateOutdatedDependencies = {}; var outdatedDependencies = hotUpdateOutdatedDependencies = {};
var outdatedModules = hotUpdateOutdatedModules = Object.keys(hotUpdate).slice(); var outdatedModules = hotUpdateOutdatedModules = Object.keys(hotUpdate).slice();
var queue = outdatedModules.slice(); var queue = outdatedModules.slice();
@ -208,7 +219,6 @@ var hotInitCode = function() {
hotCallback(null, outdatedModules); hotCallback(null, outdatedModules);
} }
} }
}
var hotApplyOnUpdate = true; var hotApplyOnUpdate = true;
var hotCurrentHash = $hash$; var hotCurrentHash = $hash$;
@ -225,9 +235,19 @@ var hotInitCode = function() {
return $require$(request); return $require$(request);
}; };
fn.e = function(chunkId, callback) { 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() { $require$.e(chunkId, function() {
callback(fn); callback(fn);
hotChunksLoading--;
if(hotStatus === "prepare") {
if(!hotWaitingFilesMap[chunkId]) {
hotDownloadUpdateChunk(chunkId);
}
if(hotChunksLoading === 0 && hotWaitingFiles === 0) {
hotUpdateDownloaded();
}
}
}); });
} }
fn.cache = $require$.cache; fn.cache = $require$.cache;
@ -298,6 +318,8 @@ var hotInitCode = function() {
} }
var hotWaitingFiles = 0; var hotWaitingFiles = 0;
var hotChunksLoading = 0;
var hotWaitingFilesMap = {};
var hotCallback; var hotCallback;
function hotCheck(callback) { function hotCheck(callback) {
if(hotStatus !== "idle") throw new Error("check() is only allowed in idle status"); if(hotStatus !== "idle") throw new Error("check() is only allowed in idle status");
@ -318,15 +340,23 @@ var hotInitCode = function() {
if(request.status !== 200 && request.status !== 304) { if(request.status !== 200 && request.status !== 304) {
hotSetStatus("idle"); hotSetStatus("idle");
callback(null, []); callback(null, null);
} else { } else {
hotWaitingFilesMap = {};
hotSetStatus("prepare"); hotSetStatus("prepare");
hotCallback = callback || function(err) { if(err) throw err }; hotCallback = callback || function(err) { if(err) throw err };
hotUpdate = {}; hotUpdate = {};
var hash = hotCurrentHash; var hash = hotCurrentHash;
/*foreachInstalledChunks*/ { /*foreachInstalledChunks*/ {
hotDownloadUpdateChunk(chunkId);
}
}
};
}
function hotDownloadUpdateChunk(chunkId) {
hotWaitingFiles++; hotWaitingFiles++;
var head = document.getElementsByTagName('head')[0]; var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script'); var script = document.createElement('script');
@ -334,10 +364,7 @@ var hotInitCode = function() {
script.charset = 'utf-8'; script.charset = 'utf-8';
script.src = modules.c + $hotChunkFilename$; script.src = modules.c + $hotChunkFilename$;
head.appendChild(script); head.appendChild(script);
} hotWaitingFilesMap[chunkId] = true;
}
};
} }
var hotUpdate, hotUpdateOutdatedDependencies, hotUpdateOutdatedModules, hotUpdateNewHash; var hotUpdate, hotUpdateOutdatedDependencies, hotUpdateOutdatedModules, hotUpdateNewHash;

View File

@ -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);
};
}

View File

@ -38,6 +38,8 @@ window.onload = function() {
require("./style.js"); require("./style.js");
require("bundle!./style2.js");
if(module.hot) { if(module.hot) {
module.hot.accept("./html.js", function() { module.hot.accept("./html.js", function() {

View File

@ -1,22 +1,11 @@
// This file can update, because it accept itself. // This file can update, because it accept itself.
// A dispose handler removes the old <style> element. // A dispose handler removes the old <style> element.
var cssCode = "body { background: green; }"; var addStyle = require("./addStyle");
var head = document.getElementsByTagName("head")[0]; var dispose = addStyle("body { background: green; }");
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);
if(module.hot) { if(module.hot) {
module.hot.accept(); module.hot.accept();
module.hot.dispose(function() { module.hot.dispose(dispose);
head.removeChild(styleElement);
});
} }

View File

@ -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);
}