-
-
Notifications
You must be signed in to change notification settings - Fork 26.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for CSS Modules with explicit filename - [name].module.css #2285
Changes from all commits
8af43b8
3cb3304
82d70ee
4e9c9da
8d52f0d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -55,6 +55,20 @@ const extractTextPluginOptions = shouldUseRelativeAssetPaths | |
{ publicPath: Array(cssFilename.split('/').length).join('../') } | ||
: {}; | ||
|
||
// Options for PostCSS as we reference these options twice | ||
// Adds vendor prefixing to support IE9 and above | ||
const postCSSLoaderOptions = { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A config file might be better since we are copy pasting this on the production and on the dev version. IMO it would be even better to merge both webpack config files and simply use variables to determine the correct environment. It would also help a lot when you're ejecting it and add/change/remove things but this is just IMHO. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It was copy and pasted previously as well. For now I think leaving it rather than making another config file is best and it simplifies the code base (at cost of repetition). The issue should be addressed in #2108 when the target browsers is pulled out into the package.json config. Thanks for the feedback. Happy to discuss further. |
||
// Necessary for external CSS imports to work | ||
// https://github.com/facebookincubator/create-react-app/issues/2677 | ||
ident: 'postcss', | ||
plugins: () => [ | ||
require('postcss-flexbugs-fixes'), | ||
autoprefixer({ | ||
flexbox: 'no-2009', | ||
}), | ||
], | ||
}; | ||
|
||
// This is the production configuration. | ||
// It compiles slowly and is focused on producing a fast and minimal bundle. | ||
// The development configuration is different and lives in a separate file. | ||
|
@@ -221,8 +235,10 @@ module.exports = { | |
// tags. If you use code splitting, however, any async bundles will still | ||
// use the "style" loader inside the async code so CSS from them won't be | ||
// in the main CSS file. | ||
// By default we support CSS Modules with the extension .module.css | ||
{ | ||
test: /\.css$/, | ||
exclude: /\.module\.css$/, | ||
loader: ExtractTextPlugin.extract( | ||
Object.assign( | ||
{ | ||
|
@@ -243,18 +259,43 @@ module.exports = { | |
}, | ||
{ | ||
loader: require.resolve('postcss-loader'), | ||
options: postCSSLoaderOptions, | ||
}, | ||
], | ||
}, | ||
extractTextPluginOptions | ||
) | ||
), | ||
// Note: this won't work without `new ExtractTextPlugin()` in `plugins`. | ||
}, | ||
// Adds support for CSS Modules (https://github.com/css-modules/css-modules) | ||
// using the extension .module.css | ||
{ | ||
test: /\.module\.css$/, | ||
loader: ExtractTextPlugin.extract( | ||
Object.assign( | ||
{ | ||
fallback: { | ||
loader: require.resolve('style-loader'), | ||
options: { | ||
hmr: false, | ||
}, | ||
}, | ||
use: [ | ||
{ | ||
loader: require.resolve('css-loader'), | ||
options: { | ||
// Necessary for external CSS imports to work | ||
// https://github.com/facebookincubator/create-react-app/issues/2677 | ||
ident: 'postcss', | ||
plugins: () => [ | ||
require('postcss-flexbugs-fixes'), | ||
autoprefixer({ | ||
flexbox: 'no-2009', | ||
}), | ||
], | ||
importLoaders: 1, | ||
minimize: true, | ||
sourceMap: shouldUseSourceMap, | ||
modules: true, | ||
localIdentName: '[path]__[name]___[local]', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should the production build expose the app architecture? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Personally I always go for In regards to @klzns comment, I'd also appreciate not exposing the file path – at least not when There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why does it need to be deterministic and targetable? kind of kills the whole module thing. Why not recommend people to add additional static class if it needs to be targetable? Im upp for hashes. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Web marketing people often freak out if they cannot attach the out-of-the-box tools like HeapAnalytics or MouseFlow to specific elements of a website/webapp by id/classname (or if the classnames they attach to are changing with each release). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's another example. Using a hash is be fine by me, and the mentioned use cases can still be addressed with static classes or e.g. data attributes. It's just a personal preference I thought I'll mention in case somebody else finds this interesting. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This sounds like a very artificial constraint. I expect that people will trip over this if it's not enforced. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Great point @andriijas. I agree that we should recommend people decouple styling classes from identifiers for testing or the tools like the ones @sompylasar mentioned. The fact that we used styling classes for so many years as hooks for these tools wasn't because they were actually related concerns, it was just all we had. Make it easy to do the right thing / hard to do the wrong thing. |
||
}, | ||
}, | ||
{ | ||
loader: require.resolve('postcss-loader'), | ||
options: postCSSLoaderOptions, | ||
}, | ||
], | ||
}, | ||
extractTextPluginOptions | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
/** | ||
* 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. | ||
*/ | ||
|
||
import React from 'react'; | ||
import styles from './assets/style.module.css'; | ||
|
||
export default () => ( | ||
<p className={styles.cssModulesInclusion}>CSS Modules are working!</p> | ||
); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
/** | ||
* 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. | ||
*/ | ||
|
||
import React from 'react'; | ||
import ReactDOM from 'react-dom'; | ||
import CssModulesInclusion from './CssModulesInclusion'; | ||
|
||
describe('css modules inclusion', () => { | ||
it('renders without crashing', () => { | ||
const div = document.createElement('div'); | ||
ReactDOM.render(<CssModulesInclusion />, div); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How should CSS modules be interpreted by Jest? I would think that http://facebook.github.io/jest/docs/webpack.html#mocking-css-modules is a good idea. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've added in the recommend |
||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
.cssModulesInclusion { | ||
background: darkblue; | ||
color: lightblue; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,6 +24,7 @@ You can find the most recent version of this guide [here](https://github.com/fac | |
- [Importing a Component](#importing-a-component) | ||
- [Code Splitting](#code-splitting) | ||
- [Adding a Stylesheet](#adding-a-stylesheet) | ||
- [Adding a CSS Modules stylesheet](#adding-a-css-modules-stylesheet) | ||
- [Post-Processing CSS](#post-processing-css) | ||
- [Adding a CSS Preprocessor (Sass, Less etc.)](#adding-a-css-preprocessor-sass-less-etc) | ||
- [Adding Images, Fonts, and Files](#adding-images-fonts-and-files) | ||
|
@@ -513,6 +514,51 @@ In development, expressing dependencies this way allows your styles to be reload | |
|
||
If you are concerned about using Webpack-specific semantics, you can put all your CSS right into `src/index.css`. It would still be imported from `src/index.js`, but you could always remove that import if you later migrate to a different build tool. | ||
|
||
## Adding a CSS Modules stylesheet | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should comment this section out before landing as it would be too confusing. |
||
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]**. | ||
|
||
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; | ||
} | ||
``` | ||
|
||
### `another-stylesheet.css` | ||
|
||
```css | ||
.button { | ||
color: green; | ||
} | ||
``` | ||
|
||
### `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 | ||
|
||
class Button extends Component { | ||
render() { | ||
// You can use them as regular CSS styles | ||
return <div className={styles.button} />; | ||
} | ||
} | ||
``` | ||
### `exported HTML` | ||
No clashes from other `.button` classnames | ||
|
||
```html | ||
<div class="src__Button-module___button"></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 | ||
|
||
This project setup minifies your CSS and adds vendor prefixes to it automatically through [Autoprefixer](https://github.com/postcss/autoprefixer) so you don’t need to worry about it. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comment outdated (since we don't use a particular config anymore)