How it Works
Once you've installed and configured everything, you can start using it, but it's best to explain what happens under the hood.
Compiled uses Babel (with pre-configuration options via Webpack and Parcel) to transform styles into atomic CSS determined at build time, resulting in very performant components.
Let's take a typical component you might write:
/** @jsxImportSource @compiled/react */
import { css } from '@compiled/react';
import type { ReactNode } from 'react';
type Props = { inverted?: boolean, children: ReactNode };
const largeTextStyles = css({
fontSize: '48px',
padding: '8px',
background: '#eee',
});
const invertedStyles = css({
background: '#333',
color: '#fff',
});
export const LargeText = ({ inverted, children }: Props): JSX.Element => {
return <span css={[largeTextStyles, inverted && invertedStyles]}>{children}</span>;
};
Runtime styles (unperformant)
With the most basic Babel setup, Compiled will be transformed to runtime styles. This is typically used in a development or testing environments.
It is not recommended in production environments as it will be less performant, but also mixing runtime and extraction can result in breaking visual changes from atomic specificity conflicts. Refer to extracted styles below for the recommendation.
$ babel src
Successfully compiled 1 file with Babel (9ms)
You'll see a few things happening in the code below:
- All styles are converted into Atomic CSS for reuse.
- Some styles, such as
padding:8px
will be expanded out topadding-left
,padding-right
, etc, while others might be sorted. Read more about this - All
css()
calls are replaced withnull
and instead the styles are injected at runtime with theclassName
inlined. Note thatcssMap()
works slightly differently and maintains the object syntax. - There are a few internal runtime functions that are used to manage the styles like
ax
andCC
. Read more about this - Postcss, autoprefixer, and some other optimizations will run over your code to make it more performant and safer for use.
import { ax, ix, CC, CS } from '@compiled/react/runtime';
const _8 = '._syazu67f{color:#fff}';
const _7 = '._bfhk1d6m{background-color:#333}';
const _6 = '._bfhkr75e{background-color:#eee}';
const _5 = '._19bvftgi{padding-left:1pc}';
const _4 = '._n3tdftgi{padding-bottom:1pc}';
const _3 = '._u5f3ftgi{padding-right:1pc}';
const _2 = '._ca0qftgi{padding-top:1pc}';
const _ = '._1wybckbl{font-size:3pc}';
const largeTextStyles = null;
const invertedStyles = null;
export const LargeText = ({ inverted, children }) => {
return (
<CC>
<CS>{[_, _2, _3, _4, _5, _6, _7, _8]}</CS>
<span
className={ax([
'_1wybckbl _ca0qftgi _u5f3ftgi _n3tdftgi _19bvftgi _bfhkr75e',
inverted && '_bfhk1d6m _syazu67f',
])}>
{children}
</span>
</CC>
);
};
Extracted styles
We highly suggest you turn on style extraction to distribute styles statically at build time, either through NPM or Production environments. Doing this, styles will have their runtime stripped and styles extracted to an atomic style sheet.
Refer to stylesheet extraction for more details.
Let's compare this to runtime styles, assuming we have Parcel configured
$ parcel build ./src/index.html
✨ Built in 4.94s
dist/index.html 246 B 349ms
dist/index.019bae5f.js 136.13 KB 806ms
# This generates `index.compiled.css` file(s) too.
🌽 ✅ Done in 6.26s
You'll see a few different things are happening in the code below:
- All styles are moved into a separate file,
index.compiled.css
, that is imported into this file for your bundler to pick up and combine and serve to the user. - The runtime injection of
<CS>
is no longer required because the styles are statically available.
The main difference beyond the greatly reduced runtime cost is that the atomic styles can be completely deduplicated.
+import "./index.compiled.css";
-import { ax, ix, CC, CS } from '@compiled/react/runtime';
+import { ax, ix } from "@compiled/react/runtime";
-const _8 = '._syazu67f{color:#fff}';
-const _7 = '._bfhk1d6m{background-color:#333}';
-const _6 = '._bfhkr75e{background-color:#eee}';
-const _5 = '._19bvftgi{padding-left:8px}';
-const _4 = '._n3tdftgi{padding-bottom:8px}';
-const _3 = '._u5f3ftgi{padding-right:8px}';
-const _2 = '._ca0qftgi{padding-top:8px}';
-const _ = '._1wybckbl{font-size:3pc}';
var largeTextStyles = null;
var invertedStyles = null;
export const LargeText = ({ inverted, children }) => {
return (
- <CC>
- <CS>{[_, _2, _3, _4, _5, _6, _7, _8]}</CS>
<span
className={ax([
'_1wybckbl _ca0qftgi _u5f3ftgi _n3tdftgi _19bvftgi _bfhkr75e',
inverted && '_bfhk1d6m _syazu67f',
])}>
{children}
</span>
- </CC>
);
};
For reference, the atomic stylesheet is created just as before, now in index.compiled.css
, and with
the bundler config, these *.compiled.css
files will be merged together with duplicates removed, resulting
in a drastically smaller CSS payload to the customer.
These *.compiled.css
files could be distributed via NPM or collected and bundled to customers.
._19bvftgi{padding-left:8px}
._1wybckbl{font-size:3pc}
._bfhk1d6m{background-color:#333}
._bfhkr75e{background-color:#eee}
._ca0qftgi{padding-top:8px}
._n3tdftgi{padding-bottom:8px}
._syazu67f{color:#fff}
._u5f3ftgi{padding-right:8px}
Suggest changes to this page ➚