Skip to content

Commit d87f71e

Browse files
committed
[change] StyleSheet performance rewrite
Improves StyleSheet benchmark performance by 13x. Removes undocumented `StyleSheet.resolve` API. Typical mean (and first) task duration. [benchmark] DeepTree: depth=3, breadth=10, wrap=4) -master 2809.76ms (3117.64ms) -patch 211.2ms (364.28ms) [benchmark] DeepTree: depth=5, breadth=3, wrap=1) -master 421.25ms (428.15ms) -patch 32.46ms (47.36ms) This patch adds memoization of DOM prop resolution (~3-4x faster), and re-introduces a `className`-based styling strategy (~3-4x faster). Styles map to "atomic css" rules. Fix #307
1 parent a2cafe5 commit d87f71e

Some content is hidden

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

41 files changed

+2358
-2290
lines changed

docs/apis/StyleSheet.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ Each key of the object passed to `create` must define a style object.
1515

1616
Flattens an array of styles into a single style object.
1717

18-
**render**: function
18+
**renderToString**: function
1919

20-
Returns a React `<style>` element for use in server-side rendering.
20+
Returns a string of the stylesheet for use in server-side rendering.
2121

2222
## Properties
2323

examples/.storybook/webpack.config.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
const path = require('path')
22
const webpack = require('webpack')
33

4+
const DEV = process.env.NODE_ENV !== 'production';
5+
46
module.exports = {
57
module: {
68
loaders: [
@@ -19,7 +21,8 @@ module.exports = {
1921
},
2022
plugins: [
2123
new webpack.DefinePlugin({
22-
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development')
24+
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development'),
25+
'process.env.__REACT_NATIVE_DEBUG_ENABLED__': DEV
2326
}),
2427
// https://github.com/animatedjs/animated/issues/40
2528
new webpack.NormalModuleReplacementPlugin(

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
"dependencies": {
2525
"animated": "^0.1.3",
2626
"array-find-index": "^1.0.2",
27+
"asap": "^2.0.5",
2728
"babel-runtime": "^6.11.6",
2829
"debounce": "^1.0.0",
2930
"deep-assign": "^2.0.0",
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
exports[`apis/AppRegistry/renderApplication getApplication 1`] = `
2+
"<style id=\"react-native-stylesheet\">
3+
html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:rgba(0,0,0,0)}
4+
body{margin:0}
5+
button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}
6+
input::-webkit-inner-spin-button,input::-webkit-outer-spin-button,input::-webkit-search-cancel-button,input::-webkit-search-decoration,input::-webkit-search-results-button,input::-webkit-search-results-decoration{display:none}
7+
.rn_pointerEvents\\:auto, .rn_pointerEvents\\:box-only, .rn_pointerEvents\\:box-none * {pointer-events:auto}.rn_pointerEvents\\:none, .rn_pointerEvents\\:box-only *, .rn_pointerEvents\\:box-none {pointer-events:none}
8+
.rn-bottom\\:0px{bottom:0px;}
9+
.rn-left\\:0px{left:0px;}
10+
.rn-position\\:absolute{position:absolute;}
11+
.rn-right\\:0px{right:0px;}
12+
.rn-top\\:0px{top:0px;}
13+
.rn-alignItems\\:stretch{-webkit-align-items:stretch;-ms-flex-align:stretch;-webkit-box-align:stretch;align-items:stretch;}
14+
.rn-backgroundColor\\:transparent{background-color:transparent;}
15+
.rn-borderTopStyle\\:solid{border-top-style:solid;}
16+
.rn-borderRightStyle\\:solid{border-right-style:solid;}
17+
.rn-borderBottomStyle\\:solid{border-bottom-style:solid;}
18+
.rn-borderLeftStyle\\:solid{border-left-style:solid;}
19+
.rn-borderTopWidth\\:0px{border-top-width:0px;}
20+
.rn-borderRightWidth\\:0px{border-right-width:0px;}
21+
.rn-borderBottomWidth\\:0px{border-bottom-width:0px;}
22+
.rn-borderLeftWidth\\:0px{border-left-width:0px;}
23+
.rn-boxSizing\\:border-box{-moz-box-sizing:border-box;box-sizing:border-box;}
24+
.rn-color\\:inherit{color:inherit;}
25+
.rn-display\\:flex{display:-webkit-box;display:-moz-box;display:-ms-flexbox;display:-webkit-flex;display:flex;}
26+
.rn-flexBasis\\:auto{-webkit-flex-basis:auto;-ms-preferred-size:auto;flex-basis:auto;}
27+
.rn-flexDirection\\:column{-webkit-flex-direction:column;-ms-flex-direction:column;-webkit-box-orient:vertical;-webkit-box-direction:normal;flex-direction:column;}
28+
.rn-font\\:inherit{font:inherit;}
29+
.rn-listStyle\\:none{list-style:none;}
30+
.rn-marginTop\\:0px{margin-top:0px;}
31+
.rn-marginRight\\:0px{margin-right:0px;}
32+
.rn-marginBottom\\:0px{margin-bottom:0px;}
33+
.rn-marginLeft\\:0px{margin-left:0px;}
34+
.rn-minHeight\\:0px{min-height:0px;}
35+
.rn-minWidth\\:0px{min-width:0px;}
36+
.rn-paddingTop\\:0px{padding-top:0px;}
37+
.rn-paddingRight\\:0px{padding-right:0px;}
38+
.rn-paddingBottom\\:0px{padding-bottom:0px;}
39+
.rn-paddingLeft\\:0px{padding-left:0px;}
40+
.rn-position\\:relative{position:relative;}
41+
.rn-textAlign\\:inherit{text-align:inherit;}
42+
.rn-textDecoration\\:none{text-decoration:none;}
43+
.rn-flexShrink\\:0{-webkit-flex-shrink:0px;-ms-flex-negative:0px;flex-shrink:0;}
44+
</style>"
45+
`;

src/apis/AppRegistry/__tests__/renderApplication-test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,6 @@ describe('apis/AppRegistry/renderApplication', () => {
1010
const { element, stylesheet } = getApplication(component, {});
1111

1212
expect(element).toBeTruthy();
13-
expect(stylesheet.type).toEqual('style');
13+
expect(stylesheet).toMatchSnapshot();
1414
});
1515
});

src/apis/AppRegistry/renderApplication.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,6 @@ export function getApplication(RootComponent: Component, initialProps: Object):
3232
rootComponent={RootComponent}
3333
/>
3434
);
35-
const stylesheet = StyleSheet.render();
35+
const stylesheet = StyleSheet.renderToString();
3636
return { element, stylesheet };
3737
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
exports[`apis/StyleSheet/createReactDOMStyle converts ReactNative style to ReactDOM style 1`] = `
2+
Object {
3+
"borderBottomWidth": "1px",
4+
"borderLeftWidth": "1px",
5+
"borderRightWidth": "1px",
6+
"borderTopWidth": "1px",
7+
"borderWidthLeft": "2px",
8+
"borderWidthRight": "3px",
9+
"boxShadow": "1px 1px 1px 1px #000, 1px 2px 0px rgba(255,0,0,1)",
10+
"display": "flex",
11+
"marginBottom": "0px",
12+
"marginTop": "0px",
13+
"opacity": 0,
14+
}
15+
`;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
exports[`apis/StyleSheet/generateCss generates correct css 1`] = `"-webkit-transition-duration:0.1s;transition-duration:0.1s;position:absolute;border-width-right:3px;border-width-left:2px;box-shadow:1px 1px 1px 1px #000;"`;
Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1-
exports[`apis/StyleSheet resolve 1`] = `
2-
Object {
3-
"className": "test __style_df __style_pebn",
4-
"style": Object {
5-
"display": null,
6-
"opacity": 1,
7-
"pointerEvents": null,
8-
},
9-
}
1+
exports[`apis/StyleSheet renderToString 1`] = `
2+
"<style id=\"react-native-stylesheet\">
3+
.rn-borderTopColor\\:red{border-top-color:red;}
4+
.rn-borderRightColor\\:red{border-right-color:red;}
5+
.rn-borderBottomColor\\:red{border-bottom-color:red;}
6+
.rn-borderLeftColor\\:red{border-left-color:red;}
7+
.rn-borderTopWidth\\:0px{border-top-width:0px;}
8+
.rn-borderRightWidth\\:0px{border-right-width:0px;}
9+
.rn-borderBottomWidth\\:0px{border-bottom-width:0px;}
10+
.rn-borderLeftWidth\\:0px{border-left-width:0px;}
11+
.rn-left\\:50px{left:50px;}
12+
.rn-position\\:absolute{position:absolute;}
13+
</style>"
1014
`;
Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
exports[`apis/StyleSheet/registry resolve with stylesheet, resolves to className 1`] = `
2+
Object {
3+
"className": "
4+
rn-borderTopColor:red
5+
rn-borderRightColor:red
6+
rn-borderBottomColor:red
7+
rn-borderLeftColor:red
8+
rn-borderTopWidth:0px
9+
rn-borderRightWidth:0px
10+
rn-borderBottomWidth:0px
11+
rn-borderLeftWidth:0px
12+
rn-left:50px
13+
rn-pointerEvents:box-only
14+
rn-position:absolute
15+
rn-width:100px",
16+
"style": Object {},
17+
}
18+
`;
19+
20+
exports[`apis/StyleSheet/registry resolve with stylesheet, resolves to className 2`] = `
21+
Object {
22+
"className": "
23+
rn-borderTopColor:red
24+
rn-borderRightColor:red
25+
rn-borderBottomColor:red
26+
rn-borderLeftColor:red
27+
rn-borderTopWidth:0px
28+
rn-borderRightWidth:0px
29+
rn-borderBottomWidth:0px
30+
rn-borderLeftWidth:0px
31+
rn-left:50px
32+
rn-pointerEvents:box-only
33+
rn-position:absolute
34+
rn-width:200px",
35+
"style": Object {},
36+
}
37+
`;
38+
39+
exports[`apis/StyleSheet/registry resolve with stylesheet, resolves to className 3`] = `
40+
Object {
41+
"className": "
42+
rn-borderTopColor:red
43+
rn-borderRightColor:red
44+
rn-borderBottomColor:red
45+
rn-borderLeftColor:red
46+
rn-borderTopWidth:0px
47+
rn-borderRightWidth:0px
48+
rn-borderBottomWidth:0px
49+
rn-borderLeftWidth:0px
50+
rn-left:50px
51+
rn-pointerEvents:box-only
52+
rn-position:absolute
53+
rn-width:100px",
54+
"style": Object {},
55+
}
56+
`;
57+
58+
exports[`apis/StyleSheet/registry resolve with stylesheet, resolves to mixed 1`] = `
59+
Object {
60+
"className": "
61+
rn-left:50px
62+
rn-pointerEvents:box-only
63+
rn-position:absolute",
64+
"style": Object {
65+
"borderBottomColor": "red",
66+
"borderBottomWidth": "0px",
67+
"borderLeftColor": "red",
68+
"borderLeftWidth": "0px",
69+
"borderRightColor": "red",
70+
"borderRightWidth": "0px",
71+
"borderTopColor": "red",
72+
"borderTopWidth": "0px",
73+
"width": "100px",
74+
},
75+
}
76+
`;
77+
78+
exports[`apis/StyleSheet/registry resolve with stylesheet, resolves to mixed 2`] = `
79+
Object {
80+
"className": "
81+
rn-left:50px
82+
rn-pointerEvents:box-only
83+
rn-position:absolute
84+
rn-width:200px",
85+
"style": Object {
86+
"borderBottomColor": "red",
87+
"borderBottomWidth": "0px",
88+
"borderLeftColor": "red",
89+
"borderLeftWidth": "0px",
90+
"borderRightColor": "red",
91+
"borderRightWidth": "0px",
92+
"borderTopColor": "red",
93+
"borderTopWidth": "0px",
94+
},
95+
}
96+
`;
97+
98+
exports[`apis/StyleSheet/registry resolve with stylesheet, resolves to mixed 3`] = `
99+
Object {
100+
"className": "
101+
rn-left:50px
102+
rn-pointerEvents:box-only
103+
rn-position:absolute",
104+
"style": Object {
105+
"borderBottomColor": "red",
106+
"borderBottomWidth": "0px",
107+
"borderLeftColor": "red",
108+
"borderLeftWidth": "0px",
109+
"borderRightColor": "red",
110+
"borderRightWidth": "0px",
111+
"borderTopColor": "red",
112+
"borderTopWidth": "0px",
113+
"width": "100px",
114+
},
115+
}
116+
`;
117+
118+
exports[`apis/StyleSheet/registry resolve without stylesheet, resolves to inline styles 1`] = `
119+
Object {
120+
"className": "
121+
",
122+
"style": Object {
123+
"borderBottomColor": "red",
124+
"borderBottomWidth": "0px",
125+
"borderLeftColor": "red",
126+
"borderLeftWidth": "0px",
127+
"borderRightColor": "red",
128+
"borderRightWidth": "0px",
129+
"borderTopColor": "red",
130+
"borderTopWidth": "0px",
131+
"left": "50px",
132+
"pointerEvents": "box-only",
133+
"position": "absolute",
134+
"width": "100px",
135+
},
136+
}
137+
`;
138+
139+
exports[`apis/StyleSheet/registry resolve without stylesheet, resolves to inline styles 2`] = `
140+
Object {
141+
"className": "
142+
",
143+
"style": Object {
144+
"borderBottomColor": "red",
145+
"borderBottomWidth": "0px",
146+
"borderLeftColor": "red",
147+
"borderLeftWidth": "0px",
148+
"borderRightColor": "red",
149+
"borderRightWidth": "0px",
150+
"borderTopColor": "red",
151+
"borderTopWidth": "0px",
152+
"left": "50px",
153+
"pointerEvents": "box-only",
154+
"position": "absolute",
155+
"width": "200px",
156+
},
157+
}
158+
`;
159+
160+
exports[`apis/StyleSheet/registry resolve without stylesheet, resolves to inline styles 3`] = `
161+
Object {
162+
"className": "
163+
",
164+
"style": Object {
165+
"borderBottomColor": "red",
166+
"borderBottomWidth": "0px",
167+
"borderLeftColor": "red",
168+
"borderLeftWidth": "0px",
169+
"borderRightColor": "red",
170+
"borderRightWidth": "0px",
171+
"borderTopColor": "red",
172+
"borderTopWidth": "0px",
173+
"left": "50px",
174+
"pointerEvents": "box-only",
175+
"position": "absolute",
176+
"width": "100px",
177+
},
178+
}
179+
`;

0 commit comments

Comments
 (0)