├── .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 | YouTube: Speed Up Your React Server With These 6 Weird Tricks 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 | --------------------------------------------------------------------------------