diff --git a/README.md b/README.md index bc70ba3..cb23498 100644 --- a/README.md +++ b/README.md @@ -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`: - path for the file that contains the react router routes. +- `routesFilePath`: \ - 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`: - 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`: - to collects [perf stats](#performance-profiling) +- `renderOptionsKeysToFilter`: \ - 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`: \ - to collects [perf stats](#performance-profiling) +- `page404`: \ - 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. ###### Rendering views on server side ```js diff --git a/examples/edge/index.js b/examples/edge/index.js index a3d6034..d28ccf0 100644 --- a/examples/edge/index.js +++ b/examples/edge/index.js @@ -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 @@ -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; diff --git a/examples/edge/public/views/account.jsx b/examples/edge/public/views/account.jsx index 333448f..d4b0744 100644 --- a/examples/edge/public/views/account.jsx +++ b/examples/edge/public/views/account.jsx @@ -25,9 +25,11 @@ export default React.createClass({ ); } diff --git a/lib/server.js b/lib/server.js index d84c8d7..2e334c9 100644 --- a/lib/server.js +++ b/lib/server.js @@ -41,6 +41,8 @@ var TEMPLATE = ['", "PROFILE_OUTPUT_WITH_REACT_ATTRS": "Hello, world!

Joshua

", - "ACCOUNT_OUTPUT": "Hello, world!

Joshua

" + "ACCOUNT_OUTPUT": "Hello, world!

Joshua

", + "DEFAULT404_OUTPUT": "

404 Page Not Found

", + "CUSTOM404_OUTPUT": "

Custom 404 Page Not Found - SorryJoshua

" } diff --git a/test/fixtures/views/page404.js b/test/fixtures/views/page404.js new file mode 100644 index 0000000..0edd9c2 --- /dev/null +++ b/test/fixtures/views/page404.js @@ -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 + ) + ) + ); + } +}); diff --git a/test/server.js b/test/server.js index 090a52f..68e02e1 100644 --- a/test/server.js +++ b/test/server.js @@ -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); +});