Last active
January 5, 2019 06:55
-
-
Save mbixby/3dae2026a77a9a3d3de9 to your computer and use it in GitHub Desktop.
Webpack Named Modules Plugin
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var RequestShortener = require("webpack/lib/RequestShortener"); | |
var _ = require("lodash"); | |
/** | |
* TODO Docs | |
* @example new NamedModulesPlugin(/^\.\/app\/(viewmodels|records|adapters)/, /^\.\/app\/(.*)\.js$/) | |
*/ | |
function NamedModulesPlugin(fileWhitelistRegex, replacementRegex) { | |
this.fileWhitelistRegex = fileWhitelistRegex; | |
this.replacementRegex = replacementRegex; | |
} | |
module.exports = NamedModulesPlugin; | |
NamedModulesPlugin.prototype.apply = function(compiler) { | |
if (!this.fileWhitelistRegex) throw new Error(); | |
if (!this.replacementRegex) throw new Error(); | |
var fileWhitelistRegex = this.fileWhitelistRegex; | |
var replacementRegex = this.replacementRegex; | |
var compilerContext = compiler.context; | |
compiler.plugin("this-compilation", function(compilation) { | |
var mainTemplate = compilation.mainTemplate; | |
mainTemplate.plugin("local-vars", function(source, chunk/*, hash*/) { | |
var self = this; | |
var buf = []; | |
buf.push(this.asString([ | |
source, | |
"// The module cache", | |
"var installedModules = {};" | |
])); | |
buf.push("// Module request paths (NamedModulesPlugin)"); | |
buf.push(this.requireFn + ".moduleNames = {"); | |
chunk.modules.forEach(function(m){ | |
var requestShortener = new RequestShortener(compilerContext); | |
var shortened = requestShortener.shorten(m.userRequest); | |
var isWhitelisted = shortened && shortened.match(fileWhitelistRegex); | |
if (isWhitelisted){ | |
var name = shortened && shortened.replace(replacementRegex, '$1'); | |
buf.push(self.indent(m.id + ": '" + name + "',")); | |
} | |
}); | |
buf.push("};"); | |
return this.asString(buf); | |
}); | |
// TODO Refactor | |
// See monkey-patch below | |
var requirePlugin = 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;", | |
"", | |
"// (NamedModulesPlugin) Set __moduleName__ on prototype of exported module", | |
"var moduleName = " + this.requireFn + ".moduleNames[moduleId];", | |
"if (moduleName && typeof module.exports === 'function'){", | |
this.indent("module.exports.prototype.__moduleId__ = moduleName;"), | |
"}", | |
"// Return the exports of the module", | |
"return module.exports;" | |
]); | |
}; | |
requirePlugin.__namedModulesPlugin = true; | |
mainTemplate.plugin("require", requirePlugin); | |
}); | |
}; | |
// TODO Temporary | |
// Monkey-patch MainTemplate.prototype.applyPluginsWaterfall to throw away the original tapable "render" plugin (defined in MainTemplate constructor). We only want to use the "render" plugin defined above. | |
var MainTemplate = require("webpack/lib/MainTemplate"); | |
var orig = MainTemplate.prototype.applyPluginsWaterfall; | |
MainTemplate.prototype.applyPluginsWaterfall = function(){ | |
if (this._plugins["require"].length > 1){ | |
this._plugins["require"] = _.filter(this._plugins["require"], '__namedModulesPlugin'); | |
} | |
return orig.apply(this, arguments); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment