├── .babelrc ├── .eslintrc ├── .gitignore ├── README.md ├── package.json ├── pages ├── ClientTransition.js ├── ServerClient.js ├── Streaming.js └── index.js └── routes.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | "react-require" 4 | ], 5 | "presets": ["es2015", "react"] 6 | } 7 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parserOptions": { 3 | "ecmaFeatures": { 4 | "jsx": true 5 | }, 6 | "sourceType": "module" 7 | }, 8 | "globals": { 9 | "__LOGGER__": false, 10 | "SERVER_SIDE": false 11 | }, 12 | "env": { 13 | "browser": true, 14 | "es6": true, 15 | "node": true, 16 | "jasmine": true 17 | }, 18 | "plugins": [ 19 | "react" 20 | ], 21 | "rules": { 22 | "react/jsx-uses-vars": 2, 23 | "camelcase": 0, 24 | "comma-dangle": [ 25 | 2, 26 | "always-multiline" 27 | ], 28 | "comma-spacing": 0, 29 | "consistent-return": 2, 30 | "constructor-super": 2, 31 | "curly": [ 32 | 2, 33 | "multi-line" 34 | ], 35 | "dot-notation": 2, 36 | "eol-last": 2, 37 | "eqeqeq": [ 38 | 2, 39 | "smart" 40 | ], 41 | "guard-for-in": 2, 42 | "handle-callback-err": 0, 43 | "indent": [ 44 | 2, 45 | "tab" 46 | ], 47 | "key-spacing": 0, 48 | "keyword-spacing": 2, 49 | "linebreak-style": [ 50 | 2, 51 | "unix" 52 | ], 53 | "new-cap": 0, 54 | "new-parens": 0, 55 | "no-cond-assign": [ 56 | 2, 57 | "except-parens" 58 | ], 59 | "no-constant-condition": 2, 60 | "no-dupe-args": 2, 61 | "no-dupe-keys": 2, 62 | "no-empty": 2, 63 | "no-eval": 2, 64 | "no-ex-assign": 2, 65 | "no-extra-bind": 2, 66 | "no-extra-semi": 0, 67 | "no-loop-func": 2, 68 | "no-mixed-requires": 0, 69 | "no-mixed-spaces-and-tabs": 2, 70 | "no-multi-spaces": 0, 71 | "no-new-func": 2, 72 | "no-obj-calls": 2, 73 | "no-path-concat": 2, 74 | "no-process-env": 2, 75 | "no-process-exit": 2, 76 | "no-redeclare": 2, 77 | "no-return-assign": 2, 78 | "no-script-url": 2, 79 | "no-self-compare": 2, 80 | "no-sequences": 0, 81 | "no-shadow": 0, 82 | "no-spaced-func": 0, 83 | "no-this-before-super": 2, 84 | "no-throw-literal": 2, 85 | "no-trailing-spaces": 2, 86 | "no-undef": 2, 87 | "no-underscore-dangle": 0, 88 | "no-unexpected-multiline": 2, 89 | "no-unreachable": 2, 90 | "no-unused-expressions": 0, 91 | "no-unused-vars": 2, 92 | "no-use-before-define": 0, 93 | "no-wrap-func": 0, 94 | "quotes": [ 95 | 0, 96 | "double" 97 | ], 98 | "react/jsx-uses-react": 2, 99 | "semi": [ 100 | 0, 101 | "always" 102 | ], 103 | "semi-spacing": 2, 104 | "space-infix-ops": 0, 105 | "space-unary-ops": 2, 106 | "strict": [ 107 | 2, 108 | "never" 109 | ], 110 | "valid-typeof": 2, 111 | "yoda": 0 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # nyc test coverage 18 | .nyc_output 19 | 20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 21 | .grunt 22 | 23 | # node-waf configuration 24 | .lock-wscript 25 | 26 | # Compiled binary addons (http://nodejs.org/api/addons.html) 27 | build/Release 28 | 29 | # Dependency directories 30 | node_modules 31 | jspm_packages 32 | 33 | # Optional npm cache directory 34 | .npm 35 | 36 | # Optional REPL history 37 | .node_repl_history 38 | 39 | __clientTemp/ 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Demos to showcase some react-server features 2 | 3 | Features: 4 | * Multiple elements as promises for streaming 5 | * Client transition (documentation [here](https://github.com/redfin/react-server/blob/8fcbcb3a20915d8901d95e2622cf723c940f42c4/docs/client-transitions.md)) 6 | * Components with different behavior on the client vs server side for isomorphism 7 | 8 | To setup: 9 | 10 | 1. npm install 11 | 2. npm start 12 | 13 | Note that I am using the following versions: 14 | node v4.3.1 15 | npm 2.14.12 16 | 17 | Check out react-server [here](https://github.com/redfin/react-server)! 18 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-server-demo", 3 | "version": "1.0.0", 4 | "description": "Demo for Redfin ReactJS meetup", 5 | "main": "index.js", 6 | "dependencies": { 7 | "q": "1.4.1", 8 | "react": "^0.14.2", 9 | "react-dom": "^0.14.2", 10 | "react-server": "^0.2.6", 11 | "react-server-cli": "^0.2.6", 12 | "react-server-data-bundle-cache": "^0.2.6", 13 | "superagent": "1.2.0" 14 | }, 15 | "devDependencies": { 16 | "babel-plugin-react-require": "^2.1.0", 17 | "babel-preset-es2015": "^6.9.0", 18 | "babel-preset-react": "^6.5.0", 19 | "eslint": "2.7.0", 20 | "eslint-plugin-react": "3.0.0" 21 | }, 22 | "scripts": { 23 | "test": "echo \"Error: no test specified\" && exit 1", 24 | "start": "react-server-cli" 25 | }, 26 | "author": "TonyHYK", 27 | "license": "ISC" 28 | } 29 | -------------------------------------------------------------------------------- /pages/ClientTransition.js: -------------------------------------------------------------------------------- 1 | import {Link} from "react-server"; 2 | 3 | class ClientTransition { 4 | getElements() { 5 | const request = this.getRequest(); 6 | const {val} = request.getRouteParams(); 7 | return ; 8 | } 9 | } 10 | 11 | function TestComp({val}) { 12 | return Current: {val} 13 | } 14 | 15 | export default ClientTransition; 16 | -------------------------------------------------------------------------------- /pages/ServerClient.js: -------------------------------------------------------------------------------- 1 | import {Component} from "react"; 2 | 3 | class ServerClient { 4 | getElements() { 5 | return ; 6 | } 7 | } 8 | 9 | class ChangeOnClient extends Component { 10 | constructor(props) { 11 | super(props); 12 | this.state = {env: "server"}; 13 | } 14 | 15 | render() { 16 | return
{this.state.env}
17 | } 18 | 19 | componentDidMount() { 20 | this.setState({env: "client"}); 21 | } 22 | } 23 | 24 | export default ServerClient; 25 | -------------------------------------------------------------------------------- /pages/Streaming.js: -------------------------------------------------------------------------------- 1 | import Q from "q"; 2 | 3 | class DemoPage { 4 | getElements() { 5 | return [1000,2000,3000,4000,5000].map((time) => { 6 | return DelayedElement(time); 7 | }); 8 | } 9 | } 10 | 11 | function DelayedElement(time) { 12 | const deferred = Q.defer(); 13 | setTimeout(() => { 14 | deferred.resolve(); 15 | }, time); 16 | return deferred.promise; 17 | } 18 | 19 | function TimedComp({time}) { 20 | return
{time}
; 21 | } 22 | 23 | export default DemoPage; 24 | -------------------------------------------------------------------------------- /pages/index.js: -------------------------------------------------------------------------------- 1 | const testPages = [ 2 | {name: "Multiple delayed root elements", url: "/streaming"}, 3 | {name: "Client navigation", url: "/clientTransition/0"}, 4 | {name: "Component change on client", url: "/serverClient"}, 5 | ]; 6 | 7 | export default class Index { 8 | getElements() { 9 | return
10 |

Welcome to react-server demo

11 |
    12 | {testPages.map((page, i) => { 13 | return
  • {page.name}
  • 14 | })} 15 |
16 |
17 | } 18 | 19 | // to make things look _somewhat_ pretty 20 | getLinkTags() { 21 | return [{ 22 | rel: "stylesheet", 23 | href: "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css", 24 | }] 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /routes.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // these will be applied to every page in the site. 3 | middleware: [], 4 | 5 | // this maps URLs to modules that export a Page class. 6 | routes: { 7 | Index: { 8 | path: ["/"], 9 | page: "./pages/index", 10 | }, 11 | Streaming: { 12 | path: ["/streaming"], 13 | page: "./pages/Streaming", 14 | }, 15 | ClientTransition: { 16 | path: ["/clientTransition/:val"], 17 | page: "./pages/ClientTransition", 18 | }, 19 | ServerClient: { 20 | path: ["/serverClient"], 21 | page: "./pages/ServerClient", 22 | }, 23 | }, 24 | }; 25 | --------------------------------------------------------------------------------