Rockey. Motivation and Requirements

June 02, 2017 0 Comments

Rockey. Motivation and Requirements

 

 

The story began when I started to use recompose by Andrew Clark and decided that I want to compose CSS rules.

CSS in JS enhancers for recompose

And it should work according to this logic:

  • Should create separated CSS class for each CSS enhancer. When change CSS class values via devtools — changes should be applied for all components that were composed with same enhancer.
  • Should not produce a lot of higher order components.
  • Should work fast! I ❤ Performance.

Recompose helps us to re-use a lot of code and make features sharable between components. At our team we have universal React components library built with recompose and we can compose component with specific features for each application. This is good way to control bundle size.

If we need new feature for component — in most cases we will implement new enhancer instead of new higher order component. But the problem was that we didn’t know how to be with CSS code related for specific component enhancer. For example component Button has enhancer raised() that provide CSS rules that should be applied if flag raised exists in props.

It would be really ugly and not usable if each enhancer has it is own CSS file. At first the file structure would be large and with a lot of CSS with very minimum content.

“CSS in JS” approach helps us.

Sharing such components is zero dependency with no need to add a <link> tag to a css file.

To implement “CSS in JS” enhancer for recompose I tried a lot of existing CSS in JS solutions to implement CSS enhancer for recompose. But none made me happy. With some libraries it is not possible. With some libraries there was worst performance. So to reach this feature I decided to develop prototype lib called rockey.

By the way! Rockey — is the name of my dog
Hello! My name is Rockey! 🐶

It is not matter for user and user experience if application was implemented with CSS in JS approach or not. But CSS in JS approach affects on Developer Experience and as the result — developers will ship new releases more faster and new features will be easier to implement.

There is list of requirements and features that should mostly improve DX (at list from my point of view).

Now rockey has it own CSS parser (rockey-css-parse and REPL) and Stylesheet class to work with styles in runtime. But maybe in nearest release I will swap them with existing solution (maybe). For example with JSS by Oleg Slobodskoi or glamor by Sunil Pai. It depends if it possible to implement all requirements and performance numbers.

Requirements list (Table of Contents):

  • I would like to use Template Literals to write CSS in JS
  • I would like to influence on components generated class name
  • I would like to use fast and small library
  • I would like to write dynamic CSS
  • Should be no problems with CSS order
  • I would like to work correct extending
  • I would like to split component into different looks
  • I want to use Component Based selectors
  • I want to work with readable Class Names
  • Should work fast without babel or prepack
  • Experimental feature — Dynamic CSS based on component events

Without explanation:

  • Supports Server Side Rendering
  • Supports Native (at least React Native)
  • Should be compatible with polished by Max Stoiber.
  • Much faster to write code. No needs to write quotes, comas and use camelCase if write CSS as JSON.
  • Much more used way.
  • Possible to copy-paste code from CSS files or snippets from Stack Overflow or other sites :)

At least for development environment. Sometimes it is hard to work in devtools when all CSS classes has fully generated names.

Right example if more readable

Small library is better then large library if the provided features are the same.

Fast library is better then slow library. It performance is more priority then size.

There is React application with different CSS in JS approaches: https://tuchk4.github.io/css-in-js-app/

It is not the real benchmark but it shows the differents between CSS in JS libraries and approaches under the same conditions. The accent was made on dynamic CSS that depends on component props.

For example it is very easy to implement grid system. Just write one JS functions instead of tons of CSS rules like col-1, col-2, col-6 and so on.

Instead of tons of CSS class names — write one JS function
It is possible to implement CSS grid system with SaSS functions that will generate all needed CSS classes but I am JS developer and I don’t know how to do it with SaSS.

There are a lot useful cases for such dynamic CSS:

  • access application theme
  • access components props
  • defined styles if value is not empty for form elements
  • access any env variable like view port size, window width, current url and so on.

Because CSS rules are injected into the DOM as soon as component is rendered there could be problems with CSS rules order.

I would like SupperButton component to be rendered with 3 classes — Button-{{ hash }}, PrimaryButton-{{ hash }} and SuperButton-{{ hash }}. This will make comfortable work in devtools — if change CSS values for parent components — it will also affect on all child components.

Why I would like to have this feature?

At first because this is awesome and improve DX when developing components.

At second — easy way to implement feature without higher order component. Most component features could be implemented as additional component property or as Higher Order Component.

Which way?

There is the approach that helps to make more correct decision what approach use.

  • ripple — could be used in any state. So it should be used as prop.
  • disabled — could be used in any state. So it should be used as prop.
  • success — could NOT be used along with warning and primary. So it should be implemented as Higher Order Component.
  • and so on.

If there is no ❌ — feature should be implemented as prop. If there is a least one ❌ — feature should be implemented as Higher Order Component.

Feature “Split component into different looks” helps us a lot.

And note that dynamic CSS rule for disabled and raised props at Button component should work for PrimaryButton and SuccessButton.

Main goal — keep code as clean as possible.

According to beast practice — keep all components name uniq or anonymous. So if component has uniq name — it is good point to use such name at CSS code.

  • I don’t want to write complex logic to choose correct classnames according to current props and mix it with components logic.
  • I don’t want to set className prop for each component manually.
  • I want to write structure of components and pass only props that affects on components logic behaviour (event handlers, values, data, flags and so on).
  • I want to use real components names for CSS rules instead of classes. Means that if I have component <Card/> — I want to use its name as CSS selector. If I have component <PrimaryCard/> — I want to use its name as CSS selector.
Component Bases selectors for CSS

I love babel and prepack. But I don’t install and setup additional plugins for library. I just want to keep “getting started” step as simple as possible.

And actually I love Create React App and don’t want to eject :) So it is not possible (at for now) to use custom babel plugin.

Babel plugins (or prepack) improve performance only for static CSS rules. But dynamic CSS (when CSS code depends on component props) improve DX mostly and plugins will not work for this case.

Write dynamic CSS that triggers along with events handlers.

Examples:

Its enough to use mapProps and withProps to make enhancers that provides additional styles. But I don’t want to use inline styles as main approach for styling. Oleg Slobodskoi wrote at “High Performance Dynamic Styles” and I completely agree.

Inline Styles have a number of limitations by design:
1. You can’t share an inline style declaration between multiple elements.
2. You need to apply them directly to a specific element.

Also it is not comfortable to work with inline styles — not possible to change styles for all same type elements and Elements panel at devtools is not readable. And it is not cool to write inline styles for :hover, :active, ::before and other pesudo classes.

Meet awesome CSS in JS — tuchk4/awesome-css-in-js

Feel free to suggest awesome link and other information.


Tag cloud