mirror of
https://github.com/zhigang1992/create-react-app.git
synced 2026-04-23 04:40:23 +08:00
Add support for CSS Modules with explicit filename (#2285)
* Add css modules with [name].modules.css file convention * Add e2e for CSS Modules * Updated based on feedback * Change css modules class name to be deterministic and fix licences * Update css modules class naming convention
This commit is contained in:
@@ -30,6 +30,20 @@ const publicUrl = '';
|
||||
// Get environment variables to inject into our app.
|
||||
const env = getClientEnvironment(publicUrl);
|
||||
|
||||
// Options for PostCSS as we reference these options twice
|
||||
// Adds vendor prefixing to support IE9 and above
|
||||
const postCSSLoaderOptions = {
|
||||
// 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 development configuration.
|
||||
// It is focused on developer experience and fast rebuilds.
|
||||
// The production configuration is different and lives in a separate file.
|
||||
@@ -209,8 +223,10 @@ module.exports = {
|
||||
// "style" loader turns CSS into JS modules that inject <style> tags.
|
||||
// In production, we use a plugin to extract that CSS to a file, but
|
||||
// in development "style" loader enables hot editing of CSS.
|
||||
// By default we support CSS Modules with the extension .module.css
|
||||
{
|
||||
test: /\.css$/,
|
||||
exclude: /\.module\.css$/,
|
||||
use: [
|
||||
require.resolve('style-loader'),
|
||||
{
|
||||
@@ -221,18 +237,28 @@ module.exports = {
|
||||
},
|
||||
{
|
||||
loader: require.resolve('postcss-loader'),
|
||||
options: postCSSLoaderOptions,
|
||||
},
|
||||
],
|
||||
},
|
||||
// Adds support for CSS Modules (https://github.com/css-modules/css-modules)
|
||||
// using the extension .module.css
|
||||
{
|
||||
test: /\.module\.css$/,
|
||||
use: [
|
||||
require.resolve('style-loader'),
|
||||
{
|
||||
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,
|
||||
modules: true,
|
||||
localIdentName: '[path]__[name]___[local]',
|
||||
},
|
||||
},
|
||||
{
|
||||
loader: require.resolve('postcss-loader'),
|
||||
options: postCSSLoaderOptions,
|
||||
},
|
||||
],
|
||||
},
|
||||
// "file" loader makes sure those assets get served by WebpackDevServer.
|
||||
|
||||
@@ -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 = {
|
||||
// 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]',
|
||||
},
|
||||
},
|
||||
{
|
||||
loader: require.resolve('postcss-loader'),
|
||||
options: postCSSLoaderOptions,
|
||||
},
|
||||
],
|
||||
},
|
||||
extractTextPluginOptions
|
||||
|
||||
@@ -21,6 +21,16 @@ describe('Integration', () => {
|
||||
).to.match(/#feature-css-inclusion\{background:.+;color:.+}/);
|
||||
});
|
||||
|
||||
it('css modules inclusion', async () => {
|
||||
const doc = await initDOM('css-modules-inclusion');
|
||||
|
||||
expect(
|
||||
doc.getElementsByTagName('style')[0].textContent.replace(/\s/g, '')
|
||||
).to.match(
|
||||
/.+__style-module___cssModulesInclusion+\{background:.+;color:.+}/
|
||||
);
|
||||
});
|
||||
|
||||
it('image inclusion', async () => {
|
||||
const doc = await initDOM('image-inclusion');
|
||||
|
||||
|
||||
@@ -81,6 +81,11 @@ class App extends Component {
|
||||
this.setFeature(f.default)
|
||||
);
|
||||
break;
|
||||
case 'css-modules-inclusion':
|
||||
import(
|
||||
'./features/webpack/CssModulesInclusion'
|
||||
).then(f => this.setFeature(f.default));
|
||||
break;
|
||||
case 'custom-interpolation':
|
||||
import('./features/syntax/CustomInterpolation').then(f =>
|
||||
this.setFeature(f.default)
|
||||
|
||||
13
packages/react-scripts/fixtures/kitchensink/src/features/webpack/CssModulesInclusion.js
vendored
Normal file
13
packages/react-scripts/fixtures/kitchensink/src/features/webpack/CssModulesInclusion.js
vendored
Normal file
@@ -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>
|
||||
);
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,4 @@
|
||||
.cssModulesInclusion {
|
||||
background: darkblue;
|
||||
color: lightblue;
|
||||
}
|
||||
@@ -45,6 +45,7 @@
|
||||
"file-loader": "1.1.6",
|
||||
"fs-extra": "5.0.0",
|
||||
"html-webpack-plugin": "2.30.1",
|
||||
"identity-obj-proxy": "3.0.0",
|
||||
"jest": "22.1.1",
|
||||
"object-assign": "4.1.1",
|
||||
"postcss-flexbugs-fixes": "3.2.0",
|
||||
|
||||
@@ -39,9 +39,13 @@ module.exports = (resolve, rootDir, isEjecting) => {
|
||||
'config/jest/fileTransform.js'
|
||||
),
|
||||
},
|
||||
transformIgnorePatterns: ['[/\\\\]node_modules[/\\\\].+\\.(js|jsx|mjs)$'],
|
||||
transformIgnorePatterns: [
|
||||
'[/\\\\]node_modules[/\\\\].+\\.(js|jsx|mjs)$',
|
||||
'^.+\\.module\\.css$',
|
||||
],
|
||||
moduleNameMapper: {
|
||||
'^react-native$': 'react-native-web',
|
||||
'^.+\\.module\\.css$': 'identity-obj-proxy',
|
||||
},
|
||||
moduleFileExtensions: [
|
||||
'web.js',
|
||||
|
||||
@@ -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
|
||||
|
||||
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.
|
||||
|
||||
Reference in New Issue
Block a user