# @emotion/babel-plugin

> Babel plugin for the minification and optimization of emotion styles.

`@emotion/babel-plugin` is highly recommended, but not required in version 8 and
above of Emotion.

## Features

<table>
  <thead>
    <tr>
      <th>Feature/Syntax</th>
      <th>Native</th>
      <th>Babel Plugin Required</th>
      <th>Notes</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code>css``</code></td>
      <td align="center">✅</td>
      <td align="center"></td>
      <td></td>
    </tr>
    <tr>
      <td><code>css(...)</code></td>
      <td align="center">✅</td>
      <td align="center"></td>
      <td>Generally used for object styles.</td>
    </tr>
    <tr>
      <td>components as selectors</td>
      <td align="center"></td>
      <td align="center">✅</td>
      <td>Allows an emotion component to be <a href="https://emotion.sh/docs/styled#targeting-another-emotion-component">used as a CSS selector</a>.</td>
    </tr>
    <tr>
      <td>Minification</td>
      <td align="center"></td>
      <td align="center">✅</td>
      <td>Any leading/trailing space between properties in your <code>css</code> and <code>styled</code> blocks is removed. This can reduce the size of your final bundle.</td>
    </tr>
    <tr>
      <td>Dead Code Elimination</td>
      <td align="center"></td>
      <td align="center">✅</td>
      <td>Uglifyjs will use the injected <code>/*#__PURE__*/</code> flag comments to mark your <code>css</code> and <code>styled</code> blocks as candidates for dead code elimination.</td>
    </tr>
    <tr>
      <td>Source Maps</td>
      <td align="center"></td>
      <td align="center">✅</td>
      <td>When enabled, navigate directly to the style declaration in your javascript file.</td>
    </tr>
    <tr>
      <td>Contextual Class Names</td>
      <td align="center"></td>
      <td align="center">✅</td>
      <td>Generated class names include the name of the variable or component they were defined in.</td>
    </tr>
  </tbody>
</table>

## Example

**In**

```javascript
const myStyles = css`
  font-size: 20px;
  @media (min-width: 420px) {
    color: blue;
    ${css`
      width: 96px;
      height: 96px;
    `};
    line-height: 26px;
  }
  background: green;
  ${{ backgroundColor: 'hotpink' }};
`
```

**Out**

```javascript
const myStyles = /* #__PURE__ */ css(
  'font-size:20px;@media(min-width:420px){color:blue;',
  /* #__PURE__ */ css('width:96px;height:96px;'),
  ';line-height:26px;}background:green;',
  { backgroundColor: 'hotpink' },
  ';'
)
```

## Installation

```bash
yarn add --dev @emotion/babel-plugin
```

or if you prefer npm

```bash
npm install --save-dev @emotion/babel-plugin
```

## Usage

### Via `.babelrc` (Recommended)

**.babelrc**

Without options:

```json
{
  "plugins": ["@emotion"]
}
```

With options:

_Defaults Shown_

```js
{
  "plugins": [
    [
      "@emotion",
      {
        // sourceMap is on by default but source maps are dead code eliminated in production
        "sourceMap": true,
        "autoLabel": "dev-only",
        "labelFormat": "[local]",
        "cssPropOptimization": true
      }
    ]
  ]
}
```

Recommended Setup

**.babelrc**

```json
{
  "plugins": ["@emotion"]
}
```

### Via CLI

```bash
babel --plugins @emotion/babel-plugin script.js
```

### Via Node API

```javascript
require('@babel/core').transform('code', {
  plugins: ['@emotion/babel-plugin']
})
```

## Options

### `sourceMap`

`boolean`, defaults to `true`.

This option enables the following:

- Injected source maps for use in browser dev tools

[**Documentation**](https://emotion.sh/docs/source-maps)

> Note:
>
> Source maps are on by default in @emotion/babel-plugin but they will be removed in production builds

### `autoLabel`

`'dev-only' | 'always' | 'never'`, defaults to `dev-only`.

This option enables the following:

- Automatically adds the `label` property to styles so that class names
  generated by `css` or `styled` include the name of the variable the result is
  assigned to.
- Please note that non word characters in the variable will be removed
  (Eg. `iconStyles$1` will become `iconStyles1`) because `$` is not valid
  [CSS ClassName Selector](https://stackoverflow.com/questions/448981/which-characters-are-valid-in-css-class-names-selectors#449000)

Each possible value for this option produces different output code:

- with `dev-only` we optimize the production code, so there are no labels added there, but at the same time we keep labels for development environments,
- with `always` we always add labels when possible,
- with `never` we disable this entirely and no labels are added.

#### css

**In**

```javascript
const brownStyles = css({ color: 'brown' })
```

**Out**

```javascript
const brownStyles = /*#__PURE__*/ css({ color: 'brown' }, 'label:brownStyles;')
```

`brownStyles`'s value would be `css-1q8eu9e-brownStyles`

### `labelFormat`

`string`, defaults to `"[local]"`.

This option only works when `autoLabel` is set to `'dev-only'` or `'always'`. It allows you to
define the format of the resulting `label`. The format is defined via string where
variable parts are enclosed in square brackets `[]`.
For example `labelFormat: "my-classname--[local]"`, where `[local]` will be replaced
with the name of the variable the result is assigned to.

Allowed values:

- `[local]` - the name of the variable the result of the `css` or `styled` expression is assigned to.
- `[filename]` - name of the file (without extension) where `css` or `styled` expression is located.
- `[dirname]` - name of the directory containing the file where `css` or `styled` expression is located.

This format only affects the label property of the expression, meaning that the `css` prefix and hash will
be prepended automatically.

#### css

**In**

```javascript
// BrownView.js
// autoLabel: 'dev-only'
// labelFormat: '[filename]--[local]'
const brownStyles = css({ color: 'brown' })
```

**Out**

```javascript
const brownStyles = /*#__PURE__*/ css(
  { color: 'brown' },
  'label:BrownView--brownStyles;'
)
```

`BrownView--brownStyles`'s value would be `css-hash-BrownView--brownStyles`

#### styled

**In**

```javascript
const H1 = styled.h1({
  borderRadius: '50%',
  transition: 'transform 400ms ease-in-out',
  boxSizing: 'border-box',
  display: 'flex',
  ':hover': {
    transform: 'scale(1.2)'
  }
})
```

**Out**

```javascript
const H1 = /*#__PURE__*/ styled('h1', {
  label: 'H1'
})({
  borderRadius: '50%',
  transition: 'transform 400ms ease-in-out',
  boxSizing: 'border-box',
  display: 'flex',
  ':hover': {
    transform: 'scale(1.2)'
  }
})
```

`H1`'s class name attribute would be `css-hash-H1`

### `cssPropOptimization`

`boolean`, defaults to `true`.

This option assumes that you are using something to make `@emotion/react`'s `jsx` function work for all jsx. If you are not doing so and you do not want such optimizations to occur, disable this option.

### `importMap`

This option allows you to tell @emotion/babel-plugin what imports it should look at to determine what it should transform so if you re-export Emotion's exports, you can still use the Babel transforms

An example file:

```js
import { anotherExport } from 'my-package';
import { someExport, thisIsTheJsxExport } from 'some-package';
```

An example config:

```json
{
  "my-package": {
    "anotherExport": {
      "canonicalImport": ["@emotion/styled", "default"],
      "styledBaseImport": ["my-package/base", "anotherExport"]
    }
  },
  "some-package": {
    "someExport": {
      "canonicalImport": ["@emotion/react", "css"]
    },
    "thisIsTheJsxExport": {
      "canonicalImport": ["@emotion/react", "jsx"]
    }
  }
}
```

## Babel Macros

Instead of using `@emotion/babel-plugin`, you can use emotion with [`babel-plugin-macros`](https://github.com/kentcdodds/babel-plugin-macros). Add `babel-plugin-macros` to your babel config (which is included in Create React App 2.0) and use the imports/packages shown below.

```jsx
import {
  css,
  keyframes,
  injectGlobal,
  flush,
  hydrate
} from '@emotion/css/macro'
import { jsx, css, Global, keyframes } from '@emotion/react/macro'
import styled from '@emotion/styled/macro'
```
