---
# System prepended metadata

title: Improve react-northstar performance (css expand during build time)
tags: [pitch]

---

---
robots: noindex, nofollow
tags: pitch
---
For instructions on shaping a project see here: [Shaping a Project](/kX02SXVbS6KzMOQd56i6Cg)

# Improve react-northstar performance (css expand during build time)

## Problem

Performance of CSS-in-JS is the most complicated question. Currently we have a lot of requests from Teams side to improve performance somehow immediately as Fluent components are widely in Teams Modular Packages.

## Appetite

If we will be able to reach reasonable performance level it can comparable with proposed CSS solution.

## Solution

The solution is separated to three parts:
- improve Fela performance
- improve Fela plugins performance
- try to pregenerate some rules at runtime

### Fela tweaks

Fela by itself is quite fast, but I was able to find slow functions there and improved perfomance (improves render time for 5-7%) of one of them.

Goal there to merge existing PR [(robinweser/css-in-js-utils#11)](https://github.com/robinweser/css-in-js-utils/pull/11) and try to find out other places to improve.

### Fela plugins performance

We have already done optimisations there, for example we changed a dependency in one of plugins ([microsoft/fluent-ui-react#1925](https://github.com/microsoft/fluent-ui-react/pull/1925)) and gained 10% improvement.

Currently our slowest plugin is `felaExpandCssShorthandsPlugin` what expands shorthand properties to longhand (`padding => padding-left, padding-right, etc.`):

![](https://i.imgur.com/yFiIppm.png)

The worst thing that we can't improve its performance in anyway except of its removal.

#### Step 1: create helpers

_So how we are going to expand properties?_ Via helpers like [`padding()`](https://polished.js.org/docs/#padding):

```diff
const styles = {
-  padding: '5px',
+  ...padding('5px'),
}
```

In this case we can keep existing behavior and disable that plugin, that will give us around 25% gain. The set of properties is limited to:

- `border`, `borderTop`, `borderRight`, `borderBottom`, `borderLeft` `borderWidth`, `borderStyle`, `borderColor`
- `padding`, `margin`
- `outline`
- `flex`

#### Step 2: babel transform

To avoid runtime costs as each helper is a function I propose to write Babel plugin to tranform them:

```diff
const styles = {
-  ...padding('5px'),
+  paddingLeft: '5px',
+  paddingBottom: '5px',
+  paddingRight: '5px',
+  paddingTop: '5px',
}
```

This will allow us to the same job as the expand plugin without any runtime cost.

### Pregenerate styles

The next step is try to pregenerate some of static styles. Some of our rules are static and can be transformed during build time:

```js
const styles = {
  paddingLeft: token.padding, // dynamic
  paddingRight: '5px', // static
}
```

During `renderRule()` Fela:
- runs `generateDeclarationReference()` to create a key to for cache entry
- runs `cssifyDeclaration()` to tranform JS styles to CSS values
- generates classes, inserts to a cache and notifies DOM consumers

_What if we will be to omit first & second stages?_

```js
const styles = {
  __a: { declaration: 'padding-right5px', css: 'padding-right: 5px' },
}
```

And in custom enhancer handle these cases. At least it worth trying.

### Risks (Rabbit holes)

#### Fela tweaks

__Risk:__ Robin will not accept my PR
__Solution:__ Finalize enhancer on our side

#### Fela plugins performance

__Risk:__ Development of Babel plugin can take too many time
__Solution:__ Finish first step and only then switch to second

#### Pregenerate styles

__Risk:__ It will not work
__Solution:__ Ensure that merging of objects will continue to work

```js
const styles = (props) => ({
   display: 'block',
   ...props.inline && { display: 'inline-block' }
})
```

__Risk:__ There will be no perf improvement
__Solution:__
- Measure amount of static styles
- Test perf improvements before trying to automate transforms

### Out of scope (No-gos)

???