loading...
Cover image for Compiled: A CSS-in-JS library without the runtime cost
LogRocket

Compiled: A CSS-in-JS library without the runtime cost

bnevilleoneill profile image Brian Neville-O'Neill Originally published at blog.logrocket.com on ・5 min read

Written by Nathan Sebhastian✏️

CSS-in-JS is a collection of patterns and ideas that aims to solve some of the most vexing challenges developers faced when writing CSS for their applications. It addresses some of the difficulties associated with scaling CSS, such as separating CSS code into smaller files using the JavaScript module system and scoping CSS style by generating unique, local names.

But CSS-in-JS doesn’t come without a cost. When you use modern UI libraries such as React, browsers wait for your JavaScript bundle file to download before rendering anything on the screen, which increases the loading time.

The problem with CSS-in-JS

Google coined the concept of First Meaningful Paint (FMP) to measure when the primary content of a page is visible to the user. As React gains adoption among companies and developers building complex projects, the bundle size of a React application can grow from 2MB to more than 20MB.

To solve the bundle size problem, developers have created several solutions. For example, you can split the bundle into several chunks or lazy load the app (i.e., the most important parts first).

The CSS-in-JS pattern has a similar problem with modern UI libraries. CSS used to be written statically, so the browser simply needed to read the code. With CSS-in-JS, browsers need to dynamically generate and update <style> tags in response to state and prop changes.

The fantastic developer experience of writing CSS inside JavaScipt files comes at the cost of generating CSS at runtime.

LogRocket Free Trial Banner

Compiled to the rescue

Compiled is a CSS-in-JS library created by Atlassian Labs that aims to provide that excellent developer experience without the runtime cost. It works by statically analyzing your code at build time, transforming it into Compiled components, and then moving the styling code into the head of the document at runtime.

Compiled mirrors the styling pattern found in styled-components and Emotion, so you’ll be right at home if you’ve used either of those.

Below is a simple example.

import { styled } from '@compiled/css-in-js';

export const ColoredText = styled.span`
  color: #ff5630;
`;

The above will be transformed into the following Compiled component.

import React from 'react';
import { CC, CS } from '@compiled/css-in-js';
export const ColoredText = /*#__PURE__*/ React.forwardRef(
  ({ as: C = 'span', ...props }, ref) => (
    <CC>
      <CS hash="zd46j1">{['.cc-zd46j1{color:#ff5630}']}</CS>
      <C
        {...props}
        ref={ref}
        className={'cc-zd46j1' + (props.className ? ' ' + props.className : '')}
      />
    </CC>
  )
);
if (process.env.NODE_ENV === 'development') {
  ColoredText.displayName = 'ColoredText';
}

Just like usual CSS-in-JS, the component will have a unique hash as a class, enabling local scoping.

This transformation enables you to consume the components without any configuration, setup, or tooling. Just import the component and use it.

const EmphasisText = (props) => {
  const color = props.massive ? '#00B8D9' : '#36B37E';
  return (
    <span
      css={{
        color,
        textTransform: 'uppercase',
        fontWeight: 600,
      }}>
      {props.children}
    </span>
  );
};
export default EmphasisText

//... import from other component

import EmphasisText from './EmphasisText';
const WelcomeComponent = () => {
    return (
        <EmphasisText massive>
            Welcome to Jumanji!
        </EmphasisText>
    );
}

It’s exactly the same CSS-in-JS pattern, but without generating CSS at runtime. This single constraint solves performance issues caused by dynamic CSS generation.

Using Compiled with React

To use Compiled with React, you’ll need to install the package and the compiler.

To install the package:

npm i @compiled/css-in-js

Next, install the compiler. You can use either Babel or the TypeScript compiler with Compiled. If you’re using Create React App, you need to eject from the bundle (you’d need to edit the config files to set up both compilers).

To install the Babel plugin:

npm install @compiled/babel-plugin-css-in-js

Make sure the plugin is the first entry in the array.

{
  "plugins": ["@compiled/babel-plugin-css-in-js"]
}

For TypeScript:

npm install @compiled/ts-transform-css-in-js ttypescript

Place the plugin inside your tsconfig.json file.

{
  "compilerOptions": {
    "plugins": [{ "transform": "@compiled/ts-transform-css-in-js" }]
  }
}

Next, get the compiler to pick up the plugins from your config using the ttypescript library.

npm i ttypescript -D

To compile the files, use the ttsc command instead of tsc.

Or, use it inside webpack.

{
  loader: require.resolve('ts-loader'),
  options: {
    compiler: 'ttypescript',
  },
},

You can also use Parcel.

npm i parcel-plugin-ttypescript

Simply write your CSS-in-JS files by importing from Compiled’s main library.

import React from 'react';
import '@compiled/css-in-js';

const EmphasisText = (props) => {
  const color = props.massive ? '#00B8D9' : '#36B37E';
  return (
    <span
      css={{
        color,
        textTransform: 'uppercase',
        fontWeight: 600,
      }}>
      {props.children}
    </span>
  );
};

export default EmphasisText

Next, import the component.

import React from "react";
import ReactDOM from "react-dom";
import EmphasisText from './EmphasisText';

const WelcomeComponent = () => {
    return (
        <EmphasisText massive>
            Welcome to Jumanji!
        </EmphasisText>
    );
}

ReactDOM.render(<WelcomeComponent />, document.getElementById("root"));

Conclusion

The CSS-in-JS pattern has solved one of the biggest problems associated with scaling CSS. By using a modular approach with local scoping, CSS is now more maintainable and less unpredictable. Yet it also comes with some tradeoffs, leading to performance issues related to its dynamic rendering.

Compiled is a CSS-in-JS library that analyzes your code at build time and transforms it into Compiled components to ensure no CSS code is generated at runtime. This way, you can enjoy the great developer experience of writing CSS-in-JS without sacrificing performance.

The Compiled documentation has additional guides for migration from styled-components or Emotions and testing Compiled components with Jest. You can even do server-side rendering with Compiled.


Is your frontend hogging your users' CPU?

As web frontends get increasingly complex, resource-greedy features demand more and more from the browser. If you’re interested in monitoring and tracking client-side CPU usage, memory usage, and more for all of your users in production, try LogRocket.

Alt Text

LogRocket is like a DVR for web apps, recording everything that happens in your web app or site. Instead of guessing why problems happen, you can aggregate and report on key frontend performance metrics, replay user sessions along with application state, log network requests, and automatically surface all errors.

Modernize how you debug web apps — Start monitoring for free.


The post Compiled: A CSS-in-JS library without the runtime cost appeared first on LogRocket Blog.

Posted on by:

bnevilleoneill profile

Brian Neville-O'Neill

@bnevilleoneill

Director content @LogRocket. I didn't write the post you just read. To find out who did, click the link directly above my name.

LogRocket

LogRocket's thoughts on all things frontend.

Discussion

pic
Editor guide