Skip to content
This repository was archived by the owner on Jan 22, 2020. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,12 @@ The options object can contain properties from [react router's create configurat

Additionally, it can contain the following **optional** properties,

- `routesFilePath`: <String> - path for the file that contains the react router routes.
- `routesFilePath`: \<String> - path for the file that contains the react router routes.
react-engine uses this behind the scenes to reload the routes file in
cases where [express's app property](http://expressjs.com/api.html#app.set) `view cache` is false, this way you don't need to restart the server every time a change is made in the view files or routes file.
- `renderOptionsKeysToFilter`: <Array> - an array of keys that need to be filtered out from the data object that gets fed into the react component for rendering. [more info](#data-for-component-rendering)
- `performanceCollector`: <Function> - to collects [perf stats](#performance-profiling)
- `renderOptionsKeysToFilter`: \<Array> - an array of keys that need to be filtered out from the data object that gets fed into the react component for rendering. [more info](#data-for-component-rendering)
- `performanceCollector`: \<Function> - to collects [perf stats](#performance-profiling)
- `page404`: \<Function> - This option allows you to define a custom 404 page when a URL is not matched in your routes. If left undeclared, a default 404 page, interally provided by this library, is rendered.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better to call page404 as a ReactComponent than Function :)
typo - interally -> internally


###### Rendering views on server side
```js
Expand Down
11 changes: 2 additions & 9 deletions examples/edge/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ var app = express();
// create the view engine with `react-engine`
var engine = renderer.server.create({
routes: require(path.join(__dirname, '/public/routes.jsx')),
routesFilePath: path.join(__dirname, '/public/routes.jsx')
routesFilePath: path.join(__dirname, '/public/routes.jsx'),
page404: require(path.join(__dirname, '/public/views/404.jsx'))
});

// set the engine
Expand Down Expand Up @@ -69,14 +70,6 @@ app.use('/', function(req, res, next) {
next();
});

// 404 template
app.use(function(req, res) {
res.render('404', {
title: 'React Engine Express Sample App',
url: req.url
});
});

var server = app.listen(3000, function() {

var host = server.address().address;
Expand Down
8 changes: 5 additions & 3 deletions examples/edge/public/views/account.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,11 @@ export default React.createClass({
<div id='account'>
<h1>{this.props.name}</h1>
<h6>I am a React Router rendered view</h6>
<a href='/some_unknown'>Click to go to an unhandled route</a>
<a href='/messages'>Messages</a>
<a href='/mymessages'>Redirects to /messages</a>
<ul>
<li><a href='/some_unknown'>Click to go to an unhandled route</a></li>
<li><a href='/messages'>Messages</a></li>
<li><a href='/mymessages'>Redirects to /messages</a></li>
</ul>
</div>
);
}
Expand Down
7 changes: 7 additions & 0 deletions lib/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ var TEMPLATE = ['<script id="%s" type="application/javascript">var ',
].join('');
var TEMPLATE_REDIRECT = '<html><head><meta http-equiv="refresh" content="0;URL=\'%s\'" /></head></html>';

var Default404 = require('./views/Page404');

exports.create = function create(createOptions) {

createOptions = createOptions || {};
Expand Down Expand Up @@ -72,6 +74,7 @@ exports.create = function create(createOptions) {
// remove all the files under the express's view folder from require cache.
// Helps in making changes to react views without restarting the server.
util.clearRequireCache(createOptions.routesFilePath);
util.clearRequireCache(createOptions.page404);
util.clearRequireCacheInDir(options.settings.views, options.settings['view engine']);
}

Expand Down Expand Up @@ -146,6 +149,10 @@ exports.create = function create(createOptions) {
//res.send(404, 'Not found');
} else {
debug('server.js match 404 %s', renderProps);

var component = React.createFactory(createOptions.page404 || Default404);

return done(null, renderAndDecorate(component(data), data, html));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

}
});
} else {
Expand Down
30 changes: 30 additions & 0 deletions lib/views/Page404.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
'use strict';

var React = require('react');

module.exports = React.createClass({

render: function render() {

return React.createElement(
'html',
null,
React.createElement(
'head',
null,
React.createElement('meta', {
charSet: 'utf-8'
})
),
React.createElement(
'body',
null,
React.createElement(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it will be good to let the user know which url resulted in this 404.
Example: https://github.com/krakenjs/kraken-js/blob/36df428533aea2c427063901fd33cbbedb5ac324/middleware/404.js#L26

'h1',
null,
'404 Page Not Found'
)
)
);
}
});
4 changes: 3 additions & 1 deletion test/fixtures/assertions.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
{
"PROFILE_OUTPUT": "<!DOCTYPE html><html><head><meta charset=\"utf-8\"><title>Hello, world!</title></head><body><div id=\"profile\"><h1>Joshua</h1></div><script id=\"react-engine-props\" type=\"application/javascript\">var __REACT_ENGINE__ = {\"__meta\":{\"view\":\"profile.js\",\"markupId\":\"react-engine-props\"},\"title\":\"Hello, world!\",\"name\":\"Joshua\",\"cache\":false};</script></body></html>",
"PROFILE_OUTPUT_WITH_REACT_ATTRS": "<!DOCTYPE html><html data-reactid=\".2eb4mptwtts\" data-react-checksum=\"-636849162\"><head data-reactid=\".2eb4mptwtts.0\"><meta charset=\"utf-8\" data-reactid=\".2eb4mptwtts.0.0\"/><title data-reactid=\".2eb4mptwtts.0.1\">Hello, world!</title></head><body data-reactid=\".2eb4mptwtts.1\"><div id=\"profile\" data-reactid=\".2eb4mptwtts.1.0\"><h1 data-reactid=\".2eb4mptwtts.1.0.0\">Joshua</h1></div><script id=\"react-engine-props\" type=\"application/javascript\">var __REACT_ENGINE__ = {\"__meta\":{\"view\":\"profile.js\",\"markupId\":\"react-engine-props\"},\"title\":\"Hello, world!\",\"name\":\"Joshua\",\"cache\":false};</script></body></html>",
"ACCOUNT_OUTPUT": "<!DOCTYPE html><html><head><meta charset=\"utf-8\"><title>Hello, world!</title></head><body><div id=\"account\"><h1>Joshua</h1></div><script id=\"react-engine-props\" type=\"application/javascript\">var __REACT_ENGINE__ = {\"__meta\":{\"view\":null,\"markupId\":\"react-engine-props\"},\"title\":\"Hello, world!\",\"name\":\"Joshua\",\"cache\":false};</script></body></html>"
"ACCOUNT_OUTPUT": "<!DOCTYPE html><html><head><meta charset=\"utf-8\"><title>Hello, world!</title></head><body><div id=\"account\"><h1>Joshua</h1></div><script id=\"react-engine-props\" type=\"application/javascript\">var __REACT_ENGINE__ = {\"__meta\":{\"view\":null,\"markupId\":\"react-engine-props\"},\"title\":\"Hello, world!\",\"name\":\"Joshua\",\"cache\":false};</script></body></html>",
"DEFAULT404_OUTPUT": "<!DOCTYPE html><html><head><meta charset=\"utf-8\"></head><body><h1>404 Page Not Found</h1><script id=\"react-engine-props\" type=\"application/javascript\">var __REACT_ENGINE__ = {\"__meta\":{\"view\":null,\"markupId\":\"react-engine-props\"},\"title\":\"Hello, world!\",\"name\":\"Joshua\",\"cache\":false};</script></body></html>",
"CUSTOM404_OUTPUT": "<!DOCTYPE html><html><head><meta charset=\"utf-8\"></head><body><h1><span>Custom 404 Page Not Found - Sorry</span><span>Joshua</span></h1><script id=\"react-engine-props\" type=\"application/javascript\">var __REACT_ENGINE__ = {\"__meta\":{\"view\":null,\"markupId\":\"react-engine-props\"},\"title\":\"Hello, world!\",\"name\":\"Joshua\",\"cache\":false};</script></body></html>"
}
31 changes: 31 additions & 0 deletions test/fixtures/views/page404.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
'use strict';

var React = require('react');

module.exports = React.createClass({

render: function render() {

return React.createElement(
'html',
null,
React.createElement(
'head',
null,
React.createElement('meta', {
charSet: 'utf-8'
})
),
React.createElement(
'body',
null,
React.createElement(
'h1',
null,
'Custom 404 Page Not Found - Sorry',
this.props.name
)
)
);
}
});
47 changes: 47 additions & 0 deletions test/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -297,3 +297,50 @@ test('all keys in express render `renderOptionsKeysToFilter` should be used to f
};
setup(options);
});

test('route not found and a default 404 is rendered', function(t) {

var options = {
engine: renderer.create({
routes: require(path.join(__dirname + '/fixtures/reactRoutes'))
}),
expressRoutes: function(req, res) {
res.render(req.url, DATA_MODEL);
},

onSetup: function(done) {
inject('/nonexistentpath', function(err, data) {
t.error(err);
var $ = cheerio.load(data);
$('*').removeAttr('data-reactid').removeAttr('data-react-checksum');
t.strictEqual($.html(), assertions.DEFAULT404_OUTPUT);
done(t);
});
}
};
setup(options);
});

test('route not found and a custom 404 is rendered with data', function(t) {

var options = {
engine: renderer.create({
routes: require(path.join(__dirname + '/fixtures/reactRoutes')),
page404: require(path.join(__dirname + '/fixtures/views/page404'))
}),
expressRoutes: function(req, res) {
res.render(req.url, DATA_MODEL);
},

onSetup: function(done) {
inject('/nonexistentpath', function(err, data) {
t.error(err);
var $ = cheerio.load(data);
$('*').removeAttr('data-reactid').removeAttr('data-react-checksum');
t.strictEqual($.html(), assertions.CUSTOM404_OUTPUT);
done(t);
});
}
};
setup(options);
});