├── .npmignore ├── .gitignore ├── examples ├── dynamic │ ├── .gitignore │ ├── .babelrc │ ├── public │ │ └── favicon.ico │ ├── views │ │ ├── main.js │ │ ├── Content.js │ │ └── Html.js │ ├── package.json │ ├── app.js │ └── readme.md └── simple │ ├── routes │ ├── user.js │ └── index.js │ ├── public │ └── stylesheets │ │ └── style.css │ ├── package.json │ ├── views │ ├── index.jsx │ └── layout.jsx │ └── app.js ├── .travis.yml ├── prettier.config.js ├── .eslintrc.js ├── test ├── es6-component.jsx ├── es5-component.jsx ├── es6-flow-component.jsx └── index.js ├── CONTRIBUTING.md ├── LICENSE ├── package.json ├── PATENTS ├── CHANGELOG.md ├── index.js ├── README.md └── yarn.lock /.npmignore: -------------------------------------------------------------------------------- 1 | examples 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .idea/ -------------------------------------------------------------------------------- /examples/dynamic/.gitignore: -------------------------------------------------------------------------------- 1 | public/main.js 2 | -------------------------------------------------------------------------------- /examples/dynamic/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "@babel/preset-react", 4 | "@babel/preset-env" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | cache: yarn 3 | node_js: 4 | - 6 5 | - 8 6 | script: 7 | - yarn run test-on-travis 8 | -------------------------------------------------------------------------------- /examples/dynamic/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reactjs/express-react-views/HEAD/examples/dynamic/public/favicon.ico -------------------------------------------------------------------------------- /examples/simple/routes/user.js: -------------------------------------------------------------------------------- 1 | /* 2 | * GET users listing. 3 | */ 4 | 5 | exports.list = function(req, res) { 6 | res.send('respond with a resource'); 7 | }; 8 | -------------------------------------------------------------------------------- /examples/simple/public/stylesheets/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding: 50px; 3 | font: 14px "Lucida Grande", Helvetica, Arial, sans-serif; 4 | } 5 | 6 | a { 7 | color: #00B7FF; 8 | } -------------------------------------------------------------------------------- /examples/simple/routes/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * GET home page. 3 | */ 4 | 5 | exports.index = function(req, res) { 6 | res.render('index', {title: 'Express', foo: {bar: 'baz'}}); 7 | }; 8 | -------------------------------------------------------------------------------- /prettier.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | printWidth: 80, 3 | semi: true, 4 | bracketSpacing: false, 5 | jsxBracketSameLine: true, 6 | singleQuote: true, 7 | trailingComma: 'es5', 8 | }; 9 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parser: 'babel-eslint', 3 | parserOptions: { 4 | ecmaVersion: 6, 5 | ecmaFeatures: { 6 | jsx: true, 7 | }, 8 | }, 9 | plugins: ['prettier'], 10 | rules: { 11 | 'prettier/prettier': 'error', 12 | }, 13 | }; 14 | -------------------------------------------------------------------------------- /examples/dynamic/views/main.js: -------------------------------------------------------------------------------- 1 | var React = require('react'); 2 | var ReactDOM = require('react-dom'); 3 | var Content = require('./Content'); 4 | 5 | module.exports = function(data, containerId) { 6 | var container = document.getElementById(containerId || 'content'); 7 | ReactDOM.render(, container); 8 | }; 9 | -------------------------------------------------------------------------------- /examples/simple/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "application-name", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "start": "node app.js" 7 | }, 8 | "dependencies": { 9 | "errorhandler": "^1.5.0", 10 | "express": "^4.16.1", 11 | "express-react-views": "file:../../", 12 | "morgan": "^1.9.0", 13 | "prop-types": "^15.6.0", 14 | "react": "^16.0.0", 15 | "react-dom": "^16.0.0" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /test/es6-component.jsx: -------------------------------------------------------------------------------- 1 | const React = require('react'); 2 | const PropTypes = require('prop-types'); 3 | 4 | function countTo(n) { 5 | var a = []; 6 | for (var i = 0; i < n; i++) { 7 | a.push(i + 1); 8 | } 9 | return a.join(', '); 10 | } 11 | 12 | class Index extends React.Component { 13 | render() { 14 | return ( 15 |
16 |

{this.props.title}

17 |

Welcome to {this.props.title}

18 |

19 | I can count to 10: 20 | {countTo(10)} 21 |

22 |
23 | ); 24 | } 25 | } 26 | 27 | Index.propTypes = { 28 | title: PropTypes.string, 29 | }; 30 | 31 | module.exports = Index; 32 | -------------------------------------------------------------------------------- /examples/dynamic/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dynamic-views", 3 | "version": "0.1.0", 4 | "description": "Example of creating a dynamic app using express-react-views", 5 | "author": "Chris Johnson ", 6 | "private": true, 7 | "scripts": { 8 | "start": 9 | "browserify -t babelify views/main.js --standalone main -o public/main.js && node app.js" 10 | }, 11 | "dependencies": { 12 | "@babel/preset-env": "^7.0.0", 13 | "@babel/preset-react": "^7.0.0", 14 | "babelify": "^10.0.0", 15 | "browserify": "^14.3.0", 16 | "express": "^4.15.3", 17 | "express-react-views": "file:../../", 18 | "react": "^16.0.0", 19 | "react-dom": "^16.0.0" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /test/es5-component.jsx: -------------------------------------------------------------------------------- 1 | var React = require('react'); 2 | var PropTypes = require('prop-types'); 3 | var createClass = require('create-react-class'); 4 | 5 | function countTo(n) { 6 | var a = []; 7 | for (var i = 0; i < n; i++) { 8 | a.push(i + 1); 9 | } 10 | return a.join(', '); 11 | } 12 | 13 | var Index = createClass({ 14 | propTypes: { 15 | title: PropTypes.string, 16 | }, 17 | 18 | render: function() { 19 | return ( 20 |
21 |

{this.props.title}

22 |

Welcome to {this.props.title}

23 |

24 | I can count to 10: 25 | {countTo(10)} 26 |

27 |
28 | ); 29 | }, 30 | }); 31 | 32 | module.exports = Index; 33 | -------------------------------------------------------------------------------- /examples/dynamic/app.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var reactViews = require('express-react-views'); 3 | 4 | var app = express(); 5 | 6 | app.set('view engine', 'js'); 7 | app.engine('js', reactViews.createEngine()); 8 | 9 | app.use(express.static(__dirname + '/public')); 10 | 11 | app.get('/', function(req, res) { 12 | var initialState = { 13 | items: [ 14 | 'document your code', 15 | 'drop the kids off at the pool', 16 | '', 17 | ], 18 | text: '', 19 | }; 20 | res.render('Html', {data: initialState}); 21 | }); 22 | 23 | var port = process.env.PORT || 3000; 24 | app.listen(port, function() { 25 | console.log('Dynamic react example listening on port ' + port); 26 | }); 27 | -------------------------------------------------------------------------------- /examples/simple/views/index.jsx: -------------------------------------------------------------------------------- 1 | var React = require('react'); 2 | var PropTypes = require('prop-types'); 3 | var Layout = require('./layout'); 4 | 5 | // Contrived example to show how one might use Flow type annotations 6 | function countTo(n: number): string { 7 | var a = []; 8 | for (var i = 0; i < n; i++) { 9 | a.push(i + 1); 10 | } 11 | return a.join(', '); 12 | } 13 | 14 | function Index(props) { 15 | return ( 16 | 17 |

{props.title}

18 |

Welcome to {props.title}

19 |

20 | I can count to 10: 21 | {countTo(10)} 22 |

23 |
24 | ); 25 | } 26 | 27 | Index.propTypes = { 28 | title: PropTypes.string, 29 | }; 30 | 31 | module.exports = Index; 32 | -------------------------------------------------------------------------------- /test/es6-flow-component.jsx: -------------------------------------------------------------------------------- 1 | const React = require('react'); 2 | const PropTypes = require('prop-types'); 3 | 4 | // Contrived example to show how one might use Flow type annotations 5 | function countTo(n: number): string { 6 | var a = []; 7 | for (var i = 0; i < n; i++) { 8 | a.push(i + 1); 9 | } 10 | return a.join(', '); 11 | } 12 | 13 | class Index extends React.Component { 14 | render() { 15 | return ( 16 |
17 |

{this.props.title}

18 |

Welcome to {this.props.title}

19 |

20 | I can count to 10: 21 | {countTo(10)} 22 |

23 |
24 | ); 25 | } 26 | } 27 | 28 | Index.propTypes = { 29 | title: PropTypes.string, 30 | }; 31 | 32 | module.exports = Index; 33 | -------------------------------------------------------------------------------- /examples/simple/views/layout.jsx: -------------------------------------------------------------------------------- 1 | var React = require('react'); 2 | var PropTypes = require('prop-types'); 3 | 4 | function Layout(props) { 5 | return ( 6 | 7 | 8 | {props.title} 9 | 10 | ", 22 | * the script tag would terminate prematurely. 23 | * And two bad things would happen. 24 | * 25 | * 1. The client-side react application would not work. 26 | * 2. A second script tag could then run arbitrary javascript. 27 | * 28 | * The former sucks a little but the latter sucks a lot. 29 | * It would pwn you, game over, the site is no longer yours. 30 | * There are three ways to thwart this scenario and you should do all of them: 31 | * 32 | * 1. Scrub input from users. 33 | * Don't even let them enter data that is known to be potentially harmful. 34 | * 2. Use a templating library that renders text by default. 35 | * React does this, so YES! 36 | * 3. Whenever you have to write raw user content into the document, 37 | * block any content from breaking the current context. 38 | * 39 | * The third is what's going on with the `replace` function below. 40 | * Because we're in a script tag context, 41 | * we cannot allow the closing tag, "", in our output. 42 | * This is an old trick that breaks up the word "script" into a string contatenation. 43 | * It works here because json always uses double quotes to escape strings. 44 | * 45 | * Properly escaping user data for raw output in html is tricky business. 46 | * Whenever possible, avoid it. 47 | * If avoidance is impossible, 48 | * know what you are doing and good luck. 49 | */ 50 | var initScript = 51 | 'main(' + JSON.stringify(data).replace(/script/g, 'scr"+"ipt') + ')'; 52 | 53 | return ( 54 | 55 | 56 | 57 | 61 | 62 | 63 |
64 | 65 |