Skip to content

Commit

Permalink
Update CSS Modules localIndetName (#4192)
Browse files Browse the repository at this point in the history
* Update CSS Modules localIndetName

* Add missing file to package

* Correct regex

* plz plz plz
  • Loading branch information
ro-savage authored and Timer committed Apr 13, 2018
1 parent 1d4fdc2 commit ae2cf07
Show file tree
Hide file tree
Showing 10 changed files with 109 additions and 16 deletions.
37 changes: 37 additions & 0 deletions packages/react-dev-utils/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -326,3 +326,40 @@ module.exports = {
// ...
}
```

#### `getCSSModuleLocalIdent(context: Object, localIdentName: String, localName: String, options: Object): string`

Creates a class name for CSS Modules that uses either the filename or folder name if named `index.module.css`.

For `MyFolder/MyComponent.module.css` and class `MyClass` the output will be `MyComponent.module_MyClass__[hash]`
For `MyFolder/index.module.css` and class `MyClass` the output will be `MyFolder_MyClass__[hash]`

```js
const getCSSModuleLocalIdent = require('react-dev-utils/getCSSModuleLocalIdent');

// In your webpack config:
// ...
module: {
rules: [
{
test: /\.module\.css$/,
use: [
require.resolve('style-loader'),
{
loader: require.resolve('css-loader'),
options: {
importLoaders: 1,
modules: true,
getLocalIdent: getCSSModuleLocalIdent,
},
},
{
loader: require.resolve('postcss-loader'),
options: postCSSLoaderOptions,
},
],
}
]
}
```

37 changes: 37 additions & 0 deletions packages/react-dev-utils/getCSSModuleLocalIdent.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

'use strict';

const loaderUtils = require('loader-utils');

module.exports = function getLocalIdent(
context,
localIdentName,
localName,
options
) {
// Use the filename or folder name, based on some uses the index.js / index.module.css project style
const fileNameOrFolder = context.resourcePath.endsWith('index.module.css')
? '[folder]'
: '[name]';
// Create a hash based on a the file location and class name. Will be unique across a project, and close to globally unique.
const hash = loaderUtils.getHashDigest(
context.resourcePath + localName,
'md5',
'base64',
5
);
// Use loaderUtils to find the file or folder name
const className = loaderUtils.interpolateName(
context,
fileNameOrFolder + '_' + localName + '__' + hash,
options
);
// remove the .module that appears in every classname when based on the file.
return className.replace('.module_', '_');
};
1 change: 1 addition & 0 deletions packages/react-dev-utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"eslintFormatter.js",
"FileSizeReporter.js",
"formatWebpackMessages.js",
"getCSSModuleLocalIdent.js",
"getProcessForPort.js",
"ignoredFiles.js",
"inquirer.js",
Expand Down
3 changes: 2 additions & 1 deletion packages/react-scripts/config/webpack.config.dev.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin');
const WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeModulesPlugin');
const eslintFormatter = require('react-dev-utils/eslintFormatter');
const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin');
const getCSSModuleLocalIdent = require('react-dev-utils/getCSSModuleLocalIdent');
const getClientEnvironment = require('./env');
const paths = require('./paths');

Expand Down Expand Up @@ -269,7 +270,7 @@ module.exports = {
options: {
importLoaders: 1,
modules: true,
localIdentName: '[path]__[name]___[local]',
getLocalIdent: getCSSModuleLocalIdent,
},
},
{
Expand Down
5 changes: 3 additions & 2 deletions packages/react-scripts/config/webpack.config.prod.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin');
const SWPrecacheWebpackPlugin = require('sw-precache-webpack-plugin');
const eslintFormatter = require('react-dev-utils/eslintFormatter');
const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin');
const getCSSModuleLocalIdent = require('react-dev-utils/getCSSModuleLocalIdent');
const paths = require('./paths');
const getClientEnvironment = require('./env');

Expand Down Expand Up @@ -306,7 +307,7 @@ module.exports = {
minimize: true,
sourceMap: shouldUseSourceMap,
modules: true,
localIdentName: '[path]__[name]___[local]',
getLocalIdent: getCSSModuleLocalIdent,
},
},
{
Expand Down Expand Up @@ -422,7 +423,7 @@ module.exports = {
// having to parse `index.html`.
new ManifestPlugin({
fileName: 'asset-manifest.json',
publicPath: publicPath
publicPath: publicPath,
}),
// Generate a service worker script that will precache, and keep up to date,
// the HTML & assets that are part of the Webpack build.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,11 @@ describe('Integration', () => {

expect(
doc.getElementsByTagName('style')[0].textContent.replace(/\s/g, '')
).to.match(/.+style_cssModulesInclusion__.+\{background:.+;color:.+}/);
expect(
doc.getElementsByTagName('style')[1].textContent.replace(/\s/g, '')
).to.match(
/.+__style-module___cssModulesInclusion+\{background:.+;color:.+}/
/.+assets_cssModulesIndexInclusion__.+\{background:.+;color:.+}/
);
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,13 @@

import React from 'react';
import styles from './assets/style.module.css';
import indexStyles from './assets/index.module.css';

export default () => (
<p className={styles.cssModulesInclusion}>CSS Modules are working!</p>
<div>
<p className={styles.cssModulesInclusion}>CSS Modules are working!</p>
<p className={indexStyles.cssModulesInclusion}>
CSS Modules with index are working!
</p>
</div>
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.cssModulesIndexInclusion {
background: darkblue;
color: lightblue;
}
1 change: 1 addition & 0 deletions packages/react-scripts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
"html-webpack-plugin": "2.30.1",
"identity-obj-proxy": "3.0.0",
"jest": "22.1.2",
"loader-utils": "^1.1.0",
"object-assign": "4.1.1",
"postcss-flexbugs-fixes": "3.2.0",
"postcss-loader": "2.0.10",
Expand Down
24 changes: 13 additions & 11 deletions packages/react-scripts/template/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -518,49 +518,51 @@ If you are concerned about using Webpack-specific semantics, you can put all you
<!---
## Adding a CSS Modules stylesheet
This project supports [CSS Modules](https://github.com/css-modules/css-modules) alongside regular stylesheets using the **[name].module.css** file naming convention. CSS Modules allows the scoping of CSS by automatically creating a unique classname of the format **[dir]\_\_[filename]___[classname]**.
This project supports [CSS Modules](https://github.com/css-modules/css-modules) alongside regular stylesheets using the **[name].module.css** file naming convention. CSS Modules allows the scoping of CSS by automatically creating a unique classname of the format **[filename]\_[classname]\_\_[hash]**.
An advantage of this is the ability to repeat the same classname within many CSS files without worrying about a clash.
### `Button.module.css`
```css
.button {
padding: 20px;
.error {
background-color: red;
}
```
### `another-stylesheet.css`
```css
.button {
color: green;
.error {
color: red;
}
```
### `Button.js`
```js
import React, { Component } from 'react';
import './another-stylesheet.css'; // Import regular stylesheet
import styles from './Button.module.css'; // Import css modules stylesheet as styles
import './another-stylesheet.css'; // Import regular stylesheet
class Button extends Component {
render() {
// You can use them as regular CSS styles
return <div className={styles.button} />;
// reference as a js object
return <button className={styles.error}>Error Button</button>;
}
}
```
### `exported HTML`
No clashes from other `.button` classnames
No clashes from other `.error` class names
```html
<div class="src__Button-module___button"></div>
<!-- This button has red background but not red text -->
<button class="Button_error_ax7yz"></div>
```
**This is an optional feature.** Regular html stylesheets and js imported stylesheets are fully supported. CSS Modules are only added when explictly named as a css module stylesheet using the extension `.module.css`.
--->
-->
## Post-Processing CSS
Expand Down

0 comments on commit ae2cf07

Please sign in to comment.