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 all 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
  •  
  •  
  •  
27 changes: 22 additions & 5 deletions .flowconfig
@@ -1,9 +1,26 @@
[ignore]
# Disable module with broken flow types.
.*/lib/
.*/es/
./benchmarks/
./examples/
.*/benchmarks/.*
.*/examples/.*

.*/node_modules/fbjs/.*
.*/node_modules/babylon/*.*
.*/node_modules/config-chain/*.*
.*/node_modules/npm/*.*
.*/node_modules/npmi/*.*
.*/node_modules/react-native/*.*
.*/node_modules/fbjs/lib/partitionObjectByKey.js
.*/node_modules/conventional-changelog-core/test/fixtures/_malformation.json
.*/node_modules/polished/*.*
.*/node_modules/findup/*.*
.*/node_modules/jss/*.*


[options]
module.system=haste
module.system.node.resolve_dirname=node_modules
module.name_mapper='(react-native)' -> 'empty/object'
module.name_mapper='(preact)' -> 'empty/object'
module.file_ext=.js

[version]
^0.81.0
56 changes: 55 additions & 1 deletion MIGRATION.md
Expand Up @@ -5,6 +5,7 @@ It is sorted by packages.

## Table of Contents
- [babel-plugin-fela](#babel-plugin-fela)
- [fela-combine-arrays](#fela-combine-arrays)
- [fela-dom](#fela-dom)
- [fela-plugin-dynamic-prefixer](#fela-plugin-dynamic-prefixer)
- [fela-plugin-remove-undefined](#fela-plugin-remove-undefined)
Expand All @@ -16,6 +17,14 @@ It is sorted by packages.
This package has been deprecated and removed as it does not add the desired benefits.<br>
One should remove it from their Babel config as it is no longer guaranteed to work as expected.


## fela-combine-arrays

### 1.0.9
This package has been deprecated as it is obsolete.<br>
css-in-js-utils' assignStyle now combines arrays by default.<br>
Please remove it from your Fela configuration.

## fela-dom

### 7.0.0
Expand Down Expand Up @@ -48,6 +57,51 @@ One should remove it form their Fela config as it no longer required.

## inferno-fela

### 10.0.0

Check the description for react-fela@10.0.0 below. It's the same changes for preact-fela as well.

### 8.0.0
In order to use inferno-fela > 8.0.0, Inferno > 4.0.0 is required.<br>
If you can't upgrade to Inferno 4.0.0 yet, consider using inferno-fela 7.0.1.
If you can't upgrade to Inferno 4.0.0 yet, consider using inferno-fela 7.0.1.

## preact-fela

### 10.0.0
Check the description for react-fela@10.0.0 below. It's the same changes for preact-fela as well.


## react-fela

### 10.0.0


#### Deprecating APIs
With this major release, we're deprecating a bunch of APIs that have been in use for almost 2 years which are **createComponent**, **createComponentWithProxy**, **connect** and **withTheme**.

> If you want to know why, please check the [umbrella PR](https://github.com/rofrischmann/fela/pull/597) and the [post on Medium](https://medium.com/felajs/the-future-of-fela-d4dad2efad00).

The new APIs use the render-props pattern rather than providing a HoC. If you're not familiar with the render-props, you should first [read about it](https://reactjs.org/docs/render-props.html).

In order to migrate to version 10.0.0, one must replace the following APIs:
| Old API | New API |
| --- | --- |
| createComponent<br>createComponentWithProxy<br>connect | FelaComponent |
| withTheme | FelaTheme |

> [Check out the detailed migration guide](./packages/react-fela/README.md#migration).

#### API Changes
Apart from the deprecation, we also changed some APIs in order to fully replace the deprecations.

##### FelaTheme
The FelaTheme component now no longer uses the special `render` prop to pass a render function, but uses `children` instead.

Check the [API Reference](docs/api/bindings/FelaTheme.md) for detailed information.

##### FelaComponent
The same goes for FelaComponent. We now use `children` directly rather than `render`. In order to pass a primitive render type, one may now use the `as` prop.

Instead of accepting both `style` and `rule` it now only accepts `style` but allows both style objects and rules. It even also accepts arrays of those.

Check the [API Reference](docs/api/bindings/FelaComponent.md) for detailed information.
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();
})();