Skip to content

feat(react-scripts): support CSS in JS via Linaria #7009

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

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions docusaurus/docs/adding-css-in-js.md
Original file line number Diff line number Diff line change
@@ -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 `[email protected]` and higher. Regular `<link>` 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 => (
<div theme={props.theme}>
{props.children}
</div>
)

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<AppProps>`
background-color: ${props => (props.theme === 'dark') ? 'black' : 'white'};
`;

const App: React.FC<AppProps> = props => (
<div theme={props.theme}>
{props.children}
</div>
)

export default App
```

See [Linaria documentation](https://github.com/callstack/linaria#documentation) for more information.
98 changes: 54 additions & 44 deletions packages/react-scripts/config/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
1 change: 1 addition & 0 deletions packages/react-scripts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down