diff --git a/docusaurus/docs/adding-css-in-js.md b/docusaurus/docs/adding-css-in-js.md new file mode 100644 index 00000000000..c389bfc4ac0 --- /dev/null +++ b/docusaurus/docs/adding-css-in-js.md @@ -0,0 +1,77 @@ +--- +id: adding-css-in-js +title: Adding CSS in JS +sidebar_label: Adding CSS in JS +--- + +> Note: this feature is an **optional feature** available with `react-scripts@3.1.0` and higher. Regular `` stylesheets and CSS files are fully supported. + +This project supports zero-runtime CSS in JSX via [Linaria](https://linaria.now.sh/), complete with dynamic properties, source maps and linting support. + +## [Setup](https://github.com/callstack/linaria#setup) + +Add the `linaria/babel` [preset](https://babeljs.io/docs/en/presets) to `package.json`: + +```json +"babel": { + "presets": [ + "react-app", + "linaria/babel" + ] +} +``` + +The [webpack configuration](https://github.com/callstack/linaria/blob/master/docs/BUNDLERS_INTEGRATION.md#webpack) is already provided for you. + +## Writing CSS + +Import the `styled` helper from `linaria/react` to write a React component with dynamic styles. + +### `App.jsx` + +```jsx +import React from 'react'; +import PropTypes from 'prop-types'; +import { styled } from 'linaria/react'; + +const App = styled.div` + background-color: ${props => (props.theme === 'dark') ? 'black' : 'white'}; +`; + +const App = props => ( +
+ {props.children} +
+) + +App.propTypes = { + theme: PropTypes.oneOf(['light', 'dark']), +}; + +export default App +``` + +### `App.tsx` + +```tsx +import React from 'react'; +import { styled } from 'linaria/react'; + +interface AppProps { + theme: 'light' | 'dark' +} + +const App = styled.button` + background-color: ${props => (props.theme === 'dark') ? 'black' : 'white'}; +`; + +const App: React.FC = props => ( +
+ {props.children} +
+) + +export default App +``` + +See [Linaria documentation](https://github.com/callstack/linaria#documentation) for more information. diff --git a/packages/react-scripts/config/webpack.config.js b/packages/react-scripts/config/webpack.config.js index 8f70442d584..bbc970a3e2d 100644 --- a/packages/react-scripts/config/webpack.config.js +++ b/packages/react-scripts/config/webpack.config.js @@ -352,51 +352,61 @@ module.exports = function(webpackEnv) { { test: /\.(js|mjs|jsx|ts|tsx)$/, include: paths.appSrc, - loader: require.resolve('babel-loader'), - options: { - customize: require.resolve( - 'babel-preset-react-app/webpack-overrides' - ), - // @remove-on-eject-begin - babelrc: false, - configFile: false, - presets: [require.resolve('babel-preset-react-app')], - // Make sure we have a unique cache identifier, erring on the - // side of caution. - // We remove this when the user ejects because the default - // is sane and uses Babel options. Instead of options, we use - // the react-scripts and babel-preset-react-app versions. - cacheIdentifier: getCacheIdentifier( - isEnvProduction - ? 'production' - : isEnvDevelopment && 'development', - [ - 'babel-plugin-named-asset-import', - 'babel-preset-react-app', - 'react-dev-utils', - 'react-scripts', - ] - ), - // @remove-on-eject-end - plugins: [ - [ - require.resolve('babel-plugin-named-asset-import'), - { - loaderMap: { - svg: { - ReactComponent: '@svgr/webpack?-svgo,+ref![path]', + use: [ + { + loader: require.resolve('babel-loader'), + options: { + customize: require.resolve( + 'babel-preset-react-app/webpack-overrides' + ), + // @remove-on-eject-begin + babelrc: false, + configFile: false, + presets: [require.resolve('babel-preset-react-app')], + // Make sure we have a unique cache identifier, erring on the + // side of caution. + // We remove this when the user ejects because the default + // is sane and uses Babel options. Instead of options, we use + // the react-scripts and babel-preset-react-app versions. + cacheIdentifier: getCacheIdentifier( + isEnvProduction + ? 'production' + : isEnvDevelopment && 'development', + [ + 'babel-plugin-named-asset-import', + 'babel-preset-react-app', + 'react-dev-utils', + 'react-scripts', + ] + ), + // @remove-on-eject-end + plugins: [ + [ + require.resolve('babel-plugin-named-asset-import'), + { + loaderMap: { + svg: { + ReactComponent: '@svgr/webpack?-svgo,+ref![path]', + }, + }, }, - }, - }, - ], - ], - // This is a feature of `babel-loader` for webpack (not Babel itself). - // It enables caching results in ./node_modules/.cache/babel-loader/ - // directory for faster rebuilds. - cacheDirectory: true, - cacheCompression: isEnvProduction, - compact: isEnvProduction, - }, + ], + ], + // This is a feature of `babel-loader` for webpack (not Babel itself). + // It enables caching results in ./node_modules/.cache/babel-loader/ + // directory for faster rebuilds. + cacheDirectory: true, + cacheCompression: isEnvProduction, + compact: isEnvProduction, + }, + }, + { + loader: 'linaria/loader', + options: { + sourceMap: isEnvProduction && shouldUseSourceMap, + }, + }, + ], }, // Process any JS outside of the app with Babel. // Unlike the application JS, we only compile the standard ES features. diff --git a/packages/react-scripts/package.json b/packages/react-scripts/package.json index 3be87d94ee3..7f303dae136 100644 --- a/packages/react-scripts/package.json +++ b/packages/react-scripts/package.json @@ -59,6 +59,7 @@ "jest-environment-jsdom-fourteen": "0.1.0", "jest-resolve": "24.7.1", "jest-watch-typeahead": "0.3.0", + "linaria": "1.3.1", "mini-css-extract-plugin": "0.5.0", "optimize-css-assets-webpack-plugin": "5.0.1", "pnp-webpack-plugin": "1.2.1",