├── .gitignore ├── .jshintrc ├── package.json ├── index.js └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | node_modules/ 3 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "asi": false, 3 | "bitwise": true, 4 | "browser": false, 5 | "curly": false, 6 | "eqeqeq": true, 7 | "eqnull": true, 8 | "esnext": false, 9 | "immed": true, 10 | "latedef": false, 11 | "newcap": false, 12 | "noarg": true, 13 | "nonew": true, 14 | "quotmark": false, 15 | "undef": true, 16 | "unused": "vars", 17 | "globalstrict": true, 18 | "trailing": false, 19 | "validthis": true, 20 | "loopfunc": true, 21 | "expr": true, 22 | "globals": { 23 | "Buffer": true, 24 | "define": true, 25 | "module": true, 26 | "require": true, 27 | "exports": true, 28 | "describe": true, 29 | "xdescribe": true, 30 | "beforeEach": true, 31 | "afterEach": true, 32 | "it": true, 33 | "xit": true, 34 | "escape": true, 35 | "process": true, 36 | "__dirname": true 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "express-react-engine", 3 | "version": "1.0.0", 4 | "description": "A React's JSX rendering engine", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/magalhas/express-react-engine.git" 12 | }, 13 | "author": "José Magalhães ", 14 | "license": "ISC", 15 | "bugs": { 16 | "url": "https://github.com/magalhas/express-react-engine/issues" 17 | }, 18 | "homepage": "https://github.com/magalhas/express-react-engine", 19 | "peerDependencies": { 20 | "react": "^0.14.0 || ^15.0.0", 21 | "react-dom": "^0.14.0 || ^15.0.0" 22 | }, 23 | "dependencies": { 24 | "babel-core": "^6.0.0", 25 | "lodash.defaults": "^3.1.0" 26 | }, 27 | "devDependencies": { 28 | "react": "^15.0", 29 | "react-dom": "^15.0" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var React = require('react'); 4 | var ReactDOMServer = require('react-dom/server'); 5 | var defaults = require('lodash.defaults'); 6 | var path = require('path'); 7 | 8 | module.exports = function engineFactory (engineOptions) { 9 | engineOptions = defaults(engineOptions || {}, { 10 | extension: '.jsx', 11 | babel: {}, 12 | docType: '', 13 | staticMarkup: false 14 | }); 15 | 16 | if (engineOptions.babel) { 17 | require('babel-core/register')(engineOptions.babel); 18 | } 19 | 20 | function requireComponent(_path_){ 21 | return require(_path_) ? require(_path_).default ? require(_path_).default : require(_path_) : require(_path_); 22 | } 23 | 24 | return function renderComponent (filename, options, callback) { 25 | options = options || {}; 26 | 27 | try { 28 | var markup = engineOptions.docType; 29 | /** 30 | Depending on whether one is using ES6 import/export style modules, 31 | or Node's require/exports style Modules, we need to specify how 32 | we should reference the component from the required file 33 | */ 34 | var ReactComponent = requireComponent(filename); 35 | var instance = React.createElement( ReactComponent, options); 36 | 37 | var componentMarkup; 38 | 39 | if (engineOptions.staticMarkup) { 40 | componentMarkup = ReactDOMServer.renderToStaticMarkup(instance); 41 | } else { 42 | componentMarkup = ReactDOMServer.renderToString(instance); 43 | } 44 | 45 | if (engineOptions.wrapper) { 46 | var Wrapper = requireComponent(path.join(this.root, engineOptions.wrapper)); 47 | var wrapperInstance = React.createElement(Wrapper, { 48 | body: componentMarkup, 49 | props: options 50 | }); 51 | 52 | markup += ReactDOMServer.renderToStaticMarkup(wrapperInstance); 53 | 54 | } else { 55 | markup += componentMarkup; 56 | } 57 | 58 | if (options.settings.env === 'development') { 59 | Object.keys(require.cache).forEach(function(module) { 60 | if (new RegExp('\\' + engineOptions.extension + '$') 61 | .test(require.cache[module].filename)) { 62 | delete require.cache[module]; 63 | } 64 | }); 65 | } 66 | 67 | callback(null, markup); 68 | } catch (error) { 69 | callback(error); 70 | } 71 | }; 72 | }; 73 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # express-react-engine 2 | 3 | This is an [Express](http://expressjs.com) view engine for [React's](http://http://facebook.github.io/react/) JSX that supports server side rendering and **it is not limited to static markdown**. 4 | 5 | ## Usage 6 | 7 | ``` 8 | npm install express-react-engine react react-dom 9 | ``` 10 | 11 | Make sure you install `react` and `react-dom` as dependencies. 12 | 13 | 14 | ### Add it to your Express App 15 | 16 | ```javascript 17 | var ReactEngine = require('express-react-engine'); 18 | var app = express(); 19 | 20 | app.set('views', __dirname + '/components'); 21 | app.engine('jsx', ReactEngine()); 22 | ``` 23 | 24 | Change your *views directory* to match your *components directory* and set `jsx` as your view engine. 25 | 26 | 27 | ## Options 28 | 29 | `wrapper` is a React component that renders the Html element as well as the initial props and children Html. 30 | 31 | ### Example 32 | 33 | ``` javascript 34 | app.engine('jsx', reactEngine({wrapper: 'html.jsx'})); 35 | ``` 36 | 37 | **/components/html.jsx** 38 | ``` javascript 39 | var React = require('react'); 40 | 41 | var Html = React.createClass({ 42 | render: function () { 43 | return ( 44 | 45 | 46 | {this.props.props.title} 47 | 48 | 49 | 50 |
51 |