├── .gitignore ├── IndexHtmlSource.js ├── LICENSE ├── README.md ├── index.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | .* 2 | !.gitignore 3 | 4 | *.iml 5 | 6 | # Logs 7 | logs 8 | *.log 9 | 10 | # Runtime data 11 | pids 12 | *.pid 13 | *.seed 14 | 15 | # Directory for instrumented libs generated by jscoverage/JSCover 16 | lib-cov 17 | 18 | # Coverage directory used by tools like istanbul 19 | coverage 20 | 21 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 22 | .grunt 23 | 24 | # node-waf configuration 25 | .lock-wscript 26 | 27 | # Compiled binary addons (http://nodejs.org/api/addons.html) 28 | build/Release 29 | 30 | # Dependency directory 31 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 32 | node_modules 33 | -------------------------------------------------------------------------------- /IndexHtmlSource.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var cheerio = require('cheerio'); 3 | var URI = require('URIjs'); 4 | var _ = require('lodash'); 5 | var Source = require('webpack/lib/Source'); 6 | 7 | /** 8 | * @class 9 | * @extends Source 10 | * @param {Module} sourceModule 11 | * @param {Chunk} sourceChunk 12 | * @param {Compilation} compilation 13 | */ 14 | function IndexHtmlSource(sourceModule, sourceChunk, compilation) { 15 | this.sourceModule = sourceModule; 16 | this.sourceChunk = sourceChunk; 17 | this.compilation = compilation; 18 | } 19 | module.exports = IndexHtmlSource; 20 | 21 | IndexHtmlSource.prototype = Object.create(Source.prototype); 22 | IndexHtmlSource.prototype.constructor = IndexHtmlSource; 23 | 24 | IndexHtmlSource.prototype.source = function() { 25 | var html = this._getHtmlFromModule(); 26 | var $ = cheerio.load(html); 27 | coalesceLinks($); 28 | this._resolveScripts($); 29 | return $.html(); 30 | }; 31 | 32 | 33 | /** 34 | * Extracts the HTML code from the module source 35 | */ 36 | IndexHtmlSource.prototype._getHtmlFromModule = function() { 37 | 38 | var compilation = this.compilation; 39 | var sourceChunk = this.sourceChunk; 40 | 41 | 42 | function moduleWasExtracted(module) { 43 | return module.loaders && module.loaders.some(function(loader) { 44 | return loader.match(/extract-text-webpack-plugin/); 45 | }) 46 | } 47 | 48 | 49 | function getExtractTextLoaderOptions(module) { 50 | for (var i = 0; i < module.loaders.length; i++) { 51 | var loader = module.loaders[i]; 52 | var match = loader.match(/extract-text-webpack-plugin[\\/]loader\.js\?({.*})/); 53 | if (match) { 54 | return JSON.parse(match[1]); 55 | } 56 | } 57 | } 58 | 59 | 60 | function getExtractedFilename(module) { 61 | 62 | var options = getExtractTextLoaderOptions(module); 63 | var loaderId = options && options.id; 64 | 65 | var extractTextPlugin = _.find(compilation.compiler.options.plugins, 66 | function (p) { 67 | return (p.constructor.name === 'ExtractTextPlugin') && 68 | ((typeof(p.id) === "undefined" && typeof(loaderId) === "undefined") || (p.id === loaderId)); 69 | }); 70 | 71 | var filenamePattern = extractTextPlugin.filename 72 | .replace(/\[(?:\w+:)?(contenthash)(?::[a-z]+\d*)?(?::(\d+))?]|([^\[\]]+)/ig, 73 | function(match, contentHash, maxLength, literalPart) { 74 | if (contentHash) { 75 | if (maxLength) { 76 | return '[a-f0-9]{1,' + maxLength + '}'; 77 | } else { 78 | return '[a-f0-9]+'; 79 | } 80 | } else { 81 | return regexpQuote(literalPart); 82 | } 83 | }); 84 | filenamePattern = new RegExp(filenamePattern); 85 | 86 | return _.find(sourceChunk.files, function(filename) { 87 | return filename.match(filenamePattern); 88 | }); 89 | } 90 | 91 | 92 | function __webpack_require__(moduleId) { 93 | 94 | var sourceModule; 95 | if (typeof moduleId === "number") { 96 | sourceModule = _.find(compilation.modules, function (m) { 97 | return m.id === moduleId; 98 | }); 99 | } else { 100 | sourceModule = moduleId; 101 | } 102 | 103 | if (!sourceModule) { 104 | return undefined; 105 | } 106 | 107 | if (_.endsWith(sourceModule.context, path.normalize('webpack-dev-server/client')) || 108 | _.endsWith(sourceModule.context, path.normalize('webpack/hot'))) { 109 | return undefined; 110 | 111 | } else if (moduleWasExtracted(sourceModule)) { 112 | return (compilation.options.output.publicPath || '') + getExtractedFilename(sourceModule); 113 | 114 | } else { 115 | var module = {}; 116 | 117 | var source = sourceModule.source(null, {}); 118 | eval(source.source()); 119 | 120 | return module.exports; 121 | } 122 | } 123 | 124 | // This is where the "real" __webpack_require__ would store the public path, 125 | // it is used by url-loader to construct the link 126 | __webpack_require__.p = compilation.options.output.publicPath || ''; 127 | 128 | return __webpack_require__(this.sourceModule); 129 | }; 130 | 131 | 132 | /** 133 | * Resolve