Skip to content

Commit 42db9bc

Browse files
committed
module mode [breaking change]
new extends syntax added :global and :local added module mode removed old deprecated syntax breaking change if you are using local scope (it was experimental)
1 parent c258432 commit 42db9bc

8 files changed

+326
-126
lines changed

README.md

+41-12
Original file line numberDiff line numberDiff line change
@@ -64,44 +64,60 @@ By default CSS exports all class names into a global selector scope. This is a f
6464

6565
The syntax `:local(.className)` can be used to declare `className` in the local scope. The local identifiers are exported by the module.
6666

67-
It does it by replacing the selectors by unique identifiers. The choosen unique identifiers are exported by the module.
67+
With `:local` (without brackets) local mode can be switched on for this selector. `:global(.className)` can be used to declare an explicit global selector. With `:global` (without brackets) global mode can be switched on for this selector.
68+
69+
The loader replaces local selectors with unique identifiers. The choosen unique identifiers are exported by the module.
6870

6971
Example:
7072

7173
``` css
7274
:local(.className) { background: red; }
73-
:local(#someId) { background: green; }
75+
:local .className { color: green; }
7476
:local(.className .subClass) { color: green; }
75-
:local(#someId .subClass) { color: blue; }
77+
:local .className .subClass :global(.global-class-name) { color: blue; }
7678
```
7779

7880
is transformed to
7981

8082
``` css
8183
._23_aKvs-b8bW2Vg3fwHozO { background: red; }
82-
#_1j3LM6lKkKzRIt19ImYVnD { background: green; }
84+
._23_aKvs-b8bW2Vg3fwHozO { color: green; }
8385
._23_aKvs-b8bW2Vg3fwHozO ._13LGdX8RMStbBE9w-t0gZ1 { color: green; }
84-
#_1j3LM6lKkKzRIt19ImYVnD ._13LGdX8RMStbBE9w-t0gZ1 { color: blue; }
86+
._23_aKvs-b8bW2Vg3fwHozO ._13LGdX8RMStbBE9w-t0gZ1 .global-class-name { color: blue; }
8587
```
8688

8789
and the identifiers are exported:
8890

8991
``` js
9092
exports.locals = {
9193
className: "_23_aKvs-b8bW2Vg3fwHozO",
92-
someId: "_1j3LM6lKkKzRIt19ImYVnD",
9394
subClass: "_13LGdX8RMStbBE9w-t0gZ1"
9495
}
9596
```
9697

98+
Camelcasing is recommended for local selectors. They are easier to use in the importing javascript module.
99+
100+
You can use `:local(#someId)`, but this is not recommended. Use classes instead of ids.
101+
97102
You can configure the generated ident with the `localIdentName` query parameter (default `[hash:base64]`). Example: `css-loader?localIdentName=[path][name]---[local]---[hash:base64:5]` for easier debugging.
98103

99104
Note: For prerendering with extract-text-webpack-plugin you should use `css-loader/locals` instead of `style-loader!css-loader` in the prerendering bundle. It doesn't embed CSS but only exports the identifier mappings.
100105

101-
### Inheriting
106+
### Module mode
102107

103108
(experimental)
104109

110+
The query parameter `module` enables **CSS module** mode. (`css-loader?module`)
111+
112+
* Local scoped by default.
113+
* `url(...)` URLs behave like requests in modules:
114+
* `./file.png` instead of `file.png`
115+
* `module/file.png` instead of `~module/file.png`
116+
117+
Thanks to @markdalgleish for prior work on this topic.
118+
119+
### Inheriting
120+
105121
When declaring a local class name you can inherit from another local class name.
106122

107123
``` css
@@ -110,7 +126,8 @@ When declaring a local class name you can inherit from another local class name.
110126
color: yellow;
111127
}
112128

113-
:local(.subClass):extends(.className) {
129+
:local(.subClass) {
130+
extends: className;
114131
background: blue;
115132
}
116133
```
@@ -139,18 +156,30 @@ and CSS is transformed to:
139156

140157
### Importing local class names
141158

142-
(experimental)
143-
144159
To import a local class name from another module:
145160

146161
``` css
147-
:local(.continueButton):extends(.button from "library/button.css") {
162+
:local(.continueButton) {
163+
extends: button from "library/button.css";
148164
background: red;
149165
}
150166
```
151167

152168
``` css
153-
:local(.nameEdit):extends(.edit.highlight from "./edit.css") {
169+
:local(.nameEdit) {
170+
extends: edit highlight from "./edit.css";
171+
background: red;
172+
}
173+
```
174+
175+
To import from multiple modules use multiple `extends:` rules. You can also use `url(...)` to specify the module (it behave a bit different).
176+
177+
``` css
178+
:local(.className) {
179+
extends: edit hightlight from "./edit.css";
180+
extends: button from url("button.css");
181+
/* equal to 'extends: button from "./button.css";' */
182+
extends: classFromThisModule;
154183
background: red;
155184
}
156185
```

lib/generateLocals.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ module.exports = function(locals, localExtends, importedUrls, importUrlPrefix, r
1010
var line = " " + JSON.stringify(key) + ": ";
1111
function addExtend(extend) {
1212
if(extend.from) {
13-
var importUrl = importUrlPrefix + extend.from;
13+
var importUrl = importUrlPrefix +
14+
(extend.fromType === "url" ? loaderUtils.urlToRequest(extend.from) : extend.from);
1415
if(importedUrls && result && importedUrls.indexOf(importUrl) < 0) {
1516
result.push("exports.i(require(" + loaderUtils.stringifyRequest(this, importUrl) + "), \"\");");
1617
importedUrls.push(importUrl);

lib/loader.js

+12-6
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ module.exports = function(content, map) {
1616
var forceMinimize = query.minimize;
1717
var importLoaders = parseInt(query.importLoaders, 10) || 0;
1818
var minimize = typeof forceMinimize !== "undefined" ? !!forceMinimize : (this && this.minimize);
19+
var moduleMode = query.module;
1920

2021
if(typeof map !== "string") {
2122
map = JSON.stringify(map);
@@ -45,7 +46,8 @@ module.exports = function(content, map) {
4546
JSON.stringify("@import url(" + imp.url + ");") + ", " +
4647
JSON.stringify(imp.mediaQuery) + "]);");
4748
} else {
48-
var importUrl = importUrlPrefix + loaderUtils.urlToRequest(imp.url);
49+
var importUrl = importUrlPrefix +
50+
(moduleMode ? imp.url : loaderUtils.urlToRequest(imp.url));
4951
result.push("exports.i(require(" + loaderUtils.stringifyRequest(this, importUrl) + "), " + JSON.stringify(imp.mediaQuery) + ");");
5052
if(!imp.mediaQuery)
5153
importedUrls.push(importUrl);
@@ -62,7 +64,7 @@ module.exports = function(content, map) {
6264
// replace :local()
6365
var locals = {};
6466
var localExtends = {};
65-
require("./processLocals").call(this, stuff.locals, query, replacer, locals, localExtends);
67+
require("./processLocals").call(this, stuff.selectors, query, replacer, locals, localExtends);
6668

6769
// remove stuff
6870
stuff.remove.forEach(function(rem) {
@@ -112,19 +114,23 @@ module.exports = function(content, map) {
112114
if(!stuff.urls[idx]) return str;
113115
var urlItem = stuff.urls[idx];
114116
var url = urlItem.url;
115-
if(!loaderUtils.isUrlRequest(url, root))
117+
if(!moduleMode && !loaderUtils.isUrlRequest(url, root))
116118
return toEmbStr(urlItem.raw);
117119
idx = url.indexOf("?#");
118120
if(idx < 0) idx = url.indexOf("#");
121+
var urlRequest;
119122
if(idx > 0) {
120123
// in cases like url('webfont.eot?#iefix')
121-
var urlRequest = url.substr(0, idx);
122-
return "\"+require(" + loaderUtils.stringifyRequest(this, loaderUtils.urlToRequest(urlRequest, root)) + ")+\"" + url.substr(idx);
124+
urlRequest = url.substr(0, idx);
125+
if(!moduleMode) urlRequest = loaderUtils.urlToRequest(urlRequest, root);
126+
return "\"+require(" + loaderUtils.stringifyRequest(this, urlRequest) + ")+\"" + url.substr(idx);
123127
} else if(idx === 0) {
124128
// only hash
125129
return toEmbStr(urlItem.raw);
126130
}
127-
return "\"+require(" + loaderUtils.stringifyRequest(this, loaderUtils.urlToRequest(url, root)) + ")+\"";
131+
urlRequest = url;
132+
if(!moduleMode) urlRequest = loaderUtils.urlToRequest(url, root);
133+
return "\"+require(" + loaderUtils.stringifyRequest(this, urlRequest) + ")+\"";
128134
}.bind(this));
129135

130136
// add a SourceMap

lib/localsLoader.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ module.exports = function(content) {
2121

2222
var locals = {};
2323
var localExtends = {};
24-
require("./processLocals").call(this, stuff.locals, query, null, locals, localExtends);
24+
require("./processLocals").call(this, stuff.selectors, query, null, locals, localExtends);
2525

2626

2727
// generate the locals

0 commit comments

Comments
 (0)