Skip to content

Commit 860ee49

Browse files
committed
fixed hot reload file if dev tools is eval, use stringify request for require -> fixed env agnostic tests
1 parent 7b150ee commit 860ee49

File tree

17 files changed

+178
-59
lines changed

17 files changed

+178
-59
lines changed

index.js

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,17 @@ ExtractTextPlugin.prototype.apply = function(compiler) {
254254
var filename = this.filename;
255255
var id = this.id;
256256
var extractedChunks, entryChunks, initialChunks;
257+
258+
const getPath = (source, chunk) => (format) => compilation.getPath(format, {
259+
chunk: chunk
260+
}).replace(/\[(?:(\w+):)?contenthash(?::([a-z]+\d*))?(?::(\d+))?\]/ig, function() {
261+
return loaderUtils.getHashDigest(source, arguments[1], arguments[2], parseInt(arguments[3], 10));
262+
});
263+
264+
var getFile =(module, chunk) => (isFunction(filename)) ?
265+
filename(getPath(module.source(), chunk)) :
266+
getPath(module.source(), chunk)(filename);
267+
257268
compilation.plugin("optimize-tree", function(chunks, modules, callback) {
258269
extractedChunks = chunks.map(function() {
259270
return new Chunk();
@@ -319,10 +330,11 @@ ExtractTextPlugin.prototype.apply = function(compiler) {
319330
callback();
320331
});
321332
} else {
322-
if(meta.content)
333+
if(meta.content) {
323334
extractCompilation.addResultToChunk(
324335
module.identifier(), meta.content, module, extractedChunk
325336
);
337+
}
326338
callback();
327339
}
328340
} else callback();
@@ -371,7 +383,22 @@ ExtractTextPlugin.prototype.apply = function(compiler) {
371383
});
372384
}
373385
});
386+
387+
// HMR: inject file name into corresponding javascript modules in order to trigger
388+
// appropriate hot module reloading of CSS
389+
extractedChunks.forEach(function(extractedChunk) {
390+
extractedChunk.modules.forEach(function (module) {
391+
if(module.__fileInjected) {
392+
return;
393+
}
394+
module.__fileInjected = true;
395+
var file = getFile(module, extractedChunk);
396+
var originalModule = module.getOriginalModule();
397+
originalModule._source._value = originalModule._source._value.replace("%%extracted-file%%", file);
398+
});
399+
})
374400
});
401+
375402
compilation.plugin("additional-assets", function(callback) {
376403
extractedChunks.forEach(function(extractedChunk) {
377404
if(extractedChunk.modules.length) {
@@ -383,26 +410,11 @@ ExtractTextPlugin.prototype.apply = function(compiler) {
383410
return getOrder(a, b);
384411
});
385412
var chunk = extractedChunk.originalChunk;
386-
var source = this.renderExtractedChunk(extractedChunk);
387-
388-
var getPath = (format) => compilation.getPath(format, {
389-
chunk: chunk
390-
}).replace(/\[(?:(\w+):)?contenthash(?::([a-z]+\d*))?(?::(\d+))?\]/ig, function() {
391-
return loaderUtils.getHashDigest(source.source(), arguments[1], arguments[2], parseInt(arguments[3], 10));
392-
});
393-
394-
var file = (isFunction(filename)) ? filename(getPath) : getPath(filename);
395-
413+
var module = this.renderExtractedChunk(extractedChunk);
414+
var file = getFile(module, extractedChunk);
396415
// add the css files to assets and the files array corresponding to its chunk
397-
compilation.assets[file] = source;
416+
compilation.assets[file] = module;
398417
chunk.files.push(file);
399-
400-
// HMR: inject file name into corresponding javascript modules in order to trigger
401-
// appropriate hot module reloading of CSS
402-
extractedChunk.modules.forEach(function(module){
403-
var originalModule = module.getOriginalModule();
404-
originalModule._source._value = originalModule._source._value.replace('%%extracted-file%%', file);
405-
});
406418
}
407419
}, this);
408420
callback();

loader.js

Lines changed: 39 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,42 @@
11
/*
2-
MIT License http://www.opensource.org/licenses/mit-license.php
3-
Author Tobias Koppers @sokra
4-
*/
2+
MIT License http://www.opensource.org/licenses/mit-license.php
3+
Author Tobias Koppers @sokra
4+
*/
55
var fs = require("fs");
66
var loaderUtils = require("loader-utils");
77
var NodeTemplatePlugin = require("webpack/lib/node/NodeTemplatePlugin");
88
var NodeTargetPlugin = require("webpack/lib/node/NodeTargetPlugin");
99
var LibraryTemplatePlugin = require("webpack/lib/LibraryTemplatePlugin");
1010
var SingleEntryPlugin = require("webpack/lib/SingleEntryPlugin");
1111
var LimitChunkCountPlugin = require("webpack/lib/optimize/LimitChunkCountPlugin");
12-
12+
var path = require('path');
1313
var NS = fs.realpathSync(__dirname);
1414

15-
module.exports = function(source) {
15+
module.exports = function (source) {
16+
if(this.cacheable) this.cacheable();
1617
return source;
1718
};
1819

19-
module.exports.pitch = function(request) {
20+
module.exports.pitch = function (request) {
2021
var query = loaderUtils.getOptions(this) || {};
2122
var loaders = this.loaders.slice(this.loaderIndex + 1);
2223
this.addDependency(this.resourcePath);
2324
// We already in child compiler, return empty bundle
24-
if(this[NS] === undefined) {
25+
if (this[NS] === undefined) {
2526
throw new Error(
2627
'"extract-text-webpack-plugin" loader is used without the corresponding plugin, ' +
2728
'refer to https://github.com/webpack/extract-text-webpack-plugin for the usage example'
2829
);
29-
} else if(this[NS] === false) {
30+
} else if (this[NS] === false) {
3031
return "";
31-
} else if(this[NS](null, query)) {
32-
if(query.omit) {
32+
} else if (this[NS](null, query)) {
33+
if (query.omit) {
3334
this.loaderIndex += +query.omit + 1;
3435
request = request.split("!").slice(+query.omit).join("!");
3536
loaders = loaders.slice(+query.omit);
3637
}
3738
var resultSource;
38-
if(query.remove) {
39+
if (query.remove) {
3940
resultSource = "// removed by extract-text-webpack-plugin";
4041
} else {
4142
resultSource = undefined;
@@ -52,22 +53,22 @@ module.exports.pitch = function(request) {
5253
childCompiler.apply(new LibraryTemplatePlugin(null, "commonjs2"));
5354
childCompiler.apply(new NodeTargetPlugin());
5455
childCompiler.apply(new SingleEntryPlugin(this.context, "!!" + request));
55-
childCompiler.apply(new LimitChunkCountPlugin({ maxChunks: 1 }));
56+
childCompiler.apply(new LimitChunkCountPlugin({maxChunks: 1}));
5657
var subCache = "subcache " + NS + " " + request; // eslint-disable-line no-path-concat
57-
childCompiler.plugin("compilation", function(compilation) {
58-
if(compilation.cache) {
59-
if(!compilation.cache[subCache])
58+
childCompiler.plugin("compilation", function (compilation) {
59+
if (compilation.cache) {
60+
if (!compilation.cache[subCache])
6061
compilation.cache[subCache] = {};
6162
compilation.cache = compilation.cache[subCache];
6263
}
6364
});
6465
// We set loaderContext[NS] = false to indicate we already in
6566
// a child compiler so we don't spawn another child compilers from there.
66-
childCompiler.plugin("this-compilation", function(compilation) {
67-
compilation.plugin("normal-module-loader", function(loaderContext, module) {
67+
childCompiler.plugin("this-compilation", function (compilation) {
68+
compilation.plugin("normal-module-loader", function (loaderContext, module) {
6869
loaderContext[NS] = false;
6970
if (module.request === request) {
70-
module.loaders = loaders.map(function(loader) {
71+
module.loaders = loaders.map(function (loader) {
7172
return {
7273
loader: loader.path,
7374
options: loader.options
@@ -78,66 +79,66 @@ module.exports.pitch = function(request) {
7879
});
7980

8081
var source;
81-
childCompiler.plugin("after-compile", function(compilation, callback) {
82+
childCompiler.plugin("after-compile", function (compilation, callback) {
8283
source = compilation.assets[childFilename] && compilation.assets[childFilename].source();
8384

8485
// Remove all chunk assets
85-
compilation.chunks.forEach(function(chunk) {
86-
chunk.files.forEach(function(file) {
86+
compilation.chunks.forEach(function (chunk) {
87+
chunk.files.forEach(function (file) {
8788
delete compilation.assets[file];
8889
});
8990
});
9091

9192
callback();
9293
});
9394
var callback = this.async();
94-
childCompiler.runAsChild(function(err, entries, compilation) {
95-
if(err) return callback(err);
95+
childCompiler.runAsChild(function (err, entries, compilation) {
96+
if (err) return callback(err);
9697

97-
if(compilation.errors.length > 0) {
98+
if (compilation.errors.length > 0) {
9899
return callback(compilation.errors[0]);
99100
}
100-
compilation.fileDependencies.forEach(function(dep) {
101+
compilation.fileDependencies.forEach(function (dep) {
101102
this.addDependency(dep);
102103
}, this);
103-
compilation.contextDependencies.forEach(function(dep) {
104+
compilation.contextDependencies.forEach(function (dep) {
104105
this.addContextDependency(dep);
105106
}, this);
106-
if(!source) {
107+
if (!source) {
107108
return callback(new Error("Didn't get a result from child compiler"));
108109
}
109110
try {
110111
var text = this.exec(source, request);
111-
if(typeof text === "string")
112+
if (typeof text === "string")
112113
text = [[0, text]];
113-
text.forEach(function(item) {
114+
text.forEach(function (item) {
114115
var id = item[0];
115-
compilation.modules.forEach(function(module) {
116-
if(module.id === id)
116+
compilation.modules.forEach(function (module) {
117+
if (module.id === id)
117118
item[0] = module.identifier();
118119
});
119120
});
120121
this[NS](text, query);
121122

122-
if(typeof resultSource !== "undefined") {
123+
if (typeof resultSource !== "undefined") {
123124
if (text.locals) {
124125
resultSource += "\nmodule.exports = " + JSON.stringify(text.locals) + ";";
125126
}
126127
resultSource += `
127128
if (module.hot) {
128129
module.hot.accept();
129130
if (module.hot.data) {
130-
require("${require.resolve('./hotModuleReplacement.js')}")("${publicPath}", "%%extracted-file%%");
131+
require(${loaderUtils.stringifyRequest(this, path.resolve('./hotModuleReplacement.js'))})("${publicPath}", "%%extracted-file%%");
131132
}
132133
}`;
133134
}
134-
} catch(e) {
135+
} catch (e) {
135136
return callback(e);
136137
}
137-
if(resultSource)
138-
callback(null, resultSource);
139-
else
140-
callback();
138+
if (resultSource) {
139+
return callback(null, resultSource);
140+
}
141+
callback();
141142
}.bind(this));
142143
}
143144
};
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
body {
2+
background: red;
3+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
require('../router');
2+
require('../routes/contact/index');
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
require('../router');
2+
require('../routes/homepage/index');
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
webpackJsonp([0],{
2+
3+
/***/ 2:
4+
/***/ (function(module, exports, __webpack_require__) {
5+
6+
eval("__webpack_require__(7);\n\nmodules.export = function() {\n\treturn 'Route Homepage';\n};\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./routes/homepage/index.js\n// module id = 2\n// module chunks = 0 2\n\n//# sourceURL=webpack:///./routes/homepage/index.js?");
7+
8+
/***/ }),
9+
10+
/***/ 7:
11+
/***/ (function(module, exports, __webpack_require__) {
12+
13+
eval("// removed by extract-text-webpack-plugin\nif (false) {\n\tmodule.hot.accept();\n\tif (module.hot.data) {\n\t\trequire(\"../../../../../hotModuleReplacement.js\")(\"undefined\", \"homepage.css\");\n\t}\n}\n\n//////////////////\n// WEBPACK FOOTER\n// ./routes/homepage/styles.css\n// module id = 7\n// module chunks = 0 2\n\n//# sourceURL=webpack:///./routes/homepage/styles.css?");
14+
15+
/***/ })
16+
17+
});
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
webpackJsonp([1],{
2+
3+
/***/ 1:
4+
/***/ (function(module, exports, __webpack_require__) {
5+
6+
eval("__webpack_require__(6);\n\nmodules.export = function() {\n\treturn 'Route Contact';\n};\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./routes/contact/index.js\n// module id = 1\n// module chunks = 1 3\n\n//# sourceURL=webpack:///./routes/contact/index.js?");
7+
8+
/***/ }),
9+
10+
/***/ 6:
11+
/***/ (function(module, exports, __webpack_require__) {
12+
13+
eval("// removed by extract-text-webpack-plugin\nif (false) {\n\tmodule.hot.accept();\n\tif (module.hot.data) {\n\t\trequire(\"../../../../../hotModuleReplacement.js\")(\"undefined\", \"homepage.css\");\n\t}\n}\n\n//////////////////\n// WEBPACK FOOTER\n// ./routes/contact/styles.css\n// module id = 6\n// module chunks = 1 3\n\n//# sourceURL=webpack:///./routes/contact/styles.css?");
14+
15+
/***/ })
16+
17+
});
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
body {
2+
background: red;
3+
}
4+
.contact {
5+
color: black;
6+
}
7+
.homepage {
8+
color: black;
9+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
body {
2+
background: red;
3+
}
4+
.contact {
5+
color: black;
6+
}
7+
.homepage {
8+
color: black;
9+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
require('./default-styles.css');
2+
module.export = function (route) {
3+
return import(/* webpackChunkName: "route-[request]" */ './routes/' + route + 'index.js').then(function (route) {
4+
return route;
5+
});
6+
};
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
require('./styles.css');
2+
3+
modules.export = function() {
4+
return 'Route Contact';
5+
};
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.contact {
2+
color: black;
3+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
require('./styles.css');
2+
3+
modules.export = function() {
4+
return 'Route Homepage';
5+
};
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.homepage {
2+
color: black;
3+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
var ExtractTextPlugin = require("../../../");
2+
3+
module.exports = {
4+
devtool: 'eval',
5+
entry: {
6+
'homepage': "./entries/homepage.js",
7+
'contact': "./entries/contact.js"
8+
},
9+
module: {
10+
loaders: [
11+
{ test: /\.css$/, use: ExtractTextPlugin.extract({
12+
fallback: "style-loader",
13+
use: { loader: "css-loader", options: {
14+
sourceMap: false
15+
} }
16+
}) }
17+
]
18+
},
19+
plugins: [
20+
new ExtractTextPlugin({
21+
filename: '[name].css',
22+
allChunks: true
23+
})
24+
]
25+
};

test/cases/multiple-entries-all-async/expected/0.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ modules.export = function() {
1919
if (false) {
2020
module.hot.accept();
2121
if (module.hot.data) {
22-
require("/home/david/Projekte/extract-css-chunks-webpack-plugin/hotModuleReplacement.js")("undefined", "homepage.css");
22+
require("../../../../../hotModuleReplacement.js")("undefined", "homepage.css");
2323
}
2424
}
2525

test/cases/multiple-entries-all-async/expected/1.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ modules.export = function() {
1919
if (false) {
2020
module.hot.accept();
2121
if (module.hot.data) {
22-
require("/home/david/Projekte/extract-css-chunks-webpack-plugin/hotModuleReplacement.js")("undefined", "homepage.css");
22+
require("../../../../../hotModuleReplacement.js")("undefined", "homepage.css");
2323
}
2424
}
2525

0 commit comments

Comments
 (0)