Skip to content

Commit d9e4ba8

Browse files
Merge pull request #20 from PhiLhoSoft/PLS-view-results
View results
2 parents 4548e6d + 3e7ee9c commit d9e4ba8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+551
-551
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,4 @@ jspm_packages
4141

4242

4343
lib
44+
output

README.md

Lines changed: 72 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1-
# CSS-in-js Performance tests
1+
# CSS-in-JS Performance Tests
22

3-
Testing a couple of CSS in JS libraries, check [the source folder](./src/cases) for the different tests.
3+
Testing a couple of CSS-in-JS libraries, check [the source folder](./src/) for the different tests.
44

5-
And read why we did these tests [here](https://engineering.hellofresh.com/the-css-in-js-battle-89c34a7a83ea).
5+
And read why we did these tests in the [CSS-in-JS Battle](https://engineering.hellofresh.com/the-css-in-js-battle-89c34a7a83ea) article.
66

77
## Usage
88

99
You can clone this repository, `npm install` and run `npm run bench` to run the tests yourself.
1010

11-
To set the amount of iterations you can set an environment variable called `ITERATIONS`. This will result in: `ITERATIONS=100 npm run bench`.
11+
To set the amount of iterations (see below) you can set an environment variable called `ITERATIONS`. This will result in: `ITERATIONS=100 npm run bench`.
1212

1313
> Make sure you have Node6 or higher installed as well.
1414
@@ -38,7 +38,7 @@ Hardware:
3838

3939
## Results
4040

41-
The first test is just a simple render test, generate 2 class names, one for a container and one for a button.
41+
The first test is just a simple render test, generates two classes, one for a container and one for a button.
4242

4343
```
4444
Running simple test.
@@ -53,7 +53,6 @@ jss length 447
5353
jss-without-preset length 443
5454
styletron length 366
5555
56-
5756
aphrodite x 9,421 ops/sec ±11.15% (61 runs sampled)
5857
cxs x 21,834 ops/sec ±9.34% (65 runs sampled)
5958
cxs-optimized x 17,377 ops/sec ±3.65% (76 runs sampled)
@@ -67,7 +66,7 @@ styletron length 366
6766
Fastest is: fela
6867
```
6968

70-
The second test overloads on styles, so it adds `n (ITERATIONS)` amount of different styles for the button.
69+
The second test overloads on styles, so it adds `n (ITERATIONS)` amount of different styles with a common part for the buttons. Show which libraries can detect the common part and isolate it.
7170

7271
```
7372
Running styles overload test.
@@ -81,7 +80,6 @@ cxs-optimized length 2337
8180
styletron length 1370
8281
fela length 1349
8382
84-
8 tests completed.
8583
8684
aphrodite x 1,446 ops/sec ±2.55% (69 runs sampled)
8785
jss x 3,160 ops/sec ±2.85% (75 runs sampled)
@@ -95,7 +93,7 @@ fela length 1349
9593
Fastest is: fela,styletron
9694
```
9795

98-
The third test overloads on class names, so it adds `n (ITERATIONS)` amount of different class names with the same styles. This test is interesting to see which library actually merges these styles when they're similar.
96+
The third test overloads on classes, so it adds `n (ITERATIONS)` amount of different class names with the same styles. This test is interesting to see which library actually merges these styles when they're identical.
9997

10098
```
10199
Running classes overload test.
@@ -124,7 +122,7 @@ styletron length 960
124122
Fastest is: fela
125123
```
126124

127-
The fourth test is about media queries and pseudo-styles.
125+
The fourth test is about media queries and pseudo-styles with nested style objects.
128126

129127
```
130128
Running nested test.
@@ -155,6 +153,8 @@ Fastest is: styletron
155153

156154
### Bundle sizes
157155

156+
Launch with `npm run bundle`.
157+
158158
```
159159
Size styletron 2.652KB
160160
Size cxs 9.766KB
@@ -166,6 +166,68 @@ Size glamor 35.436KB
166166
Size aphrodite 18.919KB
167167
```
168168

169+
### View generated code
170+
171+
Launch with `npm run view`.
172+
173+
Find the generated HTML files with their embeded CSS for each test in the `output` directory.
174+
175+
Some observations:
176+
177+
For all of them, class name is stable between generations if same content. Unless said otherwise, the generated CSS is minimized.
178+
179+
#### aphrodite
180+
181+
(simple) Removes a non-used class. Generates class names like `original-name_1fm03kj`. Adds `!important` to each CSS property, but this can be deactivated.
182+
(style overload) Different classes with a common style are kept as is.
183+
(classes overload) Doesn't detect identical classes that remain duplicate.
184+
(nested) Manages pseudo-classes and media queries.
185+
186+
#### cxs and cxs-optimized
187+
188+
(simple) Doesn't remove a non-used class. Generates class names like `cxs-4211614354`.
189+
(style overload) Different classes with a common style are kept as is. Minimized CSS.
190+
(classes overload) Detects identical classes that are merged.
191+
(nested) Manages pseudo-classes and media queries.
192+
193+
cxs-optimized can generate some specialized classes (with names like `cxs-display-block` or `cxs-text-align-center`) removed from the classes using these styles and added to elements using them. Seems limited to properties with a small number of possible values. Named colors are not deduplicated.
194+
195+
#### fela
196+
197+
(simple) Removes a non-used class. Generates class names like `a`, `b`, `c`. Each class has one property only, they are merged at element level.
198+
(style overload) Styles common to several classes go to classes added to all corresponding elements.
199+
(classes overload) Detects identical classes that are merged.
200+
(nested) Manages pseudo-classes and media queries.
201+
202+
#### free-style
203+
204+
(simple) Doesn't remove a non-used class. Generates class names like `f1lzwo7y`.
205+
(style overload) Different classes with a common style are kept as is.
206+
(classes overload) Detects identical classes that are merged.
207+
(nested) Manages pseudo-classes and media queries.
208+
209+
#### glamor
210+
211+
(simple) Doesn't remove a non-used class. Generates class names like `css-h433f4`. Add selectors like `[data-css-h433f4]`.
212+
(style overload) Different classes with a common style are kept as is.
213+
(classes overload) Detects identical classes that are merged.
214+
(nested) Manages pseudo-classes and media queries. Adds selectors like `css-1u8v7v4[data-simulate-hover]`.
215+
216+
#### jss and jss-without-preset
217+
218+
(simple) Doesn't remove a non-used class. Generates class names like `original-name-3553477605`. CSS is formatted and indented (1 space).
219+
(style overload) Different classes with a common style are kept as is.
220+
(classes overload) Doesn't detect identical classes that remain duplicate.
221+
(nested) Manages pseudo-classes and media queries.
222+
223+
#### styletron
224+
225+
(simple) Doesn't remove a non-used class. Generates class names like `a`, `b`, `c`. Each class has one property only, they are merged at element level (starts with a space).
226+
(style overload) Styles common to several classes go to classes added to all corresponding elements.
227+
(classes overload) Detects identical classes that are merged.
228+
(nested) Manages pseudo-classes and media queries.
229+
230+
169231
<p align="center">
170232
<a href="https://hellofresh.com">
171233
<img width="120" src="https://www.hellofresh.de/images/hellofresh/press/HelloFresh_Logo.png">

package.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "css-in-js-perf-tests",
33
"version": "1.0.0",
4-
"description": "Performance tests for CSS-in-js libraries",
4+
"description": "Performance tests for CSS-in-JS libraries",
55
"scripts": {
66
"compile": "rimraf lib/ && babel src/ --out-dir lib",
77
"bench:simple-test": "node lib/simple-test",
@@ -10,6 +10,11 @@
1010
"bench:classes-overload-test": "node lib/classes-overload-test",
1111
"bench": "npm run compile && npm run bench:simple-test && npm run bench:nested-test && npm run bench:style-overload-test && npm run bench:classes-overload-test",
1212
"bundle": "babel-node src/size-test",
13+
"view:simple-test": "node lib/simple-test/view.js",
14+
"view:nested-test": "node lib/nested-test/view.js",
15+
"view:style-overload-test": "node lib/style-overload-test/view.js",
16+
"view:classes-overload-test": "node lib/classes-overload-test/view.js",
17+
"view": "rimraf output/ && npm run view:simple-test && npm run view:nested-test && npm run view:style-overload-test && npm run view:classes-overload-test",
1318
"lint": "eslint src/"
1419
},
1520
"repository": {
@@ -34,6 +39,7 @@
3439
"glamor": "^2.18.2",
3540
"jss": "^5.5.6",
3641
"jss-camel-case": "^2.0.2",
42+
"jss-nested": "^2.5.0",
3743
"jss-preset-default": "^0.8.0",
3844
"rimraf": "^2.5.4",
3945
"styletron-client": "^2.1.1",
Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,17 @@
11
import { StyleSheet, css as aphroditeCss, StyleSheetServer, StyleSheetTestUtils } from 'aphrodite';
22
import { stylesheet, buttonClassNames } from '../styles';
3-
import { renderHtml } from '../render';
3+
import { renderHtml, renderBody } from '../render';
44

5-
export const aphroditeCase = () => {
5+
export const aphroditeCase = (caseName) => {
66
const useStyles = StyleSheet.create(stylesheet);
77

88
const getButtonClassName = i => aphroditeCss(useStyles[buttonClassNames[i]]);
99

1010
const { html, css } = StyleSheetServer.renderStatic(() => {
11-
return renderHtml(aphroditeCss(useStyles.container), getButtonClassName);
11+
return renderBody(caseName, aphroditeCss(useStyles.container), getButtonClassName);
1212
});
1313

1414
StyleSheetTestUtils.clearBufferAndResumeStyleInjection();
1515

16-
return `
17-
<html>
18-
<head>
19-
<style type="text/css">${css.content}</style>
20-
</head>
21-
<body>${html}</body>
22-
</html>
23-
`;
16+
return renderHtml(css.content, html);
2417
};
Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,15 @@
11
import cxs from 'cxs/optimized';
22
import { containerStyle, buttonStyles } from '../styles';
3-
import { renderHtml } from '../render';
4-
5-
export const cxsOptimizedCase = () => {
3+
import { renderHtml, renderBody } from '../render';
64

5+
export const cxsOptimizedCase = (caseName) => {
76
const getButtonClassName = i => cxs(buttonStyles[i]);
87

9-
const html = renderHtml(cxs(containerStyle), getButtonClassName);
8+
const html = renderBody(caseName, cxs(containerStyle), getButtonClassName);
109

1110
const { css } = cxs;
1211

1312
cxs.reset();
1413

15-
return `
16-
<html>
17-
<head>
18-
<style type="text/css">${css}</style>
19-
</head>
20-
<body>${html}</body>
21-
</html>
22-
`;
14+
return renderHtml(css, html);
2315
};
Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,15 @@
11
import cxs from 'cxs';
22
import { containerStyle, buttonStyles } from '../styles';
3-
import { renderHtml } from '../render';
4-
5-
export const cxsCase = () => {
3+
import { renderHtml, renderBody } from '../render';
64

5+
export const cxsCase = (caseName) => {
76
const getButtonClassName = i => cxs(buttonStyles[i]);
87

9-
const html = renderHtml(cxs(containerStyle), getButtonClassName);
8+
const html = renderBody(caseName, cxs(containerStyle), getButtonClassName);
109

1110
const { css } = cxs;
1211

1312
cxs.reset();
1413

15-
return `
16-
<html>
17-
<head>
18-
<style type="text/css">${css}</style>
19-
</head>
20-
<body>${html}</body>
21-
</html>
22-
`;
14+
return renderHtml(css, html);
2315
};
Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,14 @@
11
import { createRenderer } from 'fela';
2-
import { renderHtml } from '../render';
32
import { containerStyle, buttonStyles } from '../styles';
3+
import { renderHtml, renderBody } from '../render';
44

5-
export const felaCase = () => {
5+
export const felaCase = (caseName) => {
66
const renderer = createRenderer();
77

88
const getButtonClassName = i => renderer.renderRule(() => buttonStyles[i]);
99

10-
const html = renderHtml(renderer.renderRule(() => containerStyle), getButtonClassName);
10+
const html = renderBody(caseName, renderer.renderRule(() => containerStyle), getButtonClassName);
1111
const css = renderer.renderToString();
1212

13-
return `
14-
<html>
15-
<head>
16-
<style type="text/css">${css}</style>
17-
</head>
18-
<body>${html}</body>
19-
</html>
20-
`;
13+
return renderHtml(css, html);
2114
};
Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,15 @@
11
import FreeStyle from 'free-style';
22
import { containerStyle, buttonStyles } from '../styles';
3-
import { renderHtml } from '../render';
3+
import { renderHtml, renderBody } from '../render';
44

5-
export const freeStyleCase = () => {
5+
export const freeStyleCase = (caseName) => {
66
const Style = FreeStyle.create();
77

88
const getButtonClassName = i => Style.registerStyle(buttonStyles[i]);
99

10-
const html = renderHtml(Style.registerStyle(containerStyle), getButtonClassName);
10+
const html = renderBody(caseName, Style.registerStyle(containerStyle), getButtonClassName);
1111

1212
const css = Style.getStyles();
1313

14-
return `
15-
<html>
16-
<head>
17-
<style type="text/css">${css}</style>
18-
</head>
19-
<body>${html}</body>
20-
</html>
21-
`;
14+
return renderHtml(css, html);
2215
};
Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,17 @@
11
import { renderStatic } from 'glamor/server';
22
import { style, flush } from 'glamor';
3-
import { renderHtml } from '../render';
43
import { containerStyle, buttonStyles } from '../styles';
4+
import { renderHtml, renderBody } from '../render';
55

6-
export const glamorCase = () => {
6+
export const glamorCase = (caseName) => {
77

88
const getButtonClassName = i => style(buttonStyles[i]);
99

1010
const { html, css } = renderStatic(() =>
11-
renderHtml(style(containerStyle), getButtonClassName)
11+
renderBody(caseName, style(containerStyle), getButtonClassName)
1212
);
1313

1414
flush();
1515

16-
return `
17-
<html>
18-
<head>
19-
<style type="text/css">${css}</style>
20-
</head>
21-
<body>${html}</body>
22-
</html>
23-
`;
16+
return renderHtml(css, html);
2417
};
Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,18 @@
11
import { create } from 'jss';
22
import camelCase from 'jss-camel-case';
3-
import { renderHtml } from '../render';
43
import { stylesheet, buttonClassNames } from '../styles';
4+
import { renderHtml, renderBody } from '../render';
55

6-
export const jssWithoutPresetCase = () => {
6+
export const jssWithoutPresetCase = (caseName) => {
77
const jss = create();
88
jss.use(camelCase());
99

1010
const { classes } = jss.createStyleSheet(stylesheet).attach();
1111

1212
const getButtonClassName = i => classes[buttonClassNames[i]];
1313

14-
const html = renderHtml(classes.container, getButtonClassName);
14+
const html = renderBody(caseName, classes.container, getButtonClassName);
1515
const css = jss.sheets.toString();
1616

17-
return `
18-
<html>
19-
<head>
20-
<style type="text/css">${css}</style>
21-
</head>
22-
<body>${html}</body>
23-
</html>
24-
`;
17+
return renderHtml(css, html);
2518
};

0 commit comments

Comments
 (0)