Skip to content

Commit 145e9ac

Browse files
committed
Merge branch 'master' into externals
* master: fix: case insensitivity of @import (webpack-contrib#514) chore: update comment (webpack-contrib#515) docs(README): improve importLoaders section and example (webpack-contrib#512) docs(README): fix link (webpack-contrib#508) docs(README): fix typo in example (webpack-contrib#507) docs(README): fix typo in maintainers link (webpack-contrib#505) fix: imported variables are replaced in exports if followed by a comma (webpack-contrib#504) docs(README): standardize (webpack-contrib#503) test: `charset` directive (webpack-contrib#502) fix: url with a trailing space is now handled correctly (webpack-contrib#494) fix: use `btoa` instead `Buffer` (webpack-contrib#501) test: add test for escaped characters (webpack-contrib#493) test: add tests for encoded svg data uri (webpack-contrib#492) test: add tests when css contain data uri and source maps are enabled (webpack-contrib#491) fix: loader now correctly handles `url` with space(s) (webpack-contrib#495)
2 parents e2befc3 + de4356b commit 145e9ac

12 files changed

+459
-250
lines changed

README.md

+250-226
Large diffs are not rendered by default.

lib/css-base.js

+5-4
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ function cssWithMappingToString(item, useSourceMap) {
5454
return content;
5555
}
5656

57-
if (useSourceMap) {
57+
if (useSourceMap && typeof btoa === 'function') {
5858
var sourceMapping = toComment(cssMapping);
5959
var sourceURLs = cssMapping.sources.map(function (source) {
6060
return '/*# sourceURL=' + cssMapping.sourceRoot + source + ' */'
@@ -68,8 +68,9 @@ function cssWithMappingToString(item, useSourceMap) {
6868

6969
// Adapted from convert-source-map (MIT)
7070
function toComment(sourceMap) {
71-
var base64 = new Buffer(JSON.stringify(sourceMap)).toString('base64');
72-
var data = 'sourceMappingURL=data:application/json;charset=utf-8;base64,' + base64;
71+
// eslint-disable-next-line no-undef
72+
var base64 = btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap))));
73+
var data = 'sourceMappingURL=data:application/json;charset=utf-8;base64,' + base64;
7374

74-
return '/*# ' + data + ' */';
75+
return '/*# ' + data + ' */';
7576
}

lib/processCss.js

+17-8
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ var localByDefault = require("postcss-modules-local-by-default");
1313
var extractImports = require("postcss-modules-extract-imports");
1414
var modulesScope = require("postcss-modules-scope");
1515
var modulesValues = require("postcss-modules-values");
16+
var valueParser = require('postcss-value-parser');
1617

1718
var parserPlugin = postcss.plugin("css-loader-parser", function(options) {
1819
return function(css) {
@@ -23,21 +24,24 @@ var parserPlugin = postcss.plugin("css-loader-parser", function(options) {
2324

2425
function replaceImportsInString(str) {
2526
if(options.import) {
26-
var tokens = str.split(/(\S+)/);
27-
tokens = tokens.map(function (token) {
27+
var tokens = valueParser(str);
28+
tokens.walk(function (node) {
29+
if (node.type !== 'word') {
30+
return;
31+
}
32+
var token = node.value;
2833
var importIndex = imports["$" + token];
2934
if(typeof importIndex === "number") {
30-
return "___CSS_LOADER_IMPORT___" + importIndex + "___";
35+
node.value = "___CSS_LOADER_IMPORT___" + importIndex + "___";
3136
}
32-
return token;
33-
});
34-
return tokens.join("");
37+
})
38+
return tokens.toString();
3539
}
3640
return str;
3741
}
3842

3943
if(options.import) {
40-
css.walkAtRules("import", function(rule) {
44+
css.walkAtRules(/import/i, function(rule) {
4145
var values = Tokenizer.parseValues(rule.params);
4246
var url = values.nodes[0].nodes[0];
4347
if(url.type === "url") {
@@ -98,7 +102,10 @@ var parserPlugin = postcss.plugin("css-loader-parser", function(options) {
98102
break;
99103
case "url":
100104
if (options.url && !/^#/.test(item.url) && loaderUtils.isUrlRequest(item.url, options.root)) {
101-
item.stringType = "";
105+
// Don't remove quotes around url when contain space
106+
if (item.url.indexOf(" ") === -1) {
107+
item.stringType = "";
108+
}
102109
delete item.innerSpacingBefore;
103110
delete item.innerSpacingAfter;
104111
var url = item.url;
@@ -153,6 +160,8 @@ module.exports = function processCss(inputSource, inputMap, options, callback) {
153160
mode: options.mode,
154161
rewriteUrl: function(global, url) {
155162
if(parserOptions.url){
163+
url = url.trim(" ");
164+
156165
if(!loaderUtils.isUrlRequest(url, root)) {
157166
return url;
158167
}

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
"postcss-modules-local-by-default": "^1.0.1",
2424
"postcss-modules-scope": "^1.0.0",
2525
"postcss-modules-values": "^1.1.0",
26+
"postcss-value-parser": "^3.3.0",
2627
"source-list-map": "^0.1.7"
2728
},
2829
"devDependencies": {

test/cssBaseTest.js

+32-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,26 @@
1-
/*globals describe it*/
1+
/*eslint-env mocha*/
22

33
var base = require("../lib/css-base");
44

55
describe("css-base", function() {
6+
before(function() {
7+
global.btoa = function btoa(str) {
8+
var buffer = null;
9+
10+
if (str instanceof Buffer) {
11+
buffer = str;
12+
} else {
13+
buffer = new Buffer(str.toString(), 'binary');
14+
}
15+
16+
return buffer.toString('base64');
17+
}
18+
})
19+
20+
after(function () {
21+
global.btoa = null;
22+
})
23+
624
it("should toString a single module", function() {
725
var m = base();
826
m.push([1, "body { a: 1; }", ""]);
@@ -46,4 +64,17 @@ describe("css-base", function() {
4664
}]);
4765
m.toString().should.be.eql("body { a: 1; }\n/*# sourceURL=webpack://./path/to/test.scss */\n/*# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJmaWxlIjoidGVzdC5zY3NzIiwic291cmNlcyI6WyIuL3BhdGgvdG8vdGVzdC5zY3NzIl0sIm1hcHBpbmdzIjoiQUFBQTsiLCJzb3VyY2VSb290Ijoid2VicGFjazovLyJ9 */");
4866
});
67+
it("should toString without source mapping if btoa not avalibale", function() {
68+
global.btoa = null;
69+
var m = base(true);
70+
m.push([1, "body { a: 1; }", "", {
71+
file: "test.scss",
72+
sources: [
73+
'./path/to/test.scss'
74+
],
75+
mappings: "AAAA;",
76+
sourceRoot: "webpack://"
77+
}]);
78+
m.toString().should.be.eql("body { a: 1; }");
79+
});
4980
});

test/importTest.js

+6
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ describe("import", function() {
99
], "", {
1010
"./test.css": [[2, ".test{a: b}", ""]]
1111
});
12+
test("import camelcase", "@IMPORT url(test.css);\n.class { a: b c d; }", [
13+
[2, ".test{a: b}", ""],
14+
[1, ".class { a: b c d; }", ""]
15+
], "", {
16+
"./test.css": [[2, ".test{a: b}", ""]]
17+
});
1218
test("import with string", "@import \"test.css\";\n.class { a: b c d; }", [
1319
[2, ".test{a: b}", ""],
1420
[1, ".class { a: b c d; }", ""]

test/moduleTestCases/urls/expected.css

+2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
._a_ {
22
background: url({./module});
33
background: url({./module});
4+
background: url("{./module module}");
5+
background: url('{./module module}');
46
background: url({./module});
57
background: url({./module}#?iefix);
68
background: url("#hash");

test/moduleTestCases/urls/source.css

+2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
.a {
22
background: url(./module);
33
background: url("./module");
4+
background: url("./module module");
5+
background: url('./module module');
46
background: url('./module');
57
background: url("./module#?iefix");
68
background: url("#hash");

test/simpleTest.js

+25-11
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,32 @@ describe("simple", function() {
1818
test("simple2", ".class { a: b c d; }\n.two {}", [
1919
[1, ".class { a: b c d; }\n.two {}", ""]
2020
]);
21+
test("escape characters (uppercase)", ".class { content: \"\\F10C\" }", [
22+
[1, ".class { content: \"\\F10C\" }", ""]
23+
]);
24+
// Need uncomment after resolve https://github.com/css-modules/postcss-modules-local-by-default/issues/108
25+
/*test("escape characters (lowercase)", ".class { content: \"\\f10C\" }", [
26+
[1, ".class { content: \"\\f10C\" }", ""]
27+
]);*/
28+
// Need uncomment after resolve https://github.com/mathiasbynens/cssesc/issues/10
29+
/*test("escape characters (two)", ".class { content: \"\\F10C \\F10D\" }", [
30+
[1, ".class { content: \"\\F10C \\F10D\" }", ""]
31+
]);*/
2132
testMinimize("minimized simple", ".class { a: b c d; }", [
2233
[1, ".class{a:b c d}", ""]
2334
]);
24-
testError("error formatting", ".some {\n invalid css;\n}", function(err) {
25-
assert.equal(err.message, [
26-
'Unknown word (2:2)',
27-
'',
28-
' 1 | .some {',
29-
'> 2 | invalid css;',
30-
' | ^',
31-
' 3 | }',
32-
'',
33-
].join('\n'));
34-
});
35+
test("charset directive", "@charset \"UTF-8\";\n .class { a: b c d; }", [
36+
[1, "@charset \"UTF-8\";\n .class { a: b c d; }", ""]
37+
]);
38+
testError("error formatting", ".some {\n invalid css;\n}", function(err) {
39+
assert.equal(err.message, [
40+
'Unknown word (2:2)',
41+
'',
42+
' 1 | .some {',
43+
'> 2 | invalid css;',
44+
' | ^',
45+
' 3 | }',
46+
'',
47+
].join('\n'));
48+
});
3549
});

test/sourceMapTest.js

+34
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,40 @@ describe("source maps", function() {
4444
version: 3
4545
}]
4646
]);
47+
testMap("generate sourceMap (1 loader, data url)", ".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>\"); }", undefined, {
48+
loaders: [{request: "/path/css-loader"}],
49+
options: { context: "/" },
50+
resource: "/folder/test.css",
51+
request: "/path/css-loader!/folder/test.css",
52+
query: "?sourceMap"
53+
}, [
54+
[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>\"); }", "", {
55+
file: 'test.css',
56+
mappings: 'AAAA,SAAS,6WAA6W,EAAE',
57+
names: [],
58+
sourceRoot: '',
59+
sources: [ '/folder/test.css' ],
60+
sourcesContent: [ '.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>"); }' ],
61+
version: 3
62+
}]
63+
]);
64+
testMap("generate sourceMap (1 loader, encoded data url)", ".class { background-image: url(\"data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2042%2026%27%20fill%3D%27%23007aff%27%3E%3Crect%20width%3D%274%27%20height%3D%274%27%2F%3E%3Crect%20x%3D%278%27%20y%3D%271%27%20width%3D%2734%27%20height%3D%272%27%2F%3E%3Crect%20y%3D%2711%27%20width%3D%274%27%20height%3D%274%27%2F%3E%3Crect%20x%3D%278%27%20y%3D%2712%27%20width%3D%2734%27%20height%3D%272%27%2F%3E%3Crect%20y%3D%2722%27%20width%3D%274%27%20height%3D%274%27%2F%3E%3Crect%20x%3D%278%27%20y%3D%2723%27%20width%3D%2734%27%20height%3D%272%27%2F%3E%3C%2Fsvg%3E\"); }", undefined, {
65+
loaders: [{request: "/path/css-loader"}],
66+
options: { context: "/" },
67+
resource: "/folder/test.css",
68+
request: "/path/css-loader!/folder/test.css",
69+
query: "?sourceMap"
70+
}, [
71+
[1, ".class { background-image: url(\"data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2042%2026%27%20fill%3D%27%23007aff%27%3E%3Crect%20width%3D%274%27%20height%3D%274%27%2F%3E%3Crect%20x%3D%278%27%20y%3D%271%27%20width%3D%2734%27%20height%3D%272%27%2F%3E%3Crect%20y%3D%2711%27%20width%3D%274%27%20height%3D%274%27%2F%3E%3Crect%20x%3D%278%27%20y%3D%2712%27%20width%3D%2734%27%20height%3D%272%27%2F%3E%3Crect%20y%3D%2722%27%20width%3D%274%27%20height%3D%274%27%2F%3E%3Crect%20x%3D%278%27%20y%3D%2723%27%20width%3D%2734%27%20height%3D%272%27%2F%3E%3C%2Fsvg%3E\"); }", "", {
72+
file: 'test.css',
73+
mappings: 'AAAA,SAAS,mmBAAmmB,EAAE',
74+
names: [],
75+
sourceRoot: '',
76+
sources: [ '/folder/test.css' ],
77+
sourcesContent: [ '.class { background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2042%2026%27%20fill%3D%27%23007aff%27%3E%3Crect%20width%3D%274%27%20height%3D%274%27%2F%3E%3Crect%20x%3D%278%27%20y%3D%271%27%20width%3D%2734%27%20height%3D%272%27%2F%3E%3Crect%20y%3D%2711%27%20width%3D%274%27%20height%3D%274%27%2F%3E%3Crect%20x%3D%278%27%20y%3D%2712%27%20width%3D%2734%27%20height%3D%272%27%2F%3E%3Crect%20y%3D%2722%27%20width%3D%274%27%20height%3D%274%27%2F%3E%3Crect%20x%3D%278%27%20y%3D%2723%27%20width%3D%2734%27%20height%3D%272%27%2F%3E%3C%2Fsvg%3E"); }' ],
78+
version: 3
79+
}]
80+
]);
4781
testMap("generate sourceMap (2 loaders)", ".class { a: b c d; }", undefined, {
4882
loaders: [{request: "/path/css-loader"}, {request: "/path/sass-loader"}],
4983
options: { context: "/" },

0 commit comments

Comments
 (0)