From 3247725ba3c3d8bea3b75a5512d37eeb776edc54 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Mon, 2 Jun 2014 21:23:53 +0200 Subject: [PATCH] refactored MainTemplate to plugin interface --- lib/AmdMainTemplateDecorator.js | 47 ---- lib/AmdMainTemplatePlugin.js | 44 ++++ lib/Compilation.js | 12 +- lib/Compiler.js | 6 +- lib/HotModuleReplacementPlugin.js | 58 ++--- lib/JsonpExportMainTemplateDecorator.js | 32 --- lib/JsonpExportMainTemplatePlugin.js | 29 +++ lib/JsonpMainTemplate.js | 181 --------------- lib/JsonpMainTemplatePlugin.js | 173 ++++++++++++++ lib/JsonpTemplatePlugin.js | 6 +- lib/LibraryTemplatePlugin.js | 82 +++---- lib/MainTemplate.js | 230 +++++++++---------- lib/SetVarMainTemplateDecorator.js | 40 ---- lib/SetVarMainTemplatePlugin.js | 37 +++ lib/Template.js | 12 +- lib/UmdMainTemplateDecorator.js | 103 --------- lib/UmdMainTemplatePlugin.js | 100 ++++++++ lib/node/NodeMainTemplate.js | 161 ------------- lib/node/NodeMainTemplatePlugin.js | 154 +++++++++++++ lib/node/NodeTemplatePlugin.js | 6 +- lib/optimize/DedupePlugin.js | 23 +- lib/webworker/WebWorkerMainTemplate.js | 84 ------- lib/webworker/WebWorkerMainTemplatePlugin.js | 74 ++++++ lib/webworker/WebWorkerTemplatePlugin.js | 6 +- package.json | 2 +- 25 files changed, 833 insertions(+), 869 deletions(-) delete mode 100644 lib/AmdMainTemplateDecorator.js create mode 100644 lib/AmdMainTemplatePlugin.js delete mode 100644 lib/JsonpExportMainTemplateDecorator.js create mode 100644 lib/JsonpExportMainTemplatePlugin.js delete mode 100644 lib/JsonpMainTemplate.js create mode 100644 lib/JsonpMainTemplatePlugin.js delete mode 100644 lib/SetVarMainTemplateDecorator.js create mode 100644 lib/SetVarMainTemplatePlugin.js delete mode 100644 lib/UmdMainTemplateDecorator.js create mode 100644 lib/UmdMainTemplatePlugin.js delete mode 100644 lib/node/NodeMainTemplate.js create mode 100644 lib/node/NodeMainTemplatePlugin.js delete mode 100644 lib/webworker/WebWorkerMainTemplate.js create mode 100644 lib/webworker/WebWorkerMainTemplatePlugin.js diff --git a/lib/AmdMainTemplateDecorator.js b/lib/AmdMainTemplateDecorator.js deleted file mode 100644 index ed5740d6b..000000000 --- a/lib/AmdMainTemplateDecorator.js +++ /dev/null @@ -1,47 +0,0 @@ -/* - MIT License http://www.opensource.org/licenses/mit-license.php - Author Tobias Koppers @sokra -*/ -var ConcatSource = require("webpack-core/lib/ConcatSource"); -var Template = require("./Template"); - -function AmdMainTemplateDecorator(mainTemplate, name) { - this.mainTemplate = mainTemplate; - this.name = name; -} -module.exports = AmdMainTemplateDecorator; -AmdMainTemplateDecorator.prototype.render = function(hash, chunk, moduleTemplate, dependencyTemplates) { - var source = this.mainTemplate.render(hash, chunk, moduleTemplate, dependencyTemplates); - var externals = chunk.modules.filter(function(m) { - return m.external; - }); - var externalsDepsArray = JSON.stringify(externals.map(function(m) { - return typeof m.request === "object" ? m.request.amd : m.request; - })); - var externalsArguments = externals.map(function(m) { - return "__WEBPACK_EXTERNAL_MODULE_" + m.id + "__"; - }).join(", "); - if(this.name) { - var name = this.name - .replace(Template.REGEXP_HASH, hash) - .replace(Template.REGEXP_CHUNKHASH, chunk.renderedHash) - .replace(Template.REGEXP_ID, chunk.id) - .replace(Template.REGEXP_NAME, chunk.name || ""); - return new ConcatSource("define(" + JSON.stringify(name) + ", " + externalsDepsArray + ", function(" + externalsArguments + ") { return ", source, "});"); - } else if(externalsArguments) { - return new ConcatSource("define(" + externalsDepsArray + ", function(" + externalsArguments + ") { return ", source, "});"); - } else { - return new ConcatSource("define(function() { return ", source, "});"); - } -}; - -AmdMainTemplateDecorator.prototype.useChunkHash = function(chunk) { - if(!this.mainTemplate.useChunkHash || !this.mainTemplate.useChunkHash(chunk)) return false; - return !Template.REGEXP_HASH.test(this.name || ""); -}; - -AmdMainTemplateDecorator.prototype.updateHash = function(hash) { - hash.update("exports amd"); - hash.update(this.name + ""); - this.mainTemplate.updateHash(hash); -}; \ No newline at end of file diff --git a/lib/AmdMainTemplatePlugin.js b/lib/AmdMainTemplatePlugin.js new file mode 100644 index 000000000..850920308 --- /dev/null +++ b/lib/AmdMainTemplatePlugin.js @@ -0,0 +1,44 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +var ConcatSource = require("webpack-core/lib/ConcatSource"); +var Template = require("./Template"); + +function AmdMainTemplatePlugin(name) { + this.name = name; +} +module.exports = AmdMainTemplatePlugin; +AmdMainTemplatePlugin.prototype.apply = function(mainTemplate) { + mainTemplate.plugin("render", function(source, chunk, hash, moduleTemplate, dependencyTemplates) { + var externals = chunk.modules.filter(function(m) { + return m.external; + }); + var externalsDepsArray = JSON.stringify(externals.map(function(m) { + return typeof m.request === "object" ? m.request.amd : m.request; + })); + var externalsArguments = externals.map(function(m) { + return "__WEBPACK_EXTERNAL_MODULE_" + m.id + "__"; + }).join(", "); + if(this.name) { + var name = this.name + .replace(Template.REGEXP_HASH, hash) + .replace(Template.REGEXP_CHUNKHASH, chunk.renderedHash) + .replace(Template.REGEXP_ID, chunk.id) + .replace(Template.REGEXP_NAME, chunk.name || ""); + return new ConcatSource("define(" + JSON.stringify(name) + ", " + externalsDepsArray + ", function(" + externalsArguments + ") { return ", source, "});"); + } else if(externalsArguments) { + return new ConcatSource("define(" + externalsDepsArray + ", function(" + externalsArguments + ") { return ", source, "});"); + } else { + return new ConcatSource("define(function() { return ", source, "});"); + } + }.bind(this)); + mainTemplate.plugin("global-hash", function(chunk) { + if(Template.REGEXP_HASH.test(this.name || "")) + return true; + }.bind(this)); + mainTemplate.plugin("hash", function(hash) { + hash.update("exports amd"); + hash.update(this.name + ""); + }.bind(this)); +}; \ No newline at end of file diff --git a/lib/Compilation.js b/lib/Compilation.js index 9ab92bc37..ad34caaf1 100644 --- a/lib/Compilation.js +++ b/lib/Compilation.js @@ -15,20 +15,24 @@ var ArrayMap = require("./ArrayMap"); var Chunk = require("./Chunk"); var Stats = require("./Stats"); var Template = require("./Template"); +var MainTemplate = require("./MainTemplate"); function Compilation(compiler) { Tapable.call(this); this.compiler = compiler; - this.mainTemplate = compiler.mainTemplate; - this.chunkTemplate = compiler.chunkTemplate; - this.hotUpdateChunkTemplate = compiler.hotUpdateChunkTemplate; - this.moduleTemplate = compiler.moduleTemplate; this.resolvers = compiler.resolvers; this.inputFileSystem = compiler.inputFileSystem; + var options = this.options = compiler.options; this.outputOptions = options && options.output; this.bail = options && options.bail; this.profile = options && options.profile; + + this.mainTemplate = new MainTemplate(this.outputOptions); + this.chunkTemplate = compiler.chunkTemplate; + this.hotUpdateChunkTemplate = compiler.hotUpdateChunkTemplate; + this.moduleTemplate = compiler.moduleTemplate; + this.entries = []; this.preparedChunks = []; this.chunks = []; diff --git a/lib/Compiler.js b/lib/Compiler.js index 15685d21a..9d8522204 100644 --- a/lib/Compiler.js +++ b/lib/Compiler.js @@ -122,7 +122,7 @@ Watching.prototype.close = function(callback) { function Compiler() { Tapable.call(this); - this.mainTemplate = this.chunkTemplate = this.moduleTemplate = null; + this.chunkTemplate = this.moduleTemplate = null; this.outputPath = ""; this.outputFileSystem = null; @@ -305,11 +305,10 @@ Compiler.prototype.readRecords = function readRecords(callback) { Compiler.prototype.createChildCompiler = function(compilation, compilerName, outputOptions) { var childCompiler = new Compiler(); for(var name in this._plugins) { - if(["make", "compile", "emit", "after-emit", "invalid", "done"].indexOf(name) < 0) + if(["make", "compile", "emit", "after-emit", "invalid", "done", "this-compilation"].indexOf(name) < 0) childCompiler._plugins[name] = this._plugins[name].slice(); } childCompiler.name = compilerName; - childCompiler.mainTemplate = this.mainTemplate; childCompiler.chunkTemplate = this.chunkTemplate; childCompiler.moduleTemplate = this.moduleTemplate; childCompiler.outputPath = this.outputPath; @@ -343,6 +342,7 @@ Compiler.prototype.newCompilation = function(params) { compilation.contextTimestamps = this.contextTimestamps; compilation.name = this.name; compilation.records = this.records; + this.applyPlugins("this-compilation", compilation, params); this.applyPlugins("compilation", compilation, params); return compilation; }; diff --git a/lib/HotModuleReplacementPlugin.js b/lib/HotModuleReplacementPlugin.js index b05fd5249..902ca43f5 100644 --- a/lib/HotModuleReplacementPlugin.js +++ b/lib/HotModuleReplacementPlugin.js @@ -17,7 +17,7 @@ HotModuleReplacementPlugin.prototype.apply = function(compiler) { var hotUpdateMainFilename = compiler.options.output.hotUpdateMainFilename; compiler.plugin("compilation", function(compilation, params) { var hotUpdateChunkTemplate = compilation.compiler.hotUpdateChunkTemplate; - if(!hotUpdateChunkTemplate && !compilation.mainTemplate.renderHotModuleReplacementInit) return; + if(!hotUpdateChunkTemplate) return; var normalModuleFactory = params.normalModuleFactory; var contextModuleFactory = params.contextModuleFactory; @@ -107,41 +107,43 @@ HotModuleReplacementPlugin.prototype.apply = function(compiler) { var mainTemplate = compilation.mainTemplate; compilation.mainTemplate = Object.create(mainTemplate); - compilation.mainTemplate.updateHash = function(hash) { + compilation.mainTemplate.plugin("hash", function(hash) { hash.update("HotMainTemplateDecorator"); - mainTemplate.updateHash(hash); - }; + }); - compilation.mainTemplate.renderRequireFunctionForModule = function(hash, chunk, varModuleId) { + compilation.mainTemplate.plugin("module-require", function(_, chunk, hash, varModuleId) { return "hotCreateRequire(" + varModuleId + ")"; - }; + }); - compilation.mainTemplate.renderInit = function(hash, chunk) { - var buf = mainTemplate.renderInit(hash, chunk); - buf = buf.concat(this.renderHotModuleReplacementInit(hash, chunk)); - buf.push("\n\n"); - buf.push(hotInitCode - .replace(/\$require\$/g, this.requireFn) - .replace(/\$hash\$/g, JSON.stringify(hash)) - .replace(/\/\*foreachInstalledChunks\*\//g, chunk.chunks.length > 0 ? "for(var chunkId in installedChunks)" : "var chunkId = 0;")); - return buf; - }; + compilation.mainTemplate.plugin("bootstrap", function(source, chunk, hash) { + source = this.applyPluginsWaterfall("hot-bootstrap", source, chunk, hash); + return this.asString([ + source, + "", + hotInitCode + .replace(/\$require\$/g, this.requireFn) + .replace(/\$hash\$/g, JSON.stringify(hash)) + .replace(/\/\*foreachInstalledChunks\*\//g, chunk.chunks.length > 0 ? "for(var chunkId in installedChunks)" : "var chunkId = 0;") + ]); + }); - compilation.mainTemplate.useChunkHash = false; + compilation.mainTemplate.plugin("global-hash", function() { + return true; + }); - compilation.mainTemplate.renderCurrentHashCode = function(hash) { + compilation.mainTemplate.plugin("current-hash", function() { return "hotCurrentHash"; - }; + }); - compilation.mainTemplate.renderModule = function(hash, chunk, varModuleId) { - var buf = mainTemplate.renderModule(hash, chunk, varModuleId); - buf.push(buf.pop() + ","); - buf.push("hot: hotCreateModule(" + varModuleId + "),"); - buf.push("parents: [hotCurrentParent],"); - buf.push("data: hotCurrentModuleData[" + varModuleId + "],"); - buf.push("children: []"); - return buf; - }; + compilation.mainTemplate.plugin("module-obj", function(source, chunk, hash, varModuleId) { + return this.asString([ + source + ",", + "hot: hotCreateModule(" + varModuleId + "),", + "parents: [hotCurrentParent],", + "data: hotCurrentModuleData[" + varModuleId + "],", + "children: []" + ]); + }); }); compiler.parser.plugin("evaluate Identifier module.hot", function(expr) { diff --git a/lib/JsonpExportMainTemplateDecorator.js b/lib/JsonpExportMainTemplateDecorator.js deleted file mode 100644 index 040f78b92..000000000 --- a/lib/JsonpExportMainTemplateDecorator.js +++ /dev/null @@ -1,32 +0,0 @@ -/* - MIT License http://www.opensource.org/licenses/mit-license.php - Author Tobias Koppers @sokra -*/ -var ConcatSource = require("webpack-core/lib/ConcatSource"); -var Template = require("./Template"); - -function JsonpExportMainTemplateDecorator(mainTemplate, name) { - this.mainTemplate = mainTemplate; - this.name = name; -} -module.exports = JsonpExportMainTemplateDecorator; -JsonpExportMainTemplateDecorator.prototype.render = function(hash, chunk, moduleTemplate, dependencyTemplates) { - var source = this.mainTemplate.render(hash, chunk, moduleTemplate, dependencyTemplates); - var name = (this.name || "") - .replace(Template.REGEXP_HASH, hash) - .replace(Template.REGEXP_CHUNKHASH, chunk.renderedHash) - .replace(Template.REGEXP_ID, chunk.id) - .replace(Template.REGEXP_NAME, chunk.name || ""); - return new ConcatSource(name + "(", source, ");"); -}; - -SetVarMainTemplateDecorator.prototype.useChunkHash = function(chunk) { - if(!this.mainTemplate.useChunkHash || !this.mainTemplate.useChunkHash(chunk)) return false; - return !Template.REGEXP_HASH.test(this.name || ""); -}; - -JsonpExportMainTemplateDecorator.prototype.updateHash = function(hash) { - hash.update("jsonp export"); - hash.update(this.name + ""); - this.mainTemplate.updateHash(hash); -}; \ No newline at end of file diff --git a/lib/JsonpExportMainTemplatePlugin.js b/lib/JsonpExportMainTemplatePlugin.js new file mode 100644 index 000000000..008dc5c66 --- /dev/null +++ b/lib/JsonpExportMainTemplatePlugin.js @@ -0,0 +1,29 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +var ConcatSource = require("webpack-core/lib/ConcatSource"); +var Template = require("./Template"); + +function JsonpExportMainTemplatePlugin(name) { + this.name = name; +} +module.exports = JsonpExportMainTemplatePlugin; +JsonpExportMainTemplatePlugin.prototype.apply = function(mainTemplate) { + mainTemplate.plugin("render", function(source, chunk, hash) { + var name = (this.name || "") + .replace(Template.REGEXP_HASH, hash) + .replace(Template.REGEXP_CHUNKHASH, chunk.renderedHash) + .replace(Template.REGEXP_ID, chunk.id) + .replace(Template.REGEXP_NAME, chunk.name || ""); + return new ConcatSource(name + "(", source, ");"); + }.bind(this)); + mainTemplate.plugin("global-hash", function(chunk) { + if(Template.REGEXP_HASH.test(this.name || "")) + return true; + }.bind(this)); + mainTemplate.plugin("hash", function(hash) { + hash.update("jsonp export"); + hash.update(this.name + ""); + }.bind(this)); +}; \ No newline at end of file diff --git a/lib/JsonpMainTemplate.js b/lib/JsonpMainTemplate.js deleted file mode 100644 index 80052dfca..000000000 --- a/lib/JsonpMainTemplate.js +++ /dev/null @@ -1,181 +0,0 @@ -/* - MIT License http://www.opensource.org/licenses/mit-license.php - Author Tobias Koppers @sokra -*/ -var MainTemplate = require("./MainTemplate"); -var Template = require("./Template"); - -function JsonpMainTemplate(outputOptions) { - MainTemplate.call(this, outputOptions); -} -module.exports = JsonpMainTemplate; - -JsonpMainTemplate.prototype = Object.create(MainTemplate.prototype); -JsonpMainTemplate.prototype.constructor = JsonpMainTemplate; - -JsonpMainTemplate.prototype.renderLocalVars = function(hash, chunk) { - var buf = MainTemplate.prototype.renderLocalVars.call(this, hash, chunk); - if(chunk.chunks.length > 0) { - buf.push( - "", - "// object to store loaded and loading chunks", - '// "0" means "already loaded"', - '// Array means "loading", array contains callbacks', - "var installedChunks = {", - this.indent( - chunk.ids.map(function(id) { - return id + ":0" - }).join(",\n") - ), - "};" - ); - } - return buf; -}; - -JsonpMainTemplate.prototype.renderRequireEnsure = function(hash, chunk) { - var filename = this.outputOptions.filename || "bundle.js"; - var chunkFilename = this.outputOptions.chunkFilename || "[id]." + filename; - var chunkHashMap = {}; - (function addChunk(c) { - if(c.id in chunkHashMap) return; - if(c.entry) - chunkHashMap[c.id] = undefined; - else - chunkHashMap[c.id] = c.renderedHash; - c.chunks.forEach(addChunk); - }(chunk)); - return [ - "// \"0\" is the signal for \"already loaded\"", - "if(installedChunks[chunkId] === 0)", - this.indent("return callback.call(null, " + this.requireFn + ");"), - "", - "// an array means \"currently loading\".", - "if(installedChunks[chunkId] !== undefined) {", - this.indent("installedChunks[chunkId].push(callback);"), - "} else {", - this.indent([ - "// start chunk loading", - "installedChunks[chunkId] = [callback];", - "var head = document.getElementsByTagName('head')[0];", - "var script = document.createElement('script');", - "script.type = 'text/javascript';", - "script.charset = 'utf-8';", - "script.src = " + this.requireFn + ".p + " + - JSON.stringify(chunkFilename - .replace(Template.REGEXP_NAME, "")) - .replace(Template.REGEXP_HASH, "\" + " + this.renderCurrentHashCode(hash) + " + \"") - .replace(Template.REGEXP_CHUNKHASH, "\" + " + JSON.stringify(chunkHashMap) + "[chunkId] + \"") - .replace(Template.REGEXP_ID, "\" + chunkId + \"") + ";", - "head.appendChild(script);" - ]), - "}" - ]; -}; - -JsonpMainTemplate.prototype.renderInit = function(hash, chunk) { - var buf = MainTemplate.prototype.renderInit.call(this, hash, chunk); - if(chunk.chunks.length > 0) { - var jsonpFunction = this.outputOptions.jsonpFunction || ("webpackJsonp" + (this.outputOptions.library || "")); - buf.push( - "", - "// install a JSONP callback for chunk loading", - "var parentJsonpFunction = window[" + JSON.stringify(jsonpFunction) + "];", - "window[" + JSON.stringify(jsonpFunction) + "] = function webpackJsonpCallback(chunkIds, moreModules) {", - this.indent([ - '// add "moreModules" to the modules object,', - '// then flag all "chunkIds" as loaded and fire callback', - "var moduleId, chunkId, i = 0, callbacks = [];", - "for(;i < chunkIds.length; i++) {", - this.indent([ - "chunkId = chunkIds[i];", - "if(installedChunks[chunkId])", - this.indent("callbacks.push.apply(callbacks, installedChunks[chunkId]);"), - "installedChunks[chunkId] = 0;" - ]), - "}", - "for(moduleId in moreModules) {", - this.indent(this.renderAddModule(hash, chunk, "moduleId", "moreModules[moduleId]")), - "}", - "if(parentJsonpFunction) parentJsonpFunction(chunkIds, moreModules);", - "while(callbacks.length)", - this.indent("callbacks.shift().call(null, " + this.requireFn + ");"), - (this.entryPointInChildren(chunk) ? [ - "if(moreModules[0]) {", - this.indent([ - "installedModules[0] = 0;", - this.requireFn + "(0);" - ]), - "}" - ] : "") - ]), - "};" - ); - } - return buf; -}; - -JsonpMainTemplate.prototype.renderHotModuleReplacementInit = function(hash, chunk) { - var hotUpdateChunkFilename = this.outputOptions.hotUpdateChunkFilename; - var hotUpdateMainFilename = this.outputOptions.hotUpdateMainFilename; - var hotUpdateFunction = this.outputOptions.hotUpdateFunction || ("webpackHotUpdate" + (this.outputOptions.library || "")); - var currentHotUpdateChunkFilename = JSON.stringify(hotUpdateChunkFilename) - .replace(Template.REGEXP_HASH, "\" + " + this.renderCurrentHashCode(hash) + " + \"") - .replace(Template.REGEXP_ID, "\" + chunkId + \""); - var currentHotUpdateMainFilename = JSON.stringify(hotUpdateMainFilename) - .replace(Template.REGEXP_HASH, "\" + " + this.renderCurrentHashCode(hash) + " + \""); - return "this[" + JSON.stringify(hotUpdateFunction) + "] = " + Template.getFunctionContent(function() { - function webpackHotUpdateCallback(chunkId, moreModules) { - hotAddUpdateChunk(chunkId, moreModules); - } - - function hotDownloadUpdateChunk(chunkId) { - var head = document.getElementsByTagName('head')[0]; - var script = document.createElement('script'); - script.type = 'text/javascript'; - script.charset = 'utf-8'; - script.src = $require$.p + $hotChunkFilename$; - head.appendChild(script); - } - - function hotDownloadManifest(callback) { - if(typeof XMLHttpRequest === "undefined") - return callback(new Error("No browser support")); - try { - var request = new XMLHttpRequest(); - request.open("GET", $require$.p + $hotMainFilename$, true); - request.send(null); - } catch(err) { - return callback(err); - } - request.onreadystatechange = function() { - if(request.readyState !== 4) return; - if(request.status !== 200 && request.status !== 304) { - callback(); - } else { - try { - var update = JSON.parse(request.responseText); - } catch(e) { - callback(); - return; - } - callback(null, update); - } - }; - } - }) - .replace(/\$require\$/g, this.requireFn) - .replace(/\$hotMainFilename\$/g, currentHotUpdateMainFilename) - .replace(/\$hotChunkFilename\$/g, currentHotUpdateChunkFilename) - .replace(/\$hash\$/g, JSON.stringify(hash)) -}; - -JsonpMainTemplate.prototype.updateHash = function(hash) { - MainTemplate.prototype.updateHash.call(this, hash); - hash.update("jsonp"); - hash.update("3"); - hash.update(this.outputOptions.filename + ""); - hash.update(this.outputOptions.chunkFilename + ""); - hash.update(this.outputOptions.jsonpFunction + ""); - hash.update(this.outputOptions.library + ""); -}; \ No newline at end of file diff --git a/lib/JsonpMainTemplatePlugin.js b/lib/JsonpMainTemplatePlugin.js new file mode 100644 index 000000000..e064afa05 --- /dev/null +++ b/lib/JsonpMainTemplatePlugin.js @@ -0,0 +1,173 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +var Template = require("./Template"); + +function JsonpMainTemplatePlugin() { +} +module.exports = JsonpMainTemplatePlugin; + +JsonpMainTemplatePlugin.prototype.constructor = JsonpMainTemplatePlugin; +JsonpMainTemplatePlugin.prototype.apply = function(mainTemplate) { + mainTemplate.plugin("local-vars", function(source, chunk, hash) { + if(chunk.chunks.length > 0) { + return this.asString([ + source, + "", + "// object to store loaded and loading chunks", + '// "0" means "already loaded"', + '// Array means "loading", array contains callbacks', + "var installedChunks = {", + this.indent( + chunk.ids.map(function(id) { + return id + ":0" + }).join(",\n") + ), + "};" + ]); + } + return source; + }); + mainTemplate.plugin("require-ensure", function(_, chunk, hash) { + var filename = this.outputOptions.filename || "bundle.js"; + var chunkFilename = this.outputOptions.chunkFilename || "[id]." + filename; + var chunkHashMap = {}; + (function addChunk(c) { + if(c.id in chunkHashMap) return; + if(c.entry) + chunkHashMap[c.id] = undefined; + else + chunkHashMap[c.id] = c.renderedHash; + c.chunks.forEach(addChunk); + }(chunk)); + return this.asString([ + "// \"0\" is the signal for \"already loaded\"", + "if(installedChunks[chunkId] === 0)", + this.indent("return callback.call(null, " + this.requireFn + ");"), + "", + "// an array means \"currently loading\".", + "if(installedChunks[chunkId] !== undefined) {", + this.indent("installedChunks[chunkId].push(callback);"), + "} else {", + this.indent([ + "// start chunk loading", + "installedChunks[chunkId] = [callback];", + "var head = document.getElementsByTagName('head')[0];", + "var script = document.createElement('script');", + "script.type = 'text/javascript';", + "script.charset = 'utf-8';", + "script.src = " + this.requireFn + ".p + " + + JSON.stringify(chunkFilename.replace(Template.REGEXP_NAME, "")) + .replace(Template.REGEXP_HASH, "\" + " + this.renderCurrentHashCode(hash) + " + \"") + .replace(Template.REGEXP_CHUNKHASH, "\" + " + JSON.stringify(chunkHashMap) + "[chunkId] + \"") + .replace(Template.REGEXP_ID, "\" + chunkId + \"") + ";", + "head.appendChild(script);" + ]), + "}" + ]); + }); + mainTemplate.plugin("bootstrap", function(source, chunk, hash) { + if(chunk.chunks.length > 0) { + var jsonpFunction = this.outputOptions.jsonpFunction || ("webpackJsonp" + (this.outputOptions.library || "")); + return this.asString([ + source, + "", + "// install a JSONP callback for chunk loading", + "var parentJsonpFunction = window[" + JSON.stringify(jsonpFunction) + "];", + "window[" + JSON.stringify(jsonpFunction) + "] = function webpackJsonpCallback(chunkIds, moreModules) {", + this.indent([ + '// add "moreModules" to the modules object,', + '// then flag all "chunkIds" as loaded and fire callback', + "var moduleId, chunkId, i = 0, callbacks = [];", + "for(;i < chunkIds.length; i++) {", + this.indent([ + "chunkId = chunkIds[i];", + "if(installedChunks[chunkId])", + this.indent("callbacks.push.apply(callbacks, installedChunks[chunkId]);"), + "installedChunks[chunkId] = 0;" + ]), + "}", + "for(moduleId in moreModules) {", + this.indent(this.renderAddModule(hash, chunk, "moduleId", "moreModules[moduleId]")), + "}", + "if(parentJsonpFunction) parentJsonpFunction(chunkIds, moreModules);", + "while(callbacks.length)", + this.indent("callbacks.shift().call(null, " + this.requireFn + ");"), + (this.entryPointInChildren(chunk) ? [ + "if(moreModules[0]) {", + this.indent([ + "installedModules[0] = 0;", + this.requireFn + "(0);" + ]), + "}" + ] : "") + ]), + "};" + ]); + } + return source; + }); + mainTemplate.plugin("hot-bootstrap", function(source, chunk, hash) { + var hotUpdateChunkFilename = this.outputOptions.hotUpdateChunkFilename; + var hotUpdateMainFilename = this.outputOptions.hotUpdateMainFilename; + var hotUpdateFunction = this.outputOptions.hotUpdateFunction || ("webpackHotUpdate" + (this.outputOptions.library || "")); + var currentHotUpdateChunkFilename = JSON.stringify(hotUpdateChunkFilename) + .replace(Template.REGEXP_HASH, "\" + " + this.renderCurrentHashCode(hash) + " + \"") + .replace(Template.REGEXP_ID, "\" + chunkId + \""); + var currentHotUpdateMainFilename = JSON.stringify(hotUpdateMainFilename) + .replace(Template.REGEXP_HASH, "\" + " + this.renderCurrentHashCode(hash) + " + \""); + return "this[" + JSON.stringify(hotUpdateFunction) + "] = " + Template.getFunctionContent(function() { + function webpackHotUpdateCallback(chunkId, moreModules) { + hotAddUpdateChunk(chunkId, moreModules); + } + + function hotDownloadUpdateChunk(chunkId) { + var head = document.getElementsByTagName('head')[0]; + var script = document.createElement('script'); + script.type = 'text/javascript'; + script.charset = 'utf-8'; + script.src = $require$.p + $hotChunkFilename$; + head.appendChild(script); + } + + function hotDownloadManifest(callback) { + if(typeof XMLHttpRequest === "undefined") + return callback(new Error("No browser support")); + try { + var request = new XMLHttpRequest(); + request.open("GET", $require$.p + $hotMainFilename$, true); + request.send(null); + } catch(err) { + return callback(err); + } + request.onreadystatechange = function() { + if(request.readyState !== 4) return; + if(request.status !== 200 && request.status !== 304) { + callback(); + } else { + try { + var update = JSON.parse(request.responseText); + } catch(e) { + callback(); + return; + } + callback(null, update); + } + }; + } + }) + .replace(/\$require\$/g, this.requireFn) + .replace(/\$hotMainFilename\$/g, currentHotUpdateMainFilename) + .replace(/\$hotChunkFilename\$/g, currentHotUpdateChunkFilename) + .replace(/\$hash\$/g, JSON.stringify(hash)) + }); + mainTemplate.plugin("hash", function(hash) { + hash.update("jsonp"); + hash.update("4"); + hash.update(this.outputOptions.filename + ""); + hash.update(this.outputOptions.chunkFilename + ""); + hash.update(this.outputOptions.jsonpFunction + ""); + hash.update(this.outputOptions.library + ""); + }); +}; diff --git a/lib/JsonpTemplatePlugin.js b/lib/JsonpTemplatePlugin.js index 88aae0031..5498219db 100644 --- a/lib/JsonpTemplatePlugin.js +++ b/lib/JsonpTemplatePlugin.js @@ -2,7 +2,7 @@ MIT License http://www.opensource.org/licenses/mit-license.php Author Tobias Koppers @sokra */ -var JsonpMainTemplate = require("./JsonpMainTemplate"); +var JsonpMainTemplatePlugin = require("./JsonpMainTemplatePlugin"); var JsonpChunkTemplate = require("./JsonpChunkTemplate"); var JsonpHotUpdateChunkTemplate = require("./JsonpHotUpdateChunkTemplate"); @@ -12,7 +12,9 @@ function JsonpTemplatePlugin(options) { module.exports = JsonpTemplatePlugin; JsonpTemplatePlugin.prototype.apply = function(compiler) { var options = this.options; - compiler.mainTemplate = new JsonpMainTemplate(options); + compiler.plugin("this-compilation", function(compilation) { + compilation.mainTemplate.apply(new JsonpMainTemplatePlugin()); + }); compiler.chunkTemplate = new JsonpChunkTemplate(options); compiler.hotUpdateChunkTemplate = new JsonpHotUpdateChunkTemplate(options); }; \ No newline at end of file diff --git a/lib/LibraryTemplatePlugin.js b/lib/LibraryTemplatePlugin.js index 717094a81..0b6834214 100644 --- a/lib/LibraryTemplatePlugin.js +++ b/lib/LibraryTemplatePlugin.js @@ -2,7 +2,7 @@ MIT License http://www.opensource.org/licenses/mit-license.php Author Tobias Koppers @sokra */ -var SetVarMainTemplateDecorator = require("./SetVarMainTemplateDecorator"); +var SetVarMainTemplatePlugin = require("./SetVarMainTemplatePlugin"); function accessorToObjectAccess(accessor) { return accessor.map(function(a) { @@ -26,43 +26,45 @@ function LibraryTemplatePlugin(name, target) { } module.exports = LibraryTemplatePlugin; LibraryTemplatePlugin.prototype.apply = function(compiler) { - switch(this.target) { - case "var": - compiler.mainTemplate = new SetVarMainTemplateDecorator(compiler.mainTemplate, "var " + accessorAccess(false, this.name)); - break; - case "assign": - compiler.mainTemplate = new SetVarMainTemplateDecorator(compiler.mainTemplate, accessorAccess(undefined, this.name)); - break; - case "this": - case "window": - case "global": - if(this.name) - compiler.mainTemplate = new SetVarMainTemplateDecorator(compiler.mainTemplate, accessorAccess(this.target, this.name)); - else - compiler.mainTemplate = new SetVarMainTemplateDecorator(compiler.mainTemplate, this.target, true); - break; - case "commonjs": - if(this.name) - compiler.mainTemplate = new SetVarMainTemplateDecorator(compiler.mainTemplate, accessorAccess("exports", this.name)); - else - compiler.mainTemplate = new SetVarMainTemplateDecorator(compiler.mainTemplate, "exports", true); - break; - case "commonjs2": - compiler.mainTemplate = new SetVarMainTemplateDecorator(compiler.mainTemplate, "module.exports"); - break; - case "amd": - var AmdMainTemplateDecorator = require("./AmdMainTemplateDecorator"); - compiler.mainTemplate = new AmdMainTemplateDecorator(compiler.mainTemplate, this.name); - break; - case "umd": - var UmdMainTemplateDecorator = require("./UmdMainTemplateDecorator"); - compiler.mainTemplate = new UmdMainTemplateDecorator(compiler.mainTemplate, this.name); - break; - case "jsonp": - var JsonpExportMainTemplateDecorator = require("./JsonpExportMainTemplateDecorator"); - compiler.mainTemplate = new JsonpExportMainTemplateDecorator(compiler.mainTemplate, this.name); - break; - default: - throw new Error(this.target + " is not a valid Library target"); - } + compiler.plugin("this-compilation", function(compilation) { + switch(this.target) { + case "var": + compilation.mainTemplate.apply(new SetVarMainTemplatePlugin("var " + accessorAccess(false, this.name))); + break; + case "assign": + compilation.mainTemplate.apply(new SetVarMainTemplatePlugin(accessorAccess(undefined, this.name))); + break; + case "this": + case "window": + case "global": + if(this.name) + compilation.mainTemplate.apply(new SetVarMainTemplatePlugin(accessorAccess(this.target, this.name))); + else + compilation.mainTemplate.apply(new SetVarMainTemplatePlugin(this.target, true)); + break; + case "commonjs": + if(this.name) + compilation.mainTemplate.apply(new SetVarMainTemplatePlugin(accessorAccess("exports", this.name))); + else + compilation.mainTemplate.apply(new SetVarMainTemplatePlugin("exports", true)); + break; + case "commonjs2": + compilation.mainTemplate.apply(new SetVarMainTemplatePlugin("module.exports")); + break; + case "amd": + var AmdMainTemplatePlugin = require("./AmdMainTemplatePlugin"); + compilation.mainTemplate.apply(new AmdMainTemplatePlugin(this.name)); + break; + case "umd": + var UmdMainTemplatePlugin = require("./UmdMainTemplatePlugin"); + compilation.mainTemplate.apply(new UmdMainTemplatePlugin(this.name)); + break; + case "jsonp": + var JsonpExportMainTemplatePlugin = require("./JsonpExportMainTemplatePlugin"); + compilation.mainTemplate.apply(new JsonpExportMainTemplatePlugin(this.name)); + break; + default: + throw new Error(this.target + " is not a valid Library target"); + } + }.bind(this)); }; \ No newline at end of file diff --git a/lib/MainTemplate.js b/lib/MainTemplate.js index d3518acfd..0f5bcddb2 100644 --- a/lib/MainTemplate.js +++ b/lib/MainTemplate.js @@ -9,6 +9,98 @@ var Template = require("./Template"); function MainTemplate(outputOptions) { Template.call(this, outputOptions); + this.plugin("startup", function(source, chunk, hash) { + var buf = []; + if(chunk.modules.some(function(m) { return m.id === 0; })) { + buf.push(""); + buf.push("// Load entry module and return exports"); + buf.push("return " + this.renderRequireFunctionForModule(hash, chunk, "0") + "(0);"); + } + return this.asString(buf); + }); + this.plugin("render", function(bootstrapSource, chunk, hash, moduleTemplate, dependencyTemplates) { + var source = new ConcatSource(); + source.add("/******/ (function(modules) { // webpackBootstrap\n"); + source.add(new PrefixSource("/******/", bootstrapSource)); + source.add("\n/******/ })\n"); + source.add("/************************************************************************/\n"); + source.add("/******/ ("); + var modules = this.renderChunkModules(chunk, moduleTemplate, dependencyTemplates, "/******/ "); + source.add(this.applyPluginsWaterfall("modules", modules, chunk, hash, moduleTemplate, dependencyTemplates)); + source.add(")"); + return source; + }); + this.plugin("local-vars", function(source, chunk, hash) { + return this.asString([ + source, + "// The module cache", + "var installedModules = {};" + ]); + }); + this.plugin("require", function(source, chunk, hash) { + return this.asString([ + source, + "// Check if module is in cache", + "if(installedModules[moduleId])", + this.indent("return installedModules[moduleId].exports;"), + "", + "// Create a new module (and put it into the cache)", + "var module = installedModules[moduleId] = {", + this.indent(this.applyPluginsWaterfall("module-obj", chunk, hash, "moduleId")), + "};", + "", + "// Execute the module function", + "modules[moduleId].call(module.exports, module, module.exports, " + this.renderRequireFunctionForModule(hash, chunk, "moduleId") + ");", + "", + "// Flag the module as loaded", + "module.loaded = true;", + "", + "// Return the exports of the module", + "return module.exports;" + ]); + }); + this.plugin("module-obj", function(source, chunk, hash, varModuleId) { + return this.asString([ + "exports: {},", + "id: moduleId,", + "loaded: false" + ]); + }); + this.plugin("require-extensions", function(source, chunk, hash) { + var buf = []; + if(chunk.chunks.length > 0) { + buf.push("// This file contains only the entry chunk."); + buf.push("// The chunk loading function for additional chunks"); + buf.push(this.requireFn + ".e = function requireEnsure(chunkId, callback) {"); + buf.push(this.indent(this.applyPluginsWaterfall("require-ensure", "throw new Error('Not chunk loading available');", chunk, hash, "chunkId"))); + buf.push("};"); + } + buf.push(""); + buf.push("// expose the modules object (__webpack_modules__)"); + buf.push(this.requireFn + ".m = modules;"); + + buf.push(""); + buf.push("// expose the module cache"); + buf.push(this.requireFn + ".c = installedModules;"); + + var publicPath = this.outputOptions.publicPath || ""; + publicPath = publicPath.replace(Template.REGEXP_HASH, hash); + buf.push(""); + buf.push("// __webpack_public_path__"); + buf.push(this.requireFn + ".p = " + JSON.stringify(publicPath) + ";"); + return this.asString(buf); + }); + this.plugin("global-hash", function(chunk) { + var publicPath = this.outputOptions.publicPath || ""; + var filename = this.outputOptions.filename || ""; + var chunkFilename = this.outputOptions.chunkFilename || ""; + if(Template.REGEXP_HASH.test(publicPath) || Template.REGEXP_CHUNKHASH.test(publicPath)) + return true; + if(Template.REGEXP_HASH.test(filename) || Template.REGEXP_CHUNKHASH.test(filename)) + return true; + if(Template.REGEXP_HASH.test(chunkFilename) || Template.REGEXP_CHUNKHASH.test(chunkFilename)) + return true; + }); } module.exports = MainTemplate; @@ -16,139 +108,32 @@ MainTemplate.prototype = Object.create(Template.prototype); MainTemplate.prototype.requireFn = "__webpack_require__"; MainTemplate.prototype.render = function(hash, chunk, moduleTemplate, dependencyTemplates) { var buf = []; - buf.push(this.asString(this.renderAdditions(hash, chunk, moduleTemplate, dependencyTemplates))); - buf.push(this.asString(this.renderLocalVars(hash, chunk))); + buf.push(this.applyPluginsWaterfall("bootstrap", "", chunk, hash, moduleTemplate, dependencyTemplates)); + buf.push(this.applyPluginsWaterfall("local-vars", "", chunk, hash)); buf.push(""); buf.push("// The require function"); buf.push("function " + this.requireFn + "(moduleId) {"); - buf.push(this.indent(this.renderRequireContent(hash, chunk))); + buf.push(this.indent(this.applyPluginsWaterfall("require", "", chunk, hash))); buf.push("}"); buf.push(""); - buf.push(this.asString(this.renderRequireExtensions(hash, chunk))); - buf.push(this.asString(this.renderInit(hash, chunk))); - if(chunk.modules.some(function(m) { return m.id === 0; })) { - buf.push(""); - buf.push("// Load entry module and return exports"); - buf.push("return " + this.renderRequireFunctionForModule(hash, chunk, "0") + "(0);"); - } - var source = new ConcatSource(); - source.add("/******/ (function(modules) { // webpackBootstrap\n"); - source.add(new PrefixSource("/******/ \t", new OriginalSource(this.asString(buf), "webpack/bootstrap " + hash))); - source.add("\n/******/ })\n"); - source.add("/************************************************************************/\n"); - source.add("/******/ ("); - source.add(this.renderModules(hash, chunk, moduleTemplate, dependencyTemplates)); - source.add(")"); + buf.push(this.asString(this.applyPluginsWaterfall("require-extensions", "", chunk, hash))); + buf.push(this.asString(this.applyPluginsWaterfall("startup", "", chunk, hash))); + var source = this.applyPluginsWaterfall("render", new OriginalSource(this.prefix(buf, " \t"), "webpack/bootstrap " + hash), chunk, hash, moduleTemplate, dependencyTemplates); + if(!source) throw new Error("Compiler error: MainTemplate plugin 'render' should return something"); chunk.rendered = true; return source; }; -MainTemplate.prototype.renderModules = function renderModules(hash, chunk, moduleTemplate, dependencyTemplates) { - return this.renderChunkModules(chunk, moduleTemplate, dependencyTemplates, "/******/ "); -}; - -MainTemplate.prototype.indent = function indent(str) { - if(Array.isArray(str)) { - return str.map(indent).join("\n"); - } else { - return "\t" + str.trimRight().replace(/\n/g, "\n\t"); - } -}; - -MainTemplate.prototype.prefix = function(str, prefix) { - if(Array.isArray(str)) { - str = str.join("\n"); - } - return prefix + str.trim().replace(/\n/g, "\n" + prefix); -}; - -MainTemplate.prototype.asString = function(str) { - if(Array.isArray(str)) { - return str.join("\n"); - } - return str; -}; - -MainTemplate.prototype.renderLocalVars = function(hash, chunk) { - return [ - "// The module cache", - "var installedModules = {};" - ]; -}; - -MainTemplate.prototype.renderRequireContent = function(hash, chunk) { - return [ - "// Check if module is in cache", - "if(installedModules[moduleId])", - this.indent("return installedModules[moduleId].exports;"), - "", - "// Create a new module (and put it into the cache)", - "var module = installedModules[moduleId] = {", - this.indent(this.renderModule(hash, chunk, "moduleId")), - "};", - "", - "// Execute the module function", - "modules[moduleId].call(module.exports, module, module.exports, " + this.renderRequireFunctionForModule(hash, chunk, "moduleId") + ");", - "", - "// Flag the module as loaded", - "module.loaded = true;", - "", - "// Return the exports of the module", - "return module.exports;" - ]; -}; - MainTemplate.prototype.renderRequireFunctionForModule = function(hash, chunk, varModuleId) { - return this.requireFn; -}; - -MainTemplate.prototype.renderModule = function(hash, chunk, varModuleId) { - return [ - "exports: {},", - "id: moduleId,", - "loaded: false" - ]; -}; - -MainTemplate.prototype.renderRequireExtensions = function(hash, chunk) { - var buf = []; - if(chunk.chunks.length > 0) { - buf.push("// This file contains only the entry chunk."); - buf.push("// The chunk loading function for additional chunks"); - buf.push(this.requireFn + ".e = function requireEnsure(chunkId, callback) {"); - buf.push(this.indent(this.renderRequireEnsure(hash, chunk))); - buf.push("};"); - } - buf.push(""); - buf.push("// expose the modules object (__webpack_modules__)"); - buf.push(this.requireFn + ".m = modules;"); - - buf.push(""); - buf.push("// expose the module cache"); - buf.push(this.requireFn + ".c = installedModules;"); - - var publicPath = this.outputOptions.publicPath || ""; - publicPath = publicPath.replace(Template.REGEXP_HASH, hash); - buf.push(""); - buf.push("// __webpack_public_path__"); - buf.push(this.requireFn + ".p = " + JSON.stringify(publicPath) + ";"); - return buf; -}; - -MainTemplate.prototype.renderInit = function(hash, chunk) { - return []; -}; - -MainTemplate.prototype.renderAdditions = function(hash, chunk, moduleTemplate, dependencyTemplates) { - return []; + return this.applyPluginsWaterfall("module-require", this.requireFn, chunk, hash, varModuleId); }; MainTemplate.prototype.renderAddModule = function(hash, chunk, varModuleId, varModule) { - return ["modules[" + varModuleId + "] = " + varModule + ";"]; + return this.applyPluginsWaterfall("add-module", "modules[" + varModuleId + "] = " + varModule + ";", chunk, hash, varModuleId, varModule); }; MainTemplate.prototype.renderCurrentHashCode = function(hash) { - return JSON.stringify(hash); + return this.applyPluginsWaterfall("current-hash", JSON.stringify(hash)); }; MainTemplate.prototype.entryPointInChildren = function(chunk) { @@ -165,16 +150,11 @@ MainTemplate.prototype.entryPointInChildren = function(chunk) { MainTemplate.prototype.updateHash = function(hash) { hash.update("maintemplate"); - hash.update("2"); + hash.update("3"); hash.update(this.outputOptions.publicPath + ""); + this.applyPlugins("hash", hash); }; MainTemplate.prototype.useChunkHash = function(chunk) { - var publicPath = this.outputOptions.publicPath || ""; - var filename = this.outputOptions.filename || ""; - var chunkFilename = this.outputOptions.chunkFilename || ""; - var hashInPublicPath = Template.REGEXP_HASH.test(publicPath) || Template.REGEXP_CHUNKHASH.test(publicPath); - var hashInFilename = Template.REGEXP_HASH.test(filename) || Template.REGEXP_CHUNKHASH.test(filename); - var hashInChunkFilename = Template.REGEXP_HASH.test(chunkFilename) || Template.REGEXP_CHUNKHASH.test(chunkFilename); - return !hashInPublicPath && !hashInFilename && !hashInChunkFilename; + return this.applyPluginsBailResult("global-hash", chunk); }; \ No newline at end of file diff --git a/lib/SetVarMainTemplateDecorator.js b/lib/SetVarMainTemplateDecorator.js deleted file mode 100644 index f4a22c751..000000000 --- a/lib/SetVarMainTemplateDecorator.js +++ /dev/null @@ -1,40 +0,0 @@ -/* - MIT License http://www.opensource.org/licenses/mit-license.php - Author Tobias Koppers @sokra -*/ -var ConcatSource = require("webpack-core/lib/ConcatSource"); -var Template = require("./Template"); - -function SetVarMainTemplateDecorator(mainTemplate, varExpression, copyObject) { - this.mainTemplate = mainTemplate; - this.varExpression = varExpression; - this.copyObject = copyObject; -} -module.exports = SetVarMainTemplateDecorator; -SetVarMainTemplateDecorator.prototype.render = function(hash, chunk, moduleTemplate, dependencyTemplates) { - var source = this.mainTemplate.render(hash, chunk, moduleTemplate, dependencyTemplates); - var varExpression = this.varExpression - .replace(Template.REGEXP_HASH, hash) - .replace(Template.REGEXP_CHUNKHASH, chunk.renderedHash) - .replace(Template.REGEXP_ID, chunk.id) - .replace(Template.REGEXP_NAME, chunk.name || ""); - if(this.copyObject) { - return new ConcatSource("(function(e, a) { for(var i in a) e[i] = a[i]; }(" + - varExpression + ", ", source, "))"); - } else { - var prefix = varExpression + " =\n"; - return new ConcatSource(prefix, source); - } -}; - -SetVarMainTemplateDecorator.prototype.useChunkHash = function(chunk) { - if(!this.mainTemplate.useChunkHash || !this.mainTemplate.useChunkHash(chunk)) return false; - return !Template.REGEXP_HASH.test(this.varExpression || ""); -}; - -SetVarMainTemplateDecorator.prototype.updateHash = function(hash) { - hash.update("set var"); - hash.update(this.varExpression + ""); - hash.update(this.copyObject + ""); - this.mainTemplate.updateHash(hash); -}; \ No newline at end of file diff --git a/lib/SetVarMainTemplatePlugin.js b/lib/SetVarMainTemplatePlugin.js new file mode 100644 index 000000000..a29b74c4d --- /dev/null +++ b/lib/SetVarMainTemplatePlugin.js @@ -0,0 +1,37 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +var ConcatSource = require("webpack-core/lib/ConcatSource"); +var Template = require("./Template"); + +function SetVarMainTemplatePlugin(varExpression, copyObject) { + this.varExpression = varExpression; + this.copyObject = copyObject; +} +module.exports = SetVarMainTemplatePlugin; +SetVarMainTemplatePlugin.prototype.apply = function(mainTemplate) { + mainTemplate.plugin("render", function(source, chunk, hash) { + var varExpression = this.varExpression + .replace(Template.REGEXP_HASH, hash) + .replace(Template.REGEXP_CHUNKHASH, chunk.renderedHash) + .replace(Template.REGEXP_ID, chunk.id) + .replace(Template.REGEXP_NAME, chunk.name || ""); + if(this.copyObject) { + return new ConcatSource("(function(e, a) { for(var i in a) e[i] = a[i]; }(" + + varExpression + ", ", source, "))"); + } else { + var prefix = varExpression + " =\n"; + return new ConcatSource(prefix, source); + } + }.bind(this)); + mainTemplate.plugin("global-hash", function(chunk) { + if(Template.REGEXP_HASH.test(this.varExpression || "")) + return true; + }.bind(this)); + mainTemplate.plugin("hash", function(hash) { + hash.update("set var"); + hash.update(this.varExpression + ""); + hash.update(this.copyObject + ""); + }.bind(this)); +}; \ No newline at end of file diff --git a/lib/Template.js b/lib/Template.js index da042a929..952a52ba4 100644 --- a/lib/Template.js +++ b/lib/Template.js @@ -2,9 +2,11 @@ MIT License http://www.opensource.org/licenses/mit-license.php Author Tobias Koppers @sokra */ +var Tapable = require("tapable"); var ConcatSource = require("webpack-core/lib/ConcatSource"); function Template(outputOptions) { + Tapable.call(this); this.outputOptions = outputOptions || {}; } module.exports = Template; @@ -17,11 +19,15 @@ Template.REGEXP_FILE = /\[file\]/gi; Template.REGEXP_QUERY = /\[query\]/gi; Template.REGEXP_FILEBASE = /\[filebase\]/gi; +Template.prototype = Object.create(Tapable.prototype); + Template.prototype.indent = function indent(str) { if(Array.isArray(str)) { return str.map(indent).join("\n"); } else { - return "\t" + str.trimRight().replace(/\n/g, "\n\t"); + str = str.trimRight(); + if(!str) return ""; + return (str[0] === "\n" ? "" : "\t") + str.replace(/\n([^\n])/g, "\n\t$1"); } }; @@ -29,7 +35,9 @@ Template.prototype.prefix = function(str, prefix) { if(Array.isArray(str)) { str = str.join("\n"); } - return prefix + str.trim().replace(/\n/g, "\n" + prefix); + str = str.trim(); + if(!str) return ""; + return (str[0] === "\n" ? "" : prefix) + str.replace(/\n([^\n])/g, "\n" + prefix + "$1"); }; Template.prototype.asString = function(str) { diff --git a/lib/UmdMainTemplateDecorator.js b/lib/UmdMainTemplateDecorator.js deleted file mode 100644 index 02e9455d4..000000000 --- a/lib/UmdMainTemplateDecorator.js +++ /dev/null @@ -1,103 +0,0 @@ -/* - MIT License http://www.opensource.org/licenses/mit-license.php - Author Tobias Koppers @sokra -*/ -var ConcatSource = require("webpack-core/lib/ConcatSource"); -var OriginalSource = require("webpack-core/lib/OriginalSource"); -var Template = require("./Template"); - -function accessorToObjectAccess(accessor) { - return accessor.map(function(a) { - return "[" + JSON.stringify(a) + "]"; - }).join(""); -} - -function accessorAccess(base, accessor) { - accessor = [].concat(accessor); - return accessor.map(function(a, idx) { - a = base + accessorToObjectAccess(accessor.slice(0, idx+1)); - if(idx === accessor.length - 1) return a; - return a + " = " + a + " || {}"; - }).join(", "); -} - -function UmdMainTemplateDecorator(mainTemplate, name) { - this.mainTemplate = mainTemplate; - this.name = name; -} -module.exports = UmdMainTemplateDecorator; -UmdMainTemplateDecorator.prototype.render = function(hash, chunk, moduleTemplate, dependencyTemplates) { - var source = this.mainTemplate.render(hash, chunk, moduleTemplate, dependencyTemplates); - var externals = chunk.modules.filter(function(m) { - return m.external; - }); - function replaceKeys(str) { - return (str - .replace(Template.REGEXP_HASH, hash) - .replace(Template.REGEXP_CHUNKHASH, chunk.renderedHash) - .replace(Template.REGEXP_ID, chunk.id) - .replace(Template.REGEXP_NAME, chunk.name || "")); - } - function externalsDepsArray() { - return "[" + replaceKeys(externals.map(function(m) { - return JSON.stringify(typeof m.request === "object" ? m.request.amd : m.request); - }).join(", ")) + "]"; - } - function externalsRootArray() { - return replaceKeys(externals.map(function(m) { - var request = m.request; - if(typeof request === "object") request = request.root; - return "root" + accessorToObjectAccess([].concat(request)); - }).join(", ")); - } - function externalsRequireArray(type) { - return replaceKeys(externals.map(function(m) { - var request = m.request; - if(typeof request === "object") request = request[type]; - if(Array.isArray(request)) { - return "require(" + JSON.stringify(request[0]) + ")" + accessorToObjectAccess(request.slice(1)); - } else - return "require(" + JSON.stringify(request) + ")"; - }).join(", ")); - } - var externalsArguments = externals.map(function(m) { - return "__WEBPACK_EXTERNAL_MODULE_" + m.id + "__"; - }).join(", "); - return new ConcatSource(new OriginalSource( - "(function webpackUniversalModuleDefinition(root, factory) {\n" + - " if(typeof exports === 'object' && typeof module === 'object')\n" + - " module.exports = factory(" + externalsRequireArray("commonjs2") + ");\n" + - " else if(typeof define === 'function' && define.amd)\n" + - (externalsArguments ? - " define(" + externalsDepsArray() + ", factory);\n" - : - " define(factory);\n" - ) + - (this.name ? - " else if(typeof exports === 'object')\n" + - " exports[" + JSON.stringify(replaceKeys([].concat(this.name).pop())) + "] = factory(" + externalsRequireArray("commonjs") + ");\n" + - " else\n" + - " " + replaceKeys(accessorAccess("root", this.name)) + " = factory(" + externalsRootArray() + ");\n" - : - " else {\n" + - (externalsArguments ? - " var a = typeof exports === 'object' ? factory(" + externalsRequireArray("commonjs") + ") : factory(" + externalsRootArray() + ");\n" - : - " var a = factory();\n" - ) + - " for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i];\n" + - " }\n" - ) + - "})(this, function(" + externalsArguments + ") {\nreturn ", "webpack/universalModuleDefinition"), source, "\n})\n"); -}; - -UmdMainTemplateDecorator.prototype.useChunkHash = function(chunk) { - if(!this.mainTemplate.useChunkHash || !this.mainTemplate.useChunkHash(chunk)) return false; - return !Template.REGEXP_HASH.test([].concat(this.name || "").join("|")); -}; - -UmdMainTemplateDecorator.prototype.updateHash = function(hash) { - hash.update("umd"); - hash.update(this.name + ""); - this.mainTemplate.updateHash(hash); -}; diff --git a/lib/UmdMainTemplatePlugin.js b/lib/UmdMainTemplatePlugin.js new file mode 100644 index 000000000..ebc53ed50 --- /dev/null +++ b/lib/UmdMainTemplatePlugin.js @@ -0,0 +1,100 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +var ConcatSource = require("webpack-core/lib/ConcatSource"); +var OriginalSource = require("webpack-core/lib/OriginalSource"); +var Template = require("./Template"); + +function accessorToObjectAccess(accessor) { + return accessor.map(function(a) { + return "[" + JSON.stringify(a) + "]"; + }).join(""); +} + +function accessorAccess(base, accessor) { + accessor = [].concat(accessor); + return accessor.map(function(a, idx) { + a = base + accessorToObjectAccess(accessor.slice(0, idx+1)); + if(idx === accessor.length - 1) return a; + return a + " = " + a + " || {}"; + }).join(", "); +} + +function UmdMainTemplatePlugin(name) { + this.name = name; +} +module.exports = UmdMainTemplatePlugin; +UmdMainTemplatePlugin.prototype.apply = function(mainTemplate) { + mainTemplate.plugin("render", function(source, chunk, hash) { + var externals = chunk.modules.filter(function(m) { + return m.external; + }); + function replaceKeys(str) { + return (str + .replace(Template.REGEXP_HASH, hash) + .replace(Template.REGEXP_CHUNKHASH, chunk.renderedHash) + .replace(Template.REGEXP_ID, chunk.id) + .replace(Template.REGEXP_NAME, chunk.name || "")); + } + function externalsDepsArray() { + return "[" + replaceKeys(externals.map(function(m) { + return JSON.stringify(typeof m.request === "object" ? m.request.amd : m.request); + }).join(", ")) + "]"; + } + function externalsRootArray() { + return replaceKeys(externals.map(function(m) { + var request = m.request; + if(typeof request === "object") request = request.root; + return "root" + accessorToObjectAccess([].concat(request)); + }).join(", ")); + } + function externalsRequireArray(type) { + return replaceKeys(externals.map(function(m) { + var request = m.request; + if(typeof request === "object") request = request[type]; + if(Array.isArray(request)) { + return "require(" + JSON.stringify(request[0]) + ")" + accessorToObjectAccess(request.slice(1)); + } else + return "require(" + JSON.stringify(request) + ")"; + }).join(", ")); + } + var externalsArguments = externals.map(function(m) { + return "__WEBPACK_EXTERNAL_MODULE_" + m.id + "__"; + }).join(", "); + return new ConcatSource(new OriginalSource( + "(function webpackUniversalModuleDefinition(root, factory) {\n" + + " if(typeof exports === 'object' && typeof module === 'object')\n" + + " module.exports = factory(" + externalsRequireArray("commonjs2") + ");\n" + + " else if(typeof define === 'function' && define.amd)\n" + + (externalsArguments ? + " define(" + externalsDepsArray() + ", factory);\n" + : + " define(factory);\n" + ) + + (this.name ? + " else if(typeof exports === 'object')\n" + + " exports[" + JSON.stringify(replaceKeys([].concat(this.name).pop())) + "] = factory(" + externalsRequireArray("commonjs") + ");\n" + + " else\n" + + " " + replaceKeys(accessorAccess("root", this.name)) + " = factory(" + externalsRootArray() + ");\n" + : + " else {\n" + + (externalsArguments ? + " var a = typeof exports === 'object' ? factory(" + externalsRequireArray("commonjs") + ") : factory(" + externalsRootArray() + ");\n" + : + " var a = factory();\n" + ) + + " for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i];\n" + + " }\n" + ) + + "})(this, function(" + externalsArguments + ") {\nreturn ", "webpack/universalModuleDefinition"), source, "\n})\n"); + }.bind(this)); + mainTemplate.plugin("global-hash", function(chunk) { + if(Template.REGEXP_HASH.test([].concat(this.name || "").join("|"))) + return true; + }.bind(this)); + mainTemplate.plugin("hash", function(hash) { + hash.update("umd"); + hash.update(this.name + ""); + }.bind(this)); +}; \ No newline at end of file diff --git a/lib/node/NodeMainTemplate.js b/lib/node/NodeMainTemplate.js deleted file mode 100644 index dd4c250c7..000000000 --- a/lib/node/NodeMainTemplate.js +++ /dev/null @@ -1,161 +0,0 @@ -/* - MIT License http://www.opensource.org/licenses/mit-license.php - Author Tobias Koppers @sokra -*/ -var MainTemplate = require("../MainTemplate"); -var Template = require("../Template"); - -function NodeMainTemplate(outputOptions, asyncChunkLoading) { - MainTemplate.call(this, outputOptions); - this.asyncChunkLoading = asyncChunkLoading; -} -module.exports = NodeMainTemplate; - -NodeMainTemplate.prototype = Object.create(MainTemplate.prototype); -NodeMainTemplate.prototype.constructor = NodeMainTemplate; - -NodeMainTemplate.prototype.renderLocalVars = function(hash, chunk) { - var buf = MainTemplate.prototype.renderLocalVars.call(this, hash, chunk); - if(chunk.chunks.length > 0) { - buf.push( - "", - "// object to store loaded chunks", - '// "1" means "already loaded"', - "var installedChunks = {", - this.indent( - chunk.ids.map(function(id) { - return id + ":1" - }).join(",\n") - ), - "};" - ); - } - return buf; -}; - -NodeMainTemplate.prototype.renderRequireEnsure = function(hash, chunk) { - var filename = this.outputOptions.filename || "bundle.js"; - var chunkFilename = this.outputOptions.chunkFilename || "[id]." + filename; - var insertMoreModules = [ - "var moreModules = chunk.modules, chunkIds = chunk.ids;", - "for(var moduleId in moreModules) {", - this.indent(this.renderAddModule(hash, chunk, "moduleId", "moreModules[moduleId]")), - "}" - ]; - if(this.asyncChunkLoading) { - return [ - "if(installedChunks[chunkId] === 1) callback.call(null, " + this.requireFn + ");", - "else if(!installedChunks[chunkId]) {", - this.indent([ - "installedChunks[chunkId] = [callback];", - "var filename = __dirname + " + JSON.stringify("/" + chunkFilename - .replace(Template.REGEXP_HASH, hash) - .replace(Template.REGEXP_NAME, "")) - .replace(Template.REGEXP_ID, "\" + chunkId + \"") + ";", - "require('fs').readFile(filename, 'utf-8', function(err, content) {", - this.indent([ - "if(err) { if(" + this.requireFn + ".onError) return " + this.requireFn + ".onError(err); else throw err; }", - "var chunk = {};", - "require('vm').runInThisContext('(function(exports) {' + content + '\\n})', filename)(chunk);", - ].concat(insertMoreModules).concat([ - "var callbacks = [];", - "for(var i = 0; i < chunkIds.length; i++) {", - this.indent([ - "if(Array.isArray(installedChunks[chunkIds[i]]))", - this.indent([ - "callbacks = callbacks.concat(installedChunks[chunkIds[i]]);" - ]), - "installedChunks[chunkIds[i]] = 1;" - ]), - "}", - "for(i = 0; i < callbacks.length; i++)", - this.indent("callbacks[i].call(null, " + this.requireFn + ");") - ])), - "});" - ]), - "} else installedChunks[chunkId].push(callback);", - ]; - } else { - return [ - "// \"1\" is the signal for \"already loaded\"", - "if(!installedChunks[chunkId]) {", - this.indent([ - "var chunk = require(" + - JSON.stringify("./" + chunkFilename - .replace(Template.REGEXP_HASH, hash) - .replace(Template.REGEXP_NAME, "")) - .replace(Template.REGEXP_ID, "\" + chunkId + \"") + ");" - ].concat(insertMoreModules).concat([ - "for(var i = 0; i < chunkIds.length; i++)", - this.indent("installedChunks[chunkIds[i]] = 1;"), - ])), - "}", - "callback.call(null, " + this.requireFn + ");", - ]; - } -}; - -NodeMainTemplate.prototype.renderHotModuleReplacementInit = function(hash, chunk) { - var hotUpdateChunkFilename = this.outputOptions.hotUpdateChunkFilename; - var hotUpdateMainFilename = this.outputOptions.hotUpdateMainFilename; - var hotUpdateFunction = this.outputOptions.hotUpdateFunction || ("webpackHotUpdate" + (this.outputOptions.library || "")); - var currentHotUpdateChunkFilename = JSON.stringify(hotUpdateChunkFilename) - .replace(Template.REGEXP_HASH, "\" + " + this.renderCurrentHashCode(hash) + " + \"") - .replace(Template.REGEXP_ID, "\" + chunkId + \""); - var currentHotUpdateMainFilename = JSON.stringify(hotUpdateMainFilename) - .replace(Template.REGEXP_HASH, "\" + " + this.renderCurrentHashCode(hash) + " + \""); - return Template.getFunctionContent(this.asyncChunkLoading ? function() { - function hotDownloadUpdateChunk(chunkId) { - var filename = require("path").join(__dirname, $hotChunkFilename$); - require("fs").readFile(filename, "utf-8", function(err, content) { - if(err) { - if($require$.onError) - return $require$.onError(err); - else - throw err; - } - var chunk = {}; - require("vm").runInThisContext("(function(exports) {" + content + "\n})", filename)(chunk); - hotAddUpdateChunk(chunk.id, chunk.modules); - }); - } - - function hotDownloadManifest(callback) { - var filename = require("path").join(__dirname, $hotMainFilename$); - require("fs").readFile(filename, "utf-8", function(err, content) { - if(err) return callback(); - try { - var update = JSON.parse(content); - } catch(e) { - return callback(e); - } - callback(null, update); - }); - } - } : function() { - function hotDownloadUpdateChunk(chunkId) { - var chunk = require("./" + $hotChunkFilename$); - hotAddUpdateChunk(chunk.id, chunk.modules); - } - - function hotDownloadManifest(callback) { - try { - var update = require("./" + $hotMainFilename$); - } catch(e) { - return callback(); - } - callback(null, update); - } - }) - .replace(/\$require\$/g, this.requireFn) - .replace(/\$hotMainFilename\$/g, currentHotUpdateMainFilename) - .replace(/\$hotChunkFilename\$/g, currentHotUpdateChunkFilename); -}; - -NodeMainTemplate.prototype.updateHash = function(hash) { - MainTemplate.prototype.updateHash.call(this, hash); - hash.update("node"); - hash.update("3"); - hash.update(this.outputOptions.filename + ""); - hash.update(this.outputOptions.chunkFilename + ""); -}; \ No newline at end of file diff --git a/lib/node/NodeMainTemplatePlugin.js b/lib/node/NodeMainTemplatePlugin.js new file mode 100644 index 000000000..0c16786e8 --- /dev/null +++ b/lib/node/NodeMainTemplatePlugin.js @@ -0,0 +1,154 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +var Template = require("../Template"); + +function NodeMainTemplatePlugin(asyncChunkLoading) { + this.asyncChunkLoading = asyncChunkLoading; +} +module.exports = NodeMainTemplatePlugin; +NodeMainTemplatePlugin.prototype.apply = function(mainTemplate) { + var self = this; + mainTemplate.plugin("local-vars", function(source, chunk, hash) { + if(chunk.chunks.length > 0) { + return this.asString([ + source, + "", + "// object to store loaded chunks", + '// "1" means "already loaded"', + "var installedChunks = {", + this.indent( + chunk.ids.map(function(id) { + return id + ":1" + }).join(",\n") + ), + "};" + ]); + } + return source; + }); + mainTemplate.plugin("require-ensure", function(_, chunk, hash) { + var filename = this.outputOptions.filename || "bundle.js"; + var chunkFilename = this.outputOptions.chunkFilename || "[id]." + filename; + var insertMoreModules = [ + "var moreModules = chunk.modules, chunkIds = chunk.ids;", + "for(var moduleId in moreModules) {", + this.indent(this.renderAddModule(hash, chunk, "moduleId", "moreModules[moduleId]")), + "}" + ]; + if(self.asyncChunkLoading) { + return this.asString([ + "if(installedChunks[chunkId] === 1) callback.call(null, " + this.requireFn + ");", + "else if(!installedChunks[chunkId]) {", + this.indent([ + "installedChunks[chunkId] = [callback];", + "var filename = __dirname + " + JSON.stringify("/" + chunkFilename + .replace(Template.REGEXP_HASH, hash) + .replace(Template.REGEXP_NAME, "")) + .replace(Template.REGEXP_ID, "\" + chunkId + \"") + ";", + "require('fs').readFile(filename, 'utf-8', function(err, content) {", + this.indent([ + "if(err) { if(" + this.requireFn + ".onError) return " + this.requireFn + ".onError(err); else throw err; }", + "var chunk = {};", + "require('vm').runInThisContext('(function(exports) {' + content + '\\n})', filename)(chunk);", + ].concat(insertMoreModules).concat([ + "var callbacks = [];", + "for(var i = 0; i < chunkIds.length; i++) {", + this.indent([ + "if(Array.isArray(installedChunks[chunkIds[i]]))", + this.indent([ + "callbacks = callbacks.concat(installedChunks[chunkIds[i]]);" + ]), + "installedChunks[chunkIds[i]] = 1;" + ]), + "}", + "for(i = 0; i < callbacks.length; i++)", + this.indent("callbacks[i].call(null, " + this.requireFn + ");") + ])), + "});" + ]), + "} else installedChunks[chunkId].push(callback);", + ]); + } else { + return this.asString([ + "// \"1\" is the signal for \"already loaded\"", + "if(!installedChunks[chunkId]) {", + this.indent([ + "var chunk = require(" + + JSON.stringify("./" + chunkFilename + .replace(Template.REGEXP_HASH, hash) + .replace(Template.REGEXP_NAME, "")) + .replace(Template.REGEXP_ID, "\" + chunkId + \"") + ");" + ].concat(insertMoreModules).concat([ + "for(var i = 0; i < chunkIds.length; i++)", + this.indent("installedChunks[chunkIds[i]] = 1;"), + ])), + "}", + "callback.call(null, " + this.requireFn + ");", + ]); + } + }); + mainTemplate.plugin("hot-bootstrap", function(source, chunk, hash) { + var hotUpdateChunkFilename = this.outputOptions.hotUpdateChunkFilename; + var hotUpdateMainFilename = this.outputOptions.hotUpdateMainFilename; + var hotUpdateFunction = this.outputOptions.hotUpdateFunction || ("webpackHotUpdate" + (this.outputOptions.library || "")); + var currentHotUpdateChunkFilename = JSON.stringify(hotUpdateChunkFilename) + .replace(Template.REGEXP_HASH, "\" + " + this.renderCurrentHashCode(hash) + " + \"") + .replace(Template.REGEXP_ID, "\" + chunkId + \""); + var currentHotUpdateMainFilename = JSON.stringify(hotUpdateMainFilename) + .replace(Template.REGEXP_HASH, "\" + " + this.renderCurrentHashCode(hash) + " + \""); + return Template.getFunctionContent(self.asyncChunkLoading ? function() { + function hotDownloadUpdateChunk(chunkId) { + var filename = require("path").join(__dirname, $hotChunkFilename$); + require("fs").readFile(filename, "utf-8", function(err, content) { + if(err) { + if($require$.onError) + return $require$.onError(err); + else + throw err; + } + var chunk = {}; + require("vm").runInThisContext("(function(exports) {" + content + "\n})", filename)(chunk); + hotAddUpdateChunk(chunk.id, chunk.modules); + }); + } + + function hotDownloadManifest(callback) { + var filename = require("path").join(__dirname, $hotMainFilename$); + require("fs").readFile(filename, "utf-8", function(err, content) { + if(err) return callback(); + try { + var update = JSON.parse(content); + } catch(e) { + return callback(e); + } + callback(null, update); + }); + } + } : function() { + function hotDownloadUpdateChunk(chunkId) { + var chunk = require("./" + $hotChunkFilename$); + hotAddUpdateChunk(chunk.id, chunk.modules); + } + + function hotDownloadManifest(callback) { + try { + var update = require("./" + $hotMainFilename$); + } catch(e) { + return callback(); + } + callback(null, update); + } + }) + .replace(/\$require\$/g, this.requireFn) + .replace(/\$hotMainFilename\$/g, currentHotUpdateMainFilename) + .replace(/\$hotChunkFilename\$/g, currentHotUpdateChunkFilename); + }); + mainTemplate.plugin("hash", function(hash) { + hash.update("node"); + hash.update("3"); + hash.update(this.outputOptions.filename + ""); + hash.update(this.outputOptions.chunkFilename + ""); + }); +}; diff --git a/lib/node/NodeTemplatePlugin.js b/lib/node/NodeTemplatePlugin.js index 18b06a5d4..0f7179f35 100644 --- a/lib/node/NodeTemplatePlugin.js +++ b/lib/node/NodeTemplatePlugin.js @@ -2,7 +2,7 @@ MIT License http://www.opensource.org/licenses/mit-license.php Author Tobias Koppers @sokra */ -var NodeMainTemplate = require("./NodeMainTemplate"); +var NodeMainTemplatePlugin = require("./NodeMainTemplatePlugin"); var NodeChunkTemplate = require("./NodeChunkTemplate"); var NodeHotUpdateChunkTemplate = require("./NodeHotUpdateChunkTemplate"); @@ -13,7 +13,9 @@ function NodeTemplatePlugin(options, asyncChunkLoading) { module.exports = NodeTemplatePlugin; NodeTemplatePlugin.prototype.apply = function(compiler) { var options = this.options; - compiler.mainTemplate = new NodeMainTemplate(options, this.asyncChunkLoading); + compiler.plugin("this-compilation", function(compilation) { + compilation.mainTemplate.apply(new NodeMainTemplatePlugin(this.asyncChunkLoading)); + }.bind(this)); compiler.chunkTemplate = new NodeChunkTemplate(options); compiler.hotUpdateChunkTemplate = new NodeHotUpdateChunkTemplate(options); }; diff --git a/lib/optimize/DedupePlugin.js b/lib/optimize/DedupePlugin.js index cc3c66979..a06d93d3a 100644 --- a/lib/optimize/DedupePlugin.js +++ b/lib/optimize/DedupePlugin.js @@ -102,13 +102,13 @@ DedupePlugin.prototype.apply = function(compiler) { }); compiler.plugin("after-plugins", function(compiler) { compiler.moduleTemplate = new DedupModuleTemplateDecorator(compiler.moduleTemplate); - compiler.mainTemplate = Object.create(compiler.mainTemplate); - var oldRenderAddModule = compiler.mainTemplate.renderAddModule; - compiler.mainTemplate.renderAddModule = function(hash, chunk, varModuleId, varModule) { + }); + compiler.plugin("compilation", function(compilation) { + compilation.mainTemplate.plugin("add-module", function(source, chunk, hash, varModuleId, varModule) { if(!chunk._DedupePlugin_hasDeduplicatedModules) { - return oldRenderAddModule.call(this, hash, chunk, varModuleId, varModule); + return source; } - return [ + return this.asString([ "var _m = " + varModule + ";", "", "// Check if module is deduplicated", @@ -140,12 +140,11 @@ DedupePlugin.prototype.apply = function(compiler) { "modules[" + varModuleId + "] = _m;" ]), "}" - ] - }; - var oldRenderModules = compiler.mainTemplate.renderModules; - compiler.mainTemplate.renderModules = function renderModules(hash, chunk, moduleTemplate, dependencyTemplates) { + ]); + }); + compilation.mainTemplate.plugin("modules", function(orginalSource, chunk, hash, moduleTemplate, dependencyTemplates) { if(!chunk._DedupePlugin_hasDeduplicatedModules) { - return oldRenderModules.call(this, hash, chunk, moduleTemplate, dependencyTemplates); + return orginalSource; } var source = new ConcatSource(); source.add("(function(modules) {\n"); @@ -180,10 +179,10 @@ DedupePlugin.prototype.apply = function(compiler) { "return modules;" ])); source.add("\n}("); - source.add(oldRenderModules.call(this, hash, chunk, moduleTemplate, dependencyTemplates)); + source.add(orginalSource); source.add("))"); return source; - }; + }); }); }; diff --git a/lib/webworker/WebWorkerMainTemplate.js b/lib/webworker/WebWorkerMainTemplate.js deleted file mode 100644 index cbb22358f..000000000 --- a/lib/webworker/WebWorkerMainTemplate.js +++ /dev/null @@ -1,84 +0,0 @@ -/* - MIT License http://www.opensource.org/licenses/mit-license.php - Author Tobias Koppers @sokra -*/ -var MainTemplate = require("../MainTemplate"); -var Template = require("../Template"); - -function WebWorkerMainTemplate(outputOptions) { - MainTemplate.call(this, outputOptions); -} -module.exports = WebWorkerMainTemplate; - -WebWorkerMainTemplate.prototype = Object.create(MainTemplate.prototype); - -WebWorkerMainTemplate.prototype.renderLocalVars = function(hash, chunk) { - var buf = MainTemplate.prototype.renderLocalVars.call(this, hash, chunk); - if(chunk.chunks.length > 0) { - buf.push( - "", - "// object to store loaded chunks", - '// "1" means "already loaded"', - "var installedChunks = {", - this.indent( - chunk.ids.map(function(id) { - return id + ":1" - }).join(",\n") - ), - "};" - ); - } - return buf; -}; - -WebWorkerMainTemplate.prototype.renderRequireEnsure = function(hash, chunk) { - var filename = this.outputOptions.filename || "bundle.js"; - var chunkFilename = this.outputOptions.chunkFilename || "[id]." + filename; - return [ - "// \"1\" is the signal for \"already loaded\"", - "if(!installedChunks[chunkId]) {", - this.indent([ - "importScripts(" + - JSON.stringify(chunkFilename - .replace(Template.REGEXP_NAME, "")) - .replace(Template.REGEXP_HASH, "\" + " + this.renderCurrentHashCode(hash) + " + \"") - .replace(Template.REGEXP_ID, "\" + chunkId + \"") + ");" - ]), - "}", - "callback.call(null, " + this.requireFn + ");" - ]; -}; - -WebWorkerMainTemplate.prototype.renderInit = function(hash, chunk) { - var buf = MainTemplate.prototype.renderInit.call(this, hash, chunk); - if(chunk.chunks.length > 0) { - var chunkCallbackName = this.outputOptions.chunkCallbackName || ("webpackChunk" + (this.outputOptions.library || "")); - buf.push( - "this[" + JSON.stringify(chunkCallbackName) + "] = function webpackChunkCallback(chunkIds, moreModules) {", - this.indent([ - "for(var moduleId in moreModules) {", - this.indent(this.renderAddModule(hash, chunk, "moduleId", "moreModules[moduleId]")), - "}", - "while(chunkIds.length)", - this.indent("installedChunks[chunkIds.pop()] = 1;") - ]), - "};" - ); - } - return buf; -}; - -WebWorkerMainTemplate.prototype.renderCurrentHashCode = function(hash) { - return JSON.stringify(hash); -}; - -WebWorkerMainTemplate.prototype.updateHash = function(hash) { - MainTemplate.prototype.updateHash.call(this, hash); - hash.update("webworker"); - hash.update("3"); - hash.update(this.outputOptions.publicPath + ""); - hash.update(this.outputOptions.filename + ""); - hash.update(this.outputOptions.chunkFilename + ""); - hash.update(this.outputOptions.chunkCallbackName + ""); - hash.update(this.outputOptions.library + ""); -}; \ No newline at end of file diff --git a/lib/webworker/WebWorkerMainTemplatePlugin.js b/lib/webworker/WebWorkerMainTemplatePlugin.js new file mode 100644 index 000000000..72e1651f1 --- /dev/null +++ b/lib/webworker/WebWorkerMainTemplatePlugin.js @@ -0,0 +1,74 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +var Template = require("../Template"); + +function WebWorkerMainTemplatePlugin() { +} +module.exports = WebWorkerMainTemplatePlugin; + +WebWorkerMainTemplatePlugin.prototype.apply = function(mainTemplate) { + mainTemplate.plugin("local-vars", function(source, chunk, hash) { + if(chunk.chunks.length > 0) { + return this.asString([ + source, + "", + "// object to store loaded chunks", + '// "1" means "already loaded"', + "var installedChunks = {", + this.indent( + chunk.ids.map(function(id) { + return id + ":1" + }).join(",\n") + ), + "};" + ]); + } + return source; + }); + mainTemplate.plugin("require-ensure", function(_, chunk, hash) { + var filename = this.outputOptions.filename || "bundle.js"; + var chunkFilename = this.outputOptions.chunkFilename || "[id]." + filename; + return this.asString([ + "// \"1\" is the signal for \"already loaded\"", + "if(!installedChunks[chunkId]) {", + this.indent([ + "importScripts(" + + JSON.stringify(chunkFilename + .replace(Template.REGEXP_NAME, "")) + .replace(Template.REGEXP_HASH, "\" + " + this.renderCurrentHashCode(hash) + " + \"") + .replace(Template.REGEXP_ID, "\" + chunkId + \"") + ");" + ]), + "}", + "callback.call(null, " + this.requireFn + ");" + ]); + }); + mainTemplate.plugin("bootstrap", function(source, chunk, hash) { + if(chunk.chunks.length > 0) { + var chunkCallbackName = this.outputOptions.chunkCallbackName || ("webpackChunk" + (this.outputOptions.library || "")); + return this.asString([ + source, + "this[" + JSON.stringify(chunkCallbackName) + "] = function webpackChunkCallback(chunkIds, moreModules) {", + this.indent([ + "for(var moduleId in moreModules) {", + this.indent(this.renderAddModule(hash, chunk, "moduleId", "moreModules[moduleId]")), + "}", + "while(chunkIds.length)", + this.indent("installedChunks[chunkIds.pop()] = 1;") + ]), + "};" + ]); + } + return source; + }); + mainTemplate.plugin("hash", function(hash) { + hash.update("webworker"); + hash.update("3"); + hash.update(this.outputOptions.publicPath + ""); + hash.update(this.outputOptions.filename + ""); + hash.update(this.outputOptions.chunkFilename + ""); + hash.update(this.outputOptions.chunkCallbackName + ""); + hash.update(this.outputOptions.library + ""); + }); +}; diff --git a/lib/webworker/WebWorkerTemplatePlugin.js b/lib/webworker/WebWorkerTemplatePlugin.js index 5107e650d..23b619be8 100644 --- a/lib/webworker/WebWorkerTemplatePlugin.js +++ b/lib/webworker/WebWorkerTemplatePlugin.js @@ -2,7 +2,7 @@ MIT License http://www.opensource.org/licenses/mit-license.php Author Tobias Koppers @sokra */ -var WebWorkerMainTemplate = require("./WebWorkerMainTemplate"); +var WebWorkerMainTemplatePlugin = require("./WebWorkerMainTemplatePlugin"); var WebWorkerChunkTemplate = require("./WebWorkerChunkTemplate"); function WebWorkerTemplatePlugin(options) { @@ -11,6 +11,8 @@ function WebWorkerTemplatePlugin(options) { module.exports = WebWorkerTemplatePlugin; WebWorkerTemplatePlugin.prototype.apply = function(compiler) { var options = this.options; - compiler.mainTemplate = new WebWorkerMainTemplate(options); + compiler.plugin("this-compilation", function(compilation) { + compilation.mainTemplate.apply(new WebWorkerMainTemplatePlugin()); + }); compiler.chunkTemplate = new WebWorkerChunkTemplate(options); }; \ No newline at end of file diff --git a/package.json b/package.json index 40d94b56a..d61838e08 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "clone": "0.1.x", "webpack-core": "0.4.x", "node-libs-browser": "0.3.x", - "tapable": "0.1.x" + "tapable": "~0.1.6" }, "licenses": [ {