Skip to content

Commit d2c9c25

Browse files
committed
export placeholder
1 parent 77cc7f2 commit d2c9c25

File tree

5 files changed

+73
-71
lines changed

5 files changed

+73
-71
lines changed

README.md

+32
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,38 @@ module.exports = {
3737
};
3838
```
3939

40+
### Placeholders
41+
42+
(experimental)
43+
44+
Special selectors are automatically replaced with random identifiers, which are exported:
45+
46+
``` css
47+
.[className] { background: red; }
48+
#[someId] { background: green; }
49+
.[className] .[subClass] { color: green; }
50+
#[someId] .[subClass] { color: blue; }
51+
```
52+
53+
is transformed to
54+
55+
``` css
56+
.ze24205081ae540afa51bd4cce768e8b7 { background: red; }
57+
#zdf12049771f7fc796a63a3945da3a66d { background: green; }
58+
.ze24205081ae540afa51bd4cce768e8b7 .z9f634213cd27594c1a13d18554d47a8c { color: green; }
59+
#zdf12049771f7fc796a63a3945da3a66d .z9f634213cd27594c1a13d18554d47a8c { color: blue; }
60+
```
61+
62+
and the identifiers are exported:
63+
64+
``` js
65+
exports.placeholders = {
66+
className: "ze24205081ae540afa51bd4cce768e8b7",
67+
someId: "zdf12049771f7fc796a63a3945da3a66d",
68+
subClass: "z9f634213cd27594c1a13d18554d47a8c"
69+
}
70+
```
71+
4072
### 'Root-relative' urls
4173

4274
For urls that start with a `/`, the default behavior is to not translate them:

lib/loader.js

+16-6
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,18 @@ module.exports = function(content, map) {
4949
});
5050
var placeholders = {};
5151
stuff.placeholders.forEach(function(placeholder) {
52-
var hash = require("crypto").createHash("md5");
53-
hash.update(this.request);
54-
hash.update(placeholder.name);
55-
var ident = "z" + hash.digest("hex");
56-
placeholders[placeholder.name] = ident;
57-
replacer.replace(placeholder.start, placeholder.length, ident);
52+
if(!placeholders[placeholder.name]) {
53+
var hash = require("crypto").createHash("md5");
54+
hash.update(this.options && typeof this.options.context === "string" ?
55+
loaderUtils.stringifyRequest({ context: this.options.context }, this.request) :
56+
this.request);
57+
hash.update(placeholder.name);
58+
var ident = "z" + hash.digest("hex");
59+
placeholders[placeholder.name] = ident;
60+
} else {
61+
var ident = placeholders[placeholder.name];
62+
}
63+
replacer.replace(placeholder.start, placeholder.length, placeholder.prefix + ident);
5864
}, this);
5965

6066
var cssContent = replacer.run(content);
@@ -125,6 +131,10 @@ module.exports = function(content, map) {
125131
result.push("exports.push([module.id, " + css + ", \"\"]);");
126132
}
127133

134+
if(Object.keys(placeholders).length > 0) {
135+
result.push("exports.placeholders = " + JSON.stringify(placeholders) + ";");
136+
}
137+
128138
return "exports = module.exports = require(" + loaderUtils.stringifyRequest(this, require.resolve("./css-base.js")) + ")();\n" +
129139
result.join("\n");
130140
}

lib/parseSource.js

+5-2
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,10 @@ function urlMatch(match, textBeforeUrl, replacedText, url, index) {
1313
});
1414
}
1515

16-
function placeholderMatch(match, name, index) {
16+
function placeholderMatch(match, prefix, name, index) {
1717
this.placeholders.push({
1818
name: name,
19+
prefix: prefix,
1920
start: index,
2021
length: match.length
2122
});
@@ -47,7 +48,9 @@ var parser = new Parser({
4748
"(url\\s*\\()(\\s*([^)]*)\\s*)\\)": urlMatch,
4849

4950
// placeholder
50-
"{{([A-Za-z_0-9]+)}}": placeholderMatch
51+
"()\\{\\{([A-Za-z_0-9]+)\\}\\}": placeholderMatch,
52+
"(\\.)\\[([A-Za-z_0-9]+)\\]": placeholderMatch,
53+
"(#)\\[([A-Za-z_0-9]+)\\]": placeholderMatch,
5154
},
5255
comment: {
5356
"\\*/": "source"

lib/parser.js

-63
This file was deleted.

test/urlTest.js

+20
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,14 @@ var vm = require("vm");
66
function test(name, input, result, query, modules) {
77
it(name, function() {
88
var output = cssLoader.call({
9+
options: {
10+
context: ""
11+
},
912
loaders: [{request: "loader"}],
1013
loaderIndex: 0,
1114
context: "",
1215
resource: "test.css",
16+
request: "css-loader!test.css",
1317
query: query
1418
}, input);
1519
assetEvaluated(output, result, modules);
@@ -19,10 +23,14 @@ function test(name, input, result, query, modules) {
1923
function testMinimize(name, input, result, query, modules) {
2024
it(name, function() {
2125
var output = cssLoader.call({
26+
options: {
27+
context: ""
28+
},
2229
loaders: [{request: "loader"}],
2330
loaderIndex: 0,
2431
context: "",
2532
resource: "test.css",
33+
request: "css-loader!test.css",
2634
minimize: true,
2735
query: query
2836
}, input);
@@ -134,6 +142,18 @@ describe("url", function() {
134142
test("media query", "@media (min-width: 500px) { body { background: url(image.png); } }", [
135143
[1, "@media (min-width: 500px) { body { background: url({./image.png}); } }", ""]
136144
]);
145+
test("placeholder", ".[className] { background: red; }\n#[someId] { background: green; }\n" +
146+
".[className] .[subClass] { color: green; }\n#[someId] .[subClass] { color: blue; }", function() { var r = [
147+
[1, ".ze24205081ae540afa51bd4cce768e8b7 { background: red; }\n#zdf12049771f7fc796a63a3945da3a66d { background: green; }\n" +
148+
".ze24205081ae540afa51bd4cce768e8b7 .z9f634213cd27594c1a13d18554d47a8c { color: green; }\n#zdf12049771f7fc796a63a3945da3a66d .z9f634213cd27594c1a13d18554d47a8c { color: blue; }", ""]
149+
];
150+
r.placeholders = {
151+
className: "ze24205081ae540afa51bd4cce768e8b7",
152+
someId: "zdf12049771f7fc796a63a3945da3a66d",
153+
subClass: "z9f634213cd27594c1a13d18554d47a8c"
154+
};
155+
return r;
156+
}());
137157
testMinimize("minimized simple", ".class { a: b c d; }", [
138158
[1, ".class{a:b c d}", ""]
139159
]);

0 commit comments

Comments
 (0)