Skip to content

Commit e928350

Browse files
committed
export an array of items with ids
fixes #17
1 parent ea69dc7 commit e928350

File tree

6 files changed

+179
-81
lines changed

6 files changed

+179
-81
lines changed

README.md

+10
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,14 @@ The result is:
5858

5959
* `url(/image.png)` => `require("./image.png")`
6060

61+
### SourceMaps
62+
63+
To include SourceMaps set the `sourceMap` query param.
64+
65+
`require("css-loader?sourceMap!./file.css")`
66+
67+
I. e. the extract-text-webpack-plugin can handle them.
68+
6169
### Minification
6270

6371
By default the css-loader minimizes the css if specified by the module system.
@@ -70,6 +78,8 @@ You can also disable or enforce minification with the `minimize` query parameter
7078

7179
`require("css-loader?-minimize!./file.css")` (disabled)
7280

81+
You cannot use minimize with SourceMaps.
82+
7383
## License
7484

7585
MIT (http://www.opensource.org/licenses/mit-license.php)

cssToString.js

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
module.exports = function() {
2+
var list = [];
3+
list.toString = function toString() {
4+
var result = [];
5+
for(var i = 0; i < this.length; i++) {
6+
var item = this[i];
7+
if(item[2]) {
8+
result.push("@media " + item[2] + "{" + item[1] + "}");
9+
} else {
10+
result.push(item[1]);
11+
}
12+
}
13+
return result.join("");
14+
};
15+
return list;
16+
}

index.js

+36-20
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@
33
Author Tobias Koppers @sokra
44
*/
55
var csso = require("csso");
6-
var SourceNode = require("source-map").SourceNode;
6+
var SourceMapGenerator = require("source-map").SourceMapGenerator;
77
var loaderUtils = require("loader-utils");
8+
89
module.exports = function(content) {
910
this.cacheable && this.cacheable();
1011
var result = [];
12+
var queryString = this.query || "";
1113
var query = loaderUtils.parseQuery(this.query);
1214
var root = query.root;
1315
var forceMinimize = query.minimize;
@@ -24,17 +26,14 @@ module.exports = function(content) {
2426

2527
imports.forEach(function(imp) {
2628
if(!loaderUtils.isUrlRequest(imp.url)) {
27-
result.push(JSON.stringify("@import url(" + imp.url + ")" + imp.media.join("") + ";"));
29+
result.push("exports.push([module.id, " + JSON.stringify("@import url(" + imp.url + ");") + ", " + JSON.stringify(imp.media.join("")) + "]);");
2830
} else {
29-
if(imp.media.length > 0) {
30-
result.push(JSON.stringify("@media " + imp.media.join("") + "{"));
31-
}
32-
result.push("require(" + JSON.stringify("!" + __filename + "!" + loaderUtils.urlToRequest(imp.url)) + ")");
33-
if(imp.media.length > 0) {
34-
result.push(JSON.stringify("}"));
35-
}
31+
var importUrl = "-!" +
32+
this.loaders.slice(this.loaderIndex).map(function(x) { return x.request; }).join("!") + "!" +
33+
loaderUtils.urlToRequest(imp.url);
34+
result.push("require(" + JSON.stringify(require.resolve("./mergeImport")) + ")(exports, require(" + JSON.stringify(importUrl) + "), " + JSON.stringify(imp.media.join("")) + ");");
3635
}
37-
});
36+
}, this);
3837
}
3938

4039
var css = JSON.stringify(tree ? csso.translate(tree) : "");
@@ -55,16 +54,33 @@ module.exports = function(content) {
5554
}
5655
return "\"+require(" + JSON.stringify(loaderUtils.urlToRequest(url, root)) + ")+\"";
5756
});
58-
result.push(css);
59-
var cssRequest = loaderUtils.getRemainingRequest(this);
60-
var node = new SourceNode(1, 0,
61-
cssRequest,
62-
"module.exports =\n\t" + result.join(" +\n\t") + ";");
63-
var stringWithMap = node.toStringWithSourceMap({
64-
file: loaderUtils.getCurrentRequest(this)
65-
});
66-
stringWithMap.map.setSourceContent(cssRequest, content);
67-
this.callback(null, stringWithMap.code, stringWithMap.map.toJSON());
57+
if(query.sourceMap && !minimize) {
58+
var cssRequest = loaderUtils.getRemainingRequest(this);
59+
var request = loaderUtils.getCurrentRequest(this);
60+
var sourceMap = new SourceMapGenerator({
61+
file: request
62+
});
63+
var lines = content.split("\n").length;
64+
for(var i = 0; i < lines; i++) {
65+
sourceMap.addMapping({
66+
generated: {
67+
line: i+1,
68+
column: 0
69+
},
70+
source: cssRequest,
71+
original: {
72+
line: i+1,
73+
column: 0
74+
},
75+
});
76+
}
77+
sourceMap.setSourceContent(cssRequest, content);
78+
result.push("exports.push([module.id, " + css + ", \"\", " + JSON.stringify(sourceMap.toJSON()) + "]);");
79+
} else {
80+
result.push("exports.push([module.id, " + css + ", \"\"]);");
81+
}
82+
return "exports = module.exports = require(" + JSON.stringify(require.resolve("./cssToString")) + ")();\n" +
83+
result.join("\n");
6884
}
6985

7086
function extractImports(tree) {

mergeImport.js

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
module.exports = function(list, importedList, media) {
2+
for(var i = 0; i < importedList.length; i++) {
3+
var item = importedList[i];
4+
if(media && !item[2])
5+
item[2] = media;
6+
else if(media) {
7+
item[2] = "(" + item[2] + ") and (" + media + ")";
8+
}
9+
list.push(item);
10+
}
11+
};

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"description": "css loader module for webpack",
66
"dependencies": {
77
"csso": "1.3.x",
8-
"source-map": "0.1.x",
8+
"source-map": "~0.1.38",
99
"loader-utils": "~0.2.2"
1010
},
1111
"devDependencies": {

test/urlTest.js

+105-60
Original file line numberDiff line numberDiff line change
@@ -1,86 +1,131 @@
11
var should = require("should");
22
var path = require("path");
33
var cssLoader = require("../index.js");
4+
var vm = require("vm");
45

5-
function test(name, input, result, query) {
6+
function test(name, input, result, query, modules) {
67
it(name, function() {
7-
var output;
8-
cssLoader.call({
8+
var output = cssLoader.call({
99
loaders: [{request: "loader"}],
1010
loaderIndex: 0,
1111
resource: "test.css",
12-
query: query,
13-
callback: function(err, result) {
14-
output = result;
15-
}
12+
query: query
1613
}, input);
17-
output.should.be.eql("module.exports =\n\t" + result.join(" +\n\t") + ";");
14+
assetEvaluated(output, result, modules);
1815
});
1916
}
2017

21-
function testMinimize(name, input, result) {
18+
function testMinimize(name, input, result, query, modules) {
2219
it(name, function() {
23-
var output;
24-
cssLoader.call({
20+
var output = cssLoader.call({
2521
loaders: [{request: "loader"}],
2622
loaderIndex: 0,
2723
resource: "test.css",
2824
minimize: true,
29-
callback: function(err, result) {
30-
output = result;
31-
}
25+
query: query
3226
}, input);
33-
output.should.be.eql("module.exports =\n\t" + result.join(" +\n\t") + ";");
27+
assetEvaluated(output, result, modules);
3428
});
3529
}
3630

31+
function assetEvaluated(output, result, modules) {
32+
try {
33+
var fn = vm.runInThisContext("(function(module, exports, require) {" + output + "})", "testcase.js");
34+
var m = { exports: {}, id: 1 };
35+
fn(m, m.exports, function(module) {
36+
if(module === require.resolve("../mergeImport"))
37+
return require("../mergeImport");
38+
if(module === require.resolve("../cssToString"))
39+
return require("../cssToString");
40+
if(module.indexOf("-!loader!") === 0)
41+
module = module.substr(9);
42+
if(modules && modules[module])
43+
return modules[module];
44+
return "{" + module + "}";
45+
});
46+
} catch(e) {
47+
console.error(output);
48+
throw e;
49+
}
50+
delete m.exports.toString;
51+
m.exports.should.be.eql(result);
52+
53+
}
54+
3755
describe("url", function() {
38-
test("empty", "",
39-
["\"\""]);
40-
testMinimize("empty minimized", "",
41-
["\"\""]);
42-
test("simple", ".class { a: b c d; }",
43-
["\".class { a: b c d; }\""]);
44-
test("simple2", ".class { a: b c d; }\n.two {}",
45-
["\".class { a: b c d; }\\n.two {}\""]);
46-
test("import", "@import url(test.css);\n.class { a: b c d; }",
47-
["require("+JSON.stringify("!"+path.join(__dirname, "..", "index.js")+"!./test.css")+")",
48-
"\"\\n.class { a: b c d; }\""]);
49-
test("import 2", "@import url('test.css');",
50-
["require("+JSON.stringify("!"+path.join(__dirname, "..", "index.js")+"!./test.css")+")",
51-
"\"\""]);
52-
test("import with media", "@import url(~test/css) screen and print;\n.class { a: b c d; }",
53-
["\"@media screen and print{\"",
54-
"require("+JSON.stringify("!"+path.join(__dirname, "..", "index.js")+"!test/css")+")",
55-
"\"}\"",
56-
"\"\\n.class { a: b c d; }\""]);
57-
test("import external", "@import url(http://example.com/style.css);\n@import url(\"//example.com/style.css\");",
58-
["\"@import url(http://example.com/style.css);\"",
59-
"\"@import url(//example.com/style.css);\"",
60-
"\"\\n\""]);
61-
test("background img", ".class { background: green url( \"img.png\" ) xyz }",
62-
["\".class { background: green url( \"+require(\"./img.png\")+\" ) xyz }\""]);
63-
test("background img 2", ".class { background: green url(~img/png ) url(aaa) xyz }",
64-
["\".class { background: green url(\"+require(\"img/png\")+\" ) url(\"+require(\"./aaa\")+\") xyz }\""]);
65-
test("background img 3", ".class { background: green url( 'img.png' ) xyz }",
66-
["\".class { background: green url( \"+require(\"./img.png\")+\" ) xyz }\""]);
67-
test("background img absolute", ".class { background: green url(/img.png) xyz }",
68-
["\".class { background: green url(/img.png) xyz }\""]);
69-
test("background img absolute with root", ".class { background: green url(/img.png) xyz }",
70-
["\".class { background: green url(\"+require(\"./img.png\")+\") xyz }\""], "?root=.");
56+
test("empty", "", [
57+
[1, "", ""]
58+
]);
59+
testMinimize("empty minimized", "", [
60+
[1, "", ""]
61+
]);
62+
test("simple", ".class { a: b c d; }", [
63+
[1, ".class { a: b c d; }", ""]
64+
]);
65+
test("simple2", ".class { a: b c d; }\n.two {}", [
66+
[1, ".class { a: b c d; }\n.two {}", ""]
67+
]);
68+
test("import", "@import url(test.css);\n.class { a: b c d; }", [
69+
[2, ".test{a: b}", ""],
70+
[1, "\n.class { a: b c d; }", ""]
71+
], "", {
72+
"./test.css": [[2, ".test{a: b}", ""]]
73+
});
74+
test("import 2", "@import url('test.css');\n.class { a: b c d; }", [
75+
[2, ".test{a: b}", "screen"],
76+
[1, "\n.class { a: b c d; }", ""]
77+
], "", {
78+
"./test.css": [[2, ".test{a: b}", "screen"]]
79+
});
80+
test("import with media", "@import url('~test/css') screen and print;\n.class { a: b c d; }", [
81+
[3, ".test{a: b}", "((min-width: 100px)) and (screen and print)"],
82+
[2, ".test{c: d}", "screen and print"],
83+
[1, "\n.class { a: b c d; }", ""]
84+
], "", {
85+
"test/css": [
86+
[3, ".test{a: b}", "(min-width: 100px)"],
87+
[2, ".test{c: d}", ""]
88+
]
89+
});
90+
test("import external", "@import url(http://example.com/style.css);\n@import url(\"//example.com/style.css\");", [
91+
[1, "@import url(http://example.com/style.css);", ""],
92+
[1, "@import url(//example.com/style.css);", ""],
93+
[1, "\n", ""]
94+
]);
95+
test("background img", ".class { background: green url( \"img.png\" ) xyz }", [
96+
[1, ".class { background: green url( {./img.png} ) xyz }", ""]
97+
]);
98+
test("background img 2", ".class { background: green url(~img/png) url(aaa) xyz }", [
99+
[1, ".class { background: green url({img/png}) url({./aaa}) xyz }", ""]
100+
]);
101+
test("background img 3", ".class { background: green url( 'img.png' ) xyz }", [
102+
[1, ".class { background: green url( {./img.png} ) xyz }", ""]
103+
]);
104+
test("background img absolute", ".class { background: green url(/img.png) xyz }", [
105+
[1, ".class { background: green url(/img.png) xyz }", ""]
106+
]);
107+
test("background img absolute with root", ".class { background: green url(/img.png) xyz }", [
108+
[1, ".class { background: green url({./img.png}) xyz }", ""]
109+
], "?root=.");
71110
test("background img external",
72-
".class { background: green url(data:image/png;base64,AAA) url(http://example.com/image.jpg) url(//example.com/image.png) xyz }",
73-
["\".class { background: green url(data:image/png;base64,AAA) url(http://example.com/image.jpg) url(//example.com/image.png) xyz }\""]);
111+
".class { background: green url(data:image/png;base64,AAA) url(http://example.com/image.jpg) url(//example.com/image.png) xyz }", [
112+
[1, ".class { background: green url(data:image/png;base64,AAA) url(http://example.com/image.jpg) url(//example.com/image.png) xyz }", ""]
113+
]);
74114
test("background img external data",
75-
".class { background-image: url(\"data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 42 26' fill='%23007aff'><rect width='4' height='4'/><rect x='8' y='1' width='34' height='2'/><rect y='11' width='4' height='4'/><rect x='8' y='12' width='34' height='2'/><rect y='22' width='4' height='4'/><rect x='8' y='23' width='34' height='2'/></svg>\") }",
76-
["\".class { background-image: url(\\\"data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 42 26' fill='%23007aff'><rect width='4' height='4'/><rect x='8' y='1' width='34' height='2'/><rect y='11' width='4' height='4'/><rect x='8' y='12' width='34' height='2'/><rect y='22' width='4' height='4'/><rect x='8' y='23' width='34' height='2'/></svg>\\\") }\""]);
115+
".class { background-image: url(\"data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 42 26' fill='%23007aff'><rect width='4' height='4'/><rect x='8' y='1' width='34' height='2'/><rect y='11' width='4' height='4'/><rect x='8' y='12' width='34' height='2'/><rect y='22' width='4' height='4'/><rect x='8' y='23' width='34' height='2'/></svg>\") }", [
116+
[1, ".class { background-image: url(\"data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 42 26' fill='%23007aff'><rect width='4' height='4'/><rect x='8' y='1' width='34' height='2'/><rect y='11' width='4' height='4'/><rect x='8' y='12' width='34' height='2'/><rect y='22' width='4' height='4'/><rect x='8' y='23' width='34' height='2'/></svg>\") }", ""]
117+
]);
77118
test("filter hash",
78-
".highlight { filter: url(#highlight); }",
79-
["\".highlight { filter: url(#highlight); }\""]);
80-
test("font face", "@font-face { src: url(regular.woff) format('woff'), url(~truetype/regular.ttf) format('truetype') }",
81-
["\"@font-face { src: url(\"+require(\"./regular.woff\")+\") format('woff'), url(\"+require(\"truetype/regular.ttf\")+\") format('truetype') }\""]);
82-
test("media query", "@media (min-width: 500px) { body { background: url(image.png); } }",
83-
["\"@media (min-width: 500px) { body { background: url(\"+require(\"./image.png\")+\"); } }\""]);
84-
testMinimize("minimized simple", ".class { a: b c d; }",
85-
["\".class{a:b c d}\""]);
119+
".highlight { filter: url(#highlight); }", [
120+
[1, ".highlight { filter: url(#highlight); }", ""]
121+
]);
122+
test("font face", "@font-face { src: url(regular.woff) format('woff'), url(~truetype/regular.ttf) format('truetype') }", [
123+
[1, "@font-face { src: url({./regular.woff}) format('woff'), url({truetype/regular.ttf}) format('truetype') }", ""]
124+
]);
125+
test("media query", "@media (min-width: 500px) { body { background: url(image.png); } }", [
126+
[1, "@media (min-width: 500px) { body { background: url({./image.png}); } }", ""]
127+
]);
128+
testMinimize("minimized simple", ".class { a: b c d; }", [
129+
[1, ".class{a:b c d}", ""]
130+
]);
86131
});

0 commit comments

Comments
 (0)