Skip to content

Commit

Permalink
refactor: drop css modules
Browse files Browse the repository at this point in the history
BREAKING CHANGE: use `postcss-modules` plugin with `postcss-loader`
  • Loading branch information
alexander-akait committed Jul 9, 2018
1 parent 43179a8 commit e9600d7
Show file tree
Hide file tree
Showing 29 changed files with 9 additions and 1,031 deletions.
157 changes: 1 addition & 156 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,8 @@ It's useful when you, for instance, need to post process the CSS as a string.
|:--:|:--:|:-----:|:----------|
|**[`url`](#url)**|`{Boolean}`|`true`| Enable/Disable `url()` handling|
|**[`import`](#import)** |`{Boolean}`|`true`| Enable/Disable @import handling|
|**[`modules`](#modules)**|`{Boolean}`|`false`|Enable/Disable CSS Modules|
|**[`localIdentName`](#localidentname)**|`{String}`|`[hash:base64]`|Configure the generated ident|
|**[`sourceMap`](#sourcemap)**|`{Boolean}`|`false`|Enable/Disable Sourcemaps|
|**[`camelCase`](#camelcase)**|`{Boolean\|String}`|`false`|Export Classnames in CamelCase|
|**[`camelCase`](#camelcase)**|`{Boolean\|String}`|`false`|Export in CamelCase|
|**[`importLoaders`](#importloaders)**|`{Number}`|`0`|Number of loaders applied before CSS loader|

### `url`
Expand All @@ -123,159 +121,6 @@ To disable `@import` resolving by `css-loader` set the option to `false`

> _⚠️ Use with caution, since this disables resolving for **all** `@import`s, including css modules `composes: xxx from 'path/to/file.css'` feature._
### [`modules`](https://github.com/css-modules/css-modules)

The query parameter `modules` enables the **CSS Modules** spec.

This enables local scoped CSS by default. (You can switch it off with `:global(...)` or `:global` for selectors and/or rules.).

#### `Scope`

By default CSS exports all classnames into a global selector scope. Styles can be locally scoped to avoid globally scoping styles.

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

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.

The loader replaces local selectors with unique identifiers. The choosen unique identifiers are exported by the module.

```css
:local(.className) { background: red; }
:local .className { color: green; }
:local(.className .subClass) { color: green; }
:local .className .subClass :global(.global-class-name) { color: blue; }
```

```css
._23_aKvs-b8bW2Vg3fwHozO { background: red; }
._23_aKvs-b8bW2Vg3fwHozO { color: green; }
._23_aKvs-b8bW2Vg3fwHozO ._13LGdX8RMStbBE9w-t0gZ1 { color: green; }
._23_aKvs-b8bW2Vg3fwHozO ._13LGdX8RMStbBE9w-t0gZ1 .global-class-name { color: blue; }
```

> ℹ️ Identifiers are exported
```js
exports.locals = {
className: '_23_aKvs-b8bW2Vg3fwHozO',
subClass: '_13LGdX8RMStbBE9w-t0gZ1'
}
```

CamelCase is recommended for local selectors. They are easier to use in the within the imported JS module.

`url()` URLs in block scoped (`:local .abc`) rules behave like requests in modules.

```
file.png => ./file.png
~module/file.png => module/file.png
```

You can use `:local(#someId)`, but this is not recommended. Use classes instead of ids.

#### `Composing`

When declaring a local classname you can compose a local class from another local classname.

```css
:local(.className) {
background: red;
color: yellow;
}

:local(.subClass) {
composes: className;
background: blue;
}
```

This doesn't result in any change to the CSS itself but exports multiple classnames.

```js
exports.locals = {
className: '_23_aKvs-b8bW2Vg3fwHozO',
subClass: '_13LGdX8RMStbBE9w-t0gZ1 _23_aKvs-b8bW2Vg3fwHozO'
}
```

``` css
._23_aKvs-b8bW2Vg3fwHozO {
background: red;
color: yellow;
}

._13LGdX8RMStbBE9w-t0gZ1 {
background: blue;
}
```

#### `Importing`

To import a local classname from another module.

```css
:local(.continueButton) {
composes: button from 'library/button.css';
background: red;
}
```

```css
:local(.nameEdit) {
composes: edit highlight from './edit.css';
background: red;
}
```

To import from multiple modules use multiple `composes:` rules.

```css
:local(.className) {
composes: edit hightlight from './edit.css';
composes: button from 'module/button.css';
composes: classFromThisModule;
background: red;
}
```

### `localIdentName`

You can configure the generated ident with the `localIdentName` query parameter. See [loader-utils's documentation](https://github.com/webpack/loader-utils#interpolatename) for more information on options.

**webpack.config.js**
```js
{
test: /\.css$/,
use: [
{
loader: 'css-loader',
options: {
modules: true,
localIdentName: '[path][name]__[local]--[hash:base64:5]'
}
}
]
}
```

You can also specify the absolute path to your custom `getLocalIdent` function to generate classname based on a different schema. This requires `webpack >= 2.2.1` (it supports functions in the `options` object).

**webpack.config.js**
```js
{
loader: 'css-loader',
options: {
modules: true,
localIdentName: '[path][name]__[local]--[hash:base64:5]',
getLocalIdent: (context, localIdentName, localName, options) => {
return 'whatever_random_class_name'
}
}
}
```

> ℹ️ 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.
### `sourceMap`

To include source maps set the `sourceMap` option.
Expand Down
23 changes: 0 additions & 23 deletions lib/getLocalIdent.js

This file was deleted.

2 changes: 0 additions & 2 deletions lib/loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ var compileExports = require("./compile-exports");
module.exports = function(content, map) {
var callback = this.async();
var query = loaderUtils.getOptions(this) || {};
var moduleMode = query.modules;
var camelCaseKeys = query.camelCase;
var sourceMap = query.sourceMap || false;

Expand All @@ -34,7 +33,6 @@ module.exports = function(content, map) {
}

processCss(content, map, {
mode: moduleMode ? "local" : "global",
from: loaderUtils.getRemainingRequest(this).split("!").pop(),
to: loaderUtils.getCurrentRequest(this).split("!").pop(),
query: query,
Expand Down
44 changes: 0 additions & 44 deletions lib/localsLoader.js

This file was deleted.

41 changes: 2 additions & 39 deletions lib/processCss.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,8 @@ var formatCodeFrame = require("babel-code-frame");
var Tokenizer = require("css-selector-tokenizer");
var postcss = require("postcss");
var loaderUtils = require("loader-utils");
var getLocalIdent = require("./getLocalIdent");

var icssUtils = require('icss-utils');
var localByDefault = require("postcss-modules-local-by-default");
var extractImports = require("postcss-modules-extract-imports");
var modulesScope = require("postcss-modules-scope");
var modulesValues = require("postcss-modules-values");
var valueParser = require('postcss-value-parser');

var parserPlugin = postcss.plugin("css-loader-parser", function(options) {
Expand Down Expand Up @@ -104,7 +99,8 @@ var parserPlugin = postcss.plugin("css-loader-parser", function(options) {
item.stringType = "";
delete item.innerSpacingBefore;
delete item.innerSpacingAfter;
var url = item.url;
// For backward-compat after dropping css modules
var url = loaderUtils.urlToRequest(item.url.trim());
item.url = "___CSS_LOADER_URL___" + urlItems.length + "___";
urlItems.push({
url: url
Expand Down Expand Up @@ -135,47 +131,14 @@ var parserPlugin = postcss.plugin("css-loader-parser", function(options) {

module.exports = function processCss(inputSource, inputMap, options, callback) {
var query = options.query;
var context = query.context;
var localIdentName = query.localIdentName || "[hash:base64]";
var localIdentRegExp = query.localIdentRegExp;

var customGetLocalIdent = query.getLocalIdent || getLocalIdent;

var parserOptions = {
mode: options.mode,
url: query.url !== false,
import: query.import !== false,
resolve: options.resolve
};

var pipeline = postcss([
modulesValues,
localByDefault({
mode: options.mode,
rewriteUrl: function(global, url) {
if(parserOptions.url){
url = url.trim();

if(!url.replace(/\s/g, '').length || !loaderUtils.isUrlRequest(url)) {
return url;
}
if(global) {
return loaderUtils.urlToRequest(url);
}
}
return url;
}
}),
extractImports(),
modulesScope({
generateScopedName: function generateScopedName (exportName) {
return customGetLocalIdent(options.loaderContext, localIdentName, exportName, {
regExp: localIdentRegExp,
hashPrefix: query.hashPrefix || "",
context: context
});
}
}),
parserPlugin(parserOptions)
]);

Expand Down
5 changes: 0 additions & 5 deletions locals.js

This file was deleted.

11 changes: 2 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,15 @@
},
"files": [
"lib",
"index.js",
"locals.js"
"index.js"
],
"dependencies": {
"babel-code-frame": "^6.26.0",
"css-selector-tokenizer": "^0.7.0",
"icss-utils": "^2.1.0",
"loader-utils": "^1.0.2",
"lodash.camelcase": "^4.3.0",
"postcss": "^6.0.23",
"postcss-modules-extract-imports": "^1.2.0",
"postcss-modules-local-by-default": "^1.2.0",
"postcss-modules-scope": "^1.1.0",
"postcss-modules-values": "^1.3.0",
"postcss-value-parser": "^3.3.0",
"source-list-map": "^2.0.0"
"postcss-value-parser": "^3.3.0"
},
"devDependencies": {
"codecov": "^1.0.1",
Expand Down
Loading

0 comments on commit e9600d7

Please sign in to comment.