Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simple, robust and performant API #597

Closed
wants to merge 28 commits into from
Closed
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
49 changes: 49 additions & 0 deletions benchmarks/dom-comparison/.babelrc
@@ -0,0 +1,49 @@
{
"presets": [
[
"babel-preset-env",
{
"loose": true,
"modules": false,
"exclude": [
"transform-es2015-typeof-symbol"
],
"targets": {
"browsers": [
"chrome 38",
"android 4",
"firefox 40",
"ios_saf 7",
"safari 7",
"ie 10",
"ie_mob 11",
"edge 12",
"opera 16",
"op_mini 12",
"and_uc 9",
"and_chr 38"
]
}
}
],
"babel-preset-react",
"babel-preset-flow"
],
"plugins": [
[
"babel-plugin-transform-class-properties",
{ loose: true
}
],
[
"babel-plugin-transform-object-rest-spread",
{ useBuiltIns: true
}
],
[
"babel-plugin-transform-react-remove-prop-types",
{ mode: "wrap"
}
]
]
}
70 changes: 70 additions & 0 deletions benchmarks/dom-comparison/README.md
@@ -0,0 +1,70 @@
# benchmarks

Try the [benchmarks app](https://necolas.github.io/react-native-web/benchmarks) online.

To run the benchmarks locally:

```
yarn benchmarks
open ./packages/benchmarks/dist/index.html
```

Develop against these benchmarks:

```
yarn compile --watch
yarn benchmarks --watch
```

## Notes

These benchmarks are approximations of extreme cases that libraries may
encounter. Their purpose is to provide an early-warning signal for performance
regressions. Each test report includes the mean and standard deviation of the
timings, and approximations of the time spent in scripting (S) and layout (L).

The components used in the render benchmarks are simple enough to be
implemented by multiple UI or style libraries. The benchmark implementations
and the features of the style libraries are _only approximately equivalent in
functionality_.

No benchmark will run for more than 20 seconds.

### Mount deep/wide tree

These cases look at the performance of mounting and rendering large trees of
elements that use static styles.

### Update dynamic styles

This case looks at the performance of repeated style updates to a large mounted
tree. Some libraries choose to inject new styles for each "dynamic style",
whereas others choose to use inline styles. Libraries without built-in support
for dynamic styles (i.e., they rely on user-authored inline styles) are not
included.

## Example results

### MacBook Pro (2011)

MacBook Pro (13-inch, Early 2011); 2.3 GHz Intel Core i5; 8 GB 1333 MHz DDR3 RAM. Google Chrome 63.

Typical render timings: mean ± standard deviations.

| Implementation | Mount deep tree (ms) | Mount wide tree (ms) | Dynamic update (ms) |
| :--- | ---: | ---: | ---: |
| `css-modules` | `30.19` `±04.84` | `38.25` `±04.85` | - |
| `react-native-web@0.4.0` | `36.40` `±04.98` | `51.28` `±05.58` | `19.36` `±02.56` |
| `inline-styles` | `64.12` `±07.69` | `94.49` `±11.34` | `09.84` `±02.36` |

### Moto G4

Moto G4 (Android 7); Octa-core (4x1.5 GHz & 4x1.2 Ghz); 2 GB RAM. Google Chrome 63.

Typical render timings: mean ± standard deviations.

| Implementation | Mount deep tree (ms) | Mount wide tree (ms) | Dynamic update (ms) |
| :--- | ---: | ---: | ---: |
| `css-modules` | `98.24` `±20.26` | `143.75` `±25.50` | - |
| `react-native-web@0.4.0` | `131.46` `±18.96` | `174.70` `±14.88` | `60.87` `±06.32` |
| `inline-styles` | `184.58` `±26.23` | `273.86` `±26.23` | `30.28` `±07.44` |
121 changes: 121 additions & 0 deletions benchmarks/dom-comparison/dist/bundle.js

Large diffs are not rendered by default.

16 changes: 16 additions & 0 deletions benchmarks/dom-comparison/dist/index.html
@@ -0,0 +1,16 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Performance tests</title>
<meta name="viewport" content="width=device-width">
<style>
html, body { height: 100%; width: 100%; overflow: hidden; }
.root { height: 100%; overflow: hidden; }
</style>
</head>
<body>
<div class="root"></div>
<script src="./bundle.js"></script>
</body>
</html>
25 changes: 25 additions & 0 deletions benchmarks/dom-comparison/dist/report.html

Large diffs are not rendered by default.

16 changes: 16 additions & 0 deletions benchmarks/dom-comparison/index.html
@@ -0,0 +1,16 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Performance tests</title>
<meta name="viewport" content="width=device-width">
<style>
html, body { height: 100%; width: 100%; overflow: hidden; }
.root { height: 100%; overflow: hidden; }
</style>
</head>
<body>
<div class="root"></div>
<script src="./bundle.js"></script>
</body>
</html>
44 changes: 44 additions & 0 deletions benchmarks/dom-comparison/package.json
@@ -0,0 +1,44 @@
{
"private": true,
"name": "benchmarks",
"version": "0.8.6",
"scripts": {
"build": "mkdir -p dist && cp -f index.html dist/index.html && ./node_modules/.bin/webpack-cli --config ./webpack.config.js"
},
"dependencies": {
"aphrodite": "^2.2.0",
"classnames": "^2.2.5",
"d3-scale-chromatic": "^1.2.0",
"emotion": "^9.2.5",
"fela": "^6.2.1",
"glamor": "2.20.40",
"radium": "^0.24.1",
"react": "^16.3.2",
"react-art": "^16.4.1",
"react-dom": "^16.3.2",
"react-fela": "^8.0.1",
"react-jss": "^8.6.1",
"react-native-web": "0.8.8",
"reactxp": "^1.3.2",
"styled-components": "4.0.0-beta.7",
"styled-jsx": "^2.2.6",
"styletron-engine-atomic": "^1.0.5",
"styletron-react": "^4.2.1"
},
"devDependencies": {
"babel-loader": "^7.1.4",
"babel-plugin-react-native-web": "0.8.6",
"babel-plugin-transform-class-properties": "^6.24.1",
"babel-plugin-transform-object-rest-spread": "^6.26.0",
"babel-plugin-transform-react-remove-prop-types": "^0.4.13",
"babel-preset-env": "^1.7.0",
"babel-preset-flow": "^6.23.0",
"babel-preset-react": "^6.24.1",
"css-loader": "^0.28.11",
"style-loader": "^0.21.0",
"url-loader": "^1.0.1",
"webpack": "^4.8.1",
"webpack-bundle-analyzer": "^2.11.1",
"webpack-cli": "^2.1.3"
}
}
37 changes: 37 additions & 0 deletions benchmarks/dom-comparison/run-headless.js
@@ -0,0 +1,37 @@
const path = require('path');
const puppeteer = require('puppeteer');

const tests = ['Mount deep tree', 'Mount wide tree', 'Update dynamic styles'];
const tracing = process.argv.some(arg => arg.indexOf('tracing') > -1);

if (tracing) {
console.log('\nTracing enabled. (note that this might impact benchmark results, we recommend leaving this turned off unless you need a trace)')
}

(async () => {
console.log('\nStarting headless browser...')
const browser = await puppeteer.launch();
const page = await browser.newPage();
console.log('Opening benchmark app...')
await page.goto(`file://${path.join(__dirname, './dist/index.html')}`);

console.log('Running benchmarks... (this may take a minute or two; do not use your machine while these are running!)')
for (var i = 0; i < tests.length; i++) {
const test = tests[i];
const traceFile = `${test.toLowerCase().replace(/\s/g, '-')}-trace.json`;
// styled-components is auto-selected, so all we gotta do is select the benchmark and press "Run"
await page.select('[data-testid="benchmark-picker"]', test);
await page.waitForSelector('[data-testid="run-button"]')
if (tracing) await page.tracing.start({ path: traceFile });
await page.click('[data-testid="run-button"]')
await page.waitForSelector(`[data-testid="${test} results"]`)
if (tracing) await page.tracing.stop();
const result = await page.$eval(`[data-testid="${test} results"]`, node => node.innerText)
console.log(`\n---${test}---`)
console.log(result)
console.log('Trace written to', traceFile)
}

console.log('Done!')
await browser.close();
})();