Description
Created based on comment #689 (comment)
Do you want to request a feature or report a bug?
Bug
What is the current behavior?
Given CSS file with 10000 or more classes with URLs, in our case generated from sprites.
...
.classN { ... background-image: url(./path/to/sprite.png); ... }
...
The css-loader creates such a JS file, which on compile throws RangeError: Maximum call stack size exceeded
.
...
exports.push([
module.id,
".class0 { background-image: url(" +
escape(require("./path/to/sprite.png")) +
"); }.class1 { background-image: url(" +
escape(require("./path/to/sprite.png")) +
...
])
What is the expected behavior?
The expected behaviour is to generate a JS file, which can be compiled and executed.
Please mention other relevant information such as your webpack version, Node.js version and Operating System.
Reproducible on 1.0.0, Node 6.11.3 & Node 8.9.4.
Technical details
The issue is that URLs are replaced by requires and cssAsString
in loader.js
is built by string concatenation "..." + "..." + ... + "..."
which has upper limit in each version of v8, given by it's default stack size.
Experimentally measured:
- node 6.11.3 has ~6250 strings,
- node 8.9.4 has ~3285 strings.
The fix is straightforward, group the string concatenations by fixed amount so it can be compiled using default stack size. ("..." + ... + "...") + ("..." + ... + "...")
Smallest possible test-case for css-loader
/*globals describe */
var helpers = require("./helpers");
var test = helpers.test;
describe("string concat", function() {
this.timeout(20000);
var actualCSS, expectedCSS, i;
actualCSS = '';
expectedCSS = '';
for (i = 0; i < 10000; i++) {
actualCSS += ".class" + i + " { background-image: url(./path/to/file.png); }";
expectedCSS += ".class" + i + " { background-image: url({./path/to/file.png}); }";
}
test("should handle concat of 20001 strings", actualCSS, [[1, expectedCSS, ""]]);
});
Repo with reproducible test-case https://github.com/Gobie/css-loader/tree/issue-771