diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 62c521a7..580d0e0b 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -13,5 +13,6 @@ https://github.com/necolas/react-native-web/CONTRIBUTING.md
- [ ] includes documentation
- [ ] includes tests
+- [ ] includes benchmark reports
- [ ] includes an interactive example
- [ ] includes screenshots/videos
diff --git a/.gitignore b/.gitignore
index a2af7f53..0a7ae798 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
/dist
/dist-examples
+/dist-performance
/node_modules
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 474462e1..44531211 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,7 +1,5 @@
# Contributing
-We are open to, and grateful for, any contributions made by the community.
-
## Reporting Issues and Asking Questions
Before opening an issue, please search the [issue
@@ -31,6 +29,12 @@ Run the examples:
npm run examples
```
+Run the benchmarks in a browser by opening `./performance/index.html` after running:
+
+```
+npm run build:performance
+```
+
### Building
```
diff --git a/package.json b/package.json
index edfe1d6b..cfb19d26 100644
--- a/package.json
+++ b/package.json
@@ -11,10 +11,11 @@
"scripts": {
"build": "del ./dist && mkdir dist && babel src -d dist --ignore **/__tests__",
"build:examples": "build-storybook -o dist-examples -c ./examples/.storybook",
+ "build:performance": "cd performance && webpack",
"build:umd": "webpack --config webpack.config.js --sort-assets-by --progress",
"deploy:examples": "git checkout gh-pages && rm -rf ./storybook && mv dist-examples storybook && git add -A && git commit -m \"Storybook deploy\" && git push origin gh-pages && git checkout -",
"examples": "start-storybook -p 9001 -c ./examples/.storybook --dont-track",
- "lint": "eslint src",
+ "lint": "eslint performance src",
"prepublish": "npm run build && npm run build:umd",
"test": "npm run lint && npm run test:jest",
"test:jest": "jest",
@@ -48,6 +49,7 @@
"eslint-plugin-react": "^6.1.2",
"file-loader": "^0.9.0",
"jest": "^16.0.2",
+ "marky": "^1.1.1",
"node-libs-browser": "^0.5.3",
"react": "~15.4.1",
"react-addons-test-utils": "~15.4.1",
diff --git a/performance/benchmark.js b/performance/benchmark.js
new file mode 100644
index 00000000..aa4c9066
--- /dev/null
+++ b/performance/benchmark.js
@@ -0,0 +1,65 @@
+import * as marky from 'marky';
+
+const fmt = (time) => `${Math.round(time * 100) / 100}ms`;
+
+const measure = (name, fn) => {
+ marky.mark(name);
+ fn();
+ const performanceMeasure = marky.stop(name);
+ return performanceMeasure;
+};
+
+const benchmark = ({ name, description, setup, teardown, task, runs }) => {
+ return new Promise((resolve) => {
+ const performanceMeasures = [];
+ let i = 0;
+
+ setup();
+ const first = measure('first', task);
+ teardown();
+
+ const done = () => {
+ const mean = performanceMeasures.reduce((sum, performanceMeasure) => {
+ return sum + performanceMeasure.duration;
+ }, 0) / runs;
+
+ const firstDuration = fmt(first.duration);
+ const meanDuration = fmt(mean);
+
+ console.log(`First: ${firstDuration}`);
+ console.log(`Mean: ${meanDuration}`);
+ console.groupEnd();
+ resolve(mean);
+ };
+
+ const a = () => {
+ setup();
+ window.requestAnimationFrame(b);
+ };
+
+ const b = () => {
+ performanceMeasures.push(measure('mean', task));
+ window.requestAnimationFrame(c);
+ };
+
+ const c = () => {
+ teardown();
+ window.requestAnimationFrame(d);
+ };
+
+ const d = () => {
+ i += 1;
+ if (i < runs) {
+ window.requestAnimationFrame(a);
+ } else {
+ window.requestAnimationFrame(done);
+ }
+ };
+
+ console.group();
+ console.log(`[benchmark] ${name}: ${description}`);
+ window.requestAnimationFrame(a);
+ });
+};
+
+module.exports = benchmark;
diff --git a/performance/benchmarks/deepTree/createDeepTree.js b/performance/benchmarks/deepTree/createDeepTree.js
new file mode 100644
index 00000000..8a494df9
--- /dev/null
+++ b/performance/benchmarks/deepTree/createDeepTree.js
@@ -0,0 +1,85 @@
+import React, { Component, PropTypes } from 'react';
+
+const createDeepTree = ({ StyleSheet, View }) => {
+ class DeepTree extends Component {
+ static propTypes = {
+ breadth: PropTypes.number.isRequired,
+ depth: PropTypes.number.isRequired,
+ id: PropTypes.number.isRequired,
+ wrap: PropTypes.number.isRequired
+ };
+
+ render() {
+ const { breadth, depth, id, wrap } = this.props;
+ let result = (
+