├── .babelrc
├── .gitignore
├── README.md
├── RecursiveDivs.js
├── TimingStream.js
├── benchmarkRunner.js
├── benchmarkedFns.js
├── index.js
└── package.json
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["es2015", "react"],
3 | "plugins": ["transform-react-constant-elements", "transform-react-inline-elements"]
4 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # react-server-perf-tricks
2 |
3 | This repo contains the code for the benchmark used in my talk ["Speed Up Your React Server With These 6 Weird Tricks"](http://www.youtube.com/watch?feature=player_embedded&v=PnpfGy7q96U).
4 |
5 |
6 |
7 | In the talk, I presented a small ReactJS benchmark, and I edited the code in stages to improve the benchmark performance. All 7 versions of the code are present in this repo as different branches, from stage-0 (no optimizations at all) to stage-6 (all optimizations from the talk applied). Note that each stage includes the tricks from the previous stages.
8 |
9 | ## How to install
10 |
11 | ```
12 | git clone https://github.com/aickin/react-server-perf-tricks.git
13 | npm install
14 | ```
15 |
16 | ## How to run
17 |
18 | Checkout the stage you want to run and then type `npm run benchmark`. For example, if you want to run stage 3 (Babel Transforms):
19 |
20 | ```
21 | git checkout stage-3
22 | npm run benchmark
23 | ```
24 |
--------------------------------------------------------------------------------
/RecursiveDivs.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | class RecursiveDivs extends React.Component {
4 | render() {
5 | const {depth, breadth} = this.props;
6 |
7 | if (depth <= 0) {
8 | return
{"abcdefghij"}
;
9 | }
10 |
11 | let children = [];
12 | for (let i = 0; i < breadth; i++) {
13 | children.push();
14 | }
15 | return this.click()}>{children}
;
16 | }
17 |
18 | click() {
19 | alert("clicked!");
20 | }
21 |
22 | componentCacheKey() {
23 | return JSON.stringify(this.props);
24 | }
25 |
26 | }
27 |
28 | export default RecursiveDivs;
--------------------------------------------------------------------------------
/TimingStream.js:
--------------------------------------------------------------------------------
1 | import stream from "stream"
2 |
3 | export default class TimingStream extends stream.Writable {
4 | _write(data, encoding, next) {
5 | if (!this.firedFirstByte && data.length > 0) {
6 | this.firedFirstByte = true;
7 | this.emit("start");
8 | // no need to emit "finish" explicitly; that is part of stream.Writable
9 | }
10 | next();
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/benchmarkRunner.js:
--------------------------------------------------------------------------------
1 | import Benchmark from "benchmark"
2 | import benchmarkedFns from "./benchmarkedFns"
3 |
4 | // add tests; can be a single test or an array of tests.
5 | let benchmarkedFnsArray = Array.isArray(benchmarkedFns) ? benchmarkedFns : [benchmarkedFns];
6 |
7 | const suite = new Benchmark.Suite();
8 |
9 | benchmarkedFnsArray.forEach((benchmarkedSpec) => {
10 | suite.add(benchmarkedSpec);
11 | })
12 |
13 | suite
14 | .on("complete", function () {
15 | for (let index = 0; index < this.length; index++) {
16 | const benchmark = this[index];
17 | console.log(benchmark.name);
18 | console.log(`Mean: ${Math.round(benchmark.stats.mean * 1000)} ms`);
19 | console.log(`Std Dev: ${Math.round(benchmark.stats.deviation * 1000)} ms`);
20 | console.log("");
21 | }
22 | })
23 | .run({ 'async': true });
24 |
--------------------------------------------------------------------------------
/benchmarkedFns.js:
--------------------------------------------------------------------------------
1 | import React from "react"
2 | import ReactDOMServer from "react-dom-stream/server"
3 | import LRURenderCache from "react-dom-stream/lru-render-cache"
4 | import RecursiveDivs from "./RecursiveDivs"
5 | import TimingStream from "./TimingStream"
6 |
7 | const depth = 4, breadth = 11;
8 |
9 | const cache1 = new LRURenderCache(), cache2 = new LRURenderCache();
10 |
11 | const render1 = (deferred) => {
12 | const stream = ReactDOMServer.renderToString(, {cache: cache1});
13 | stream.pipe(new TimingStream())
14 | .on("start", () => {
15 | deferred.resolve();
16 | stream.unpipe();
17 | });
18 | }
19 |
20 | const render2 = (deferred) => {
21 | const stream = ReactDOMServer.renderToString(, {cache: cache2});
22 | stream.pipe(new TimingStream())
23 | .on("finish", () => {
24 | deferred.resolve();
25 | stream.unpipe();
26 | });
27 | }
28 |
29 | export default [
30 | {name: "Streaming TTFB with cache", defer: true, fn:render1},
31 | {name: "Streaming TTLB with cache", defer: true, fn:render2}
32 | ];
33 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | require("babel-register");
2 | require("./benchmarkRunner");
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-server-perf-tricks",
3 | "version": "0.1.0",
4 | "description": "A benchmark repo for React Server Side Perf Tricks",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "benchmark": "NODE_ENV=production node index.js"
9 | },
10 | "author": "Sasha Aickin",
11 | "license": "Apache-2.0",
12 | "dependencies": {
13 | "babel-plugin-transform-react-constant-elements": "^6.4.0",
14 | "babel-plugin-transform-react-inline-elements": "^6.4.0",
15 | "babel-preset-es2015": "^6.3.13",
16 | "babel-preset-react": "^6.3.13",
17 | "babel-register": "^6.3.13",
18 | "benchmark": "^2.0.0",
19 | "react": "^0.14.6",
20 | "react-dom": "^0.14.6",
21 | "react-dom-stream": "^0.5.0"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------