Skip to content
This repository has been archived by the owner on May 17, 2019. It is now read-only.

Commit

Permalink
Render server errors in the browser in dev mode
Browse files Browse the repository at this point in the history
Currently we just display internal server error. Rendering the error in the browser should lead to a better developer UX.

Refs #108
  • Loading branch information
KevinGrandon committed Jan 8, 2018
1 parent 600099d commit e4a1b29
Show file tree
Hide file tree
Showing 10 changed files with 59 additions and 11 deletions.
3 changes: 2 additions & 1 deletion build/dev-runtime.js
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,8 @@ module.exports.DevelopmentRuntime = function({
req.pipe(proxyReq).pipe(res);
},
error => {
renderError(res, error);
res.write(renderError(error));
res.end();
}
);
});
Expand Down
14 changes: 7 additions & 7 deletions build/server-error.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,19 @@ const React = require('react');
const RedBox = require('redbox-react').RedBoxError;
const ReactDOMServer = require('react-dom/server');

function renderError(res, error) {
res.write(
'<!DOCTYPE html><html><head><title>Server error</title></head><body>'
);
function renderError(error) {
const content = [
'<!DOCTYPE html><html><head><title>Server error</title></head><body>',
];

const displayError = typeof error === 'string' ? new Error(error) : error;
const errorComponent = ReactDOMServer.renderToString(
React.createElement(RedBox, {error: displayError})
);
res.write(errorComponent);
content.push(errorComponent);

res.write('</body></html>');
res.end();
content.push('</body></html>');
return content.join('');
}

module.exports.renderError = renderError;
5 changes: 5 additions & 0 deletions entries/server-entry.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ import main from '__FRAMEWORK_SHARED_ENTRY__';
import CompilationMetaDataFactory from '../plugins/compilation-metadata-plugin';
import AssetsFactory from '../plugins/assets-plugin';
import ContextFactory from '../plugins/context-plugin';
import ServerErrorFactory from '../plugins/server-error-plugin';

const CompilationMetaData = CompilationMetaDataFactory();
const Assets = AssetsFactory();
const Context = ContextFactory();
const ServerErrorHandling = ServerErrorFactory();

/*
Webpack has a configuration option called `publicPath`, which determines the
Expand Down Expand Up @@ -59,6 +61,9 @@ export async function start({port}) {
async function reload() {
const app = await initialize();
app.plugins = [Assets, Context].concat(app.plugins);
if (__DEV__) {
app.plugins.unshift(ServerErrorHandling);
}
state.serve = app.callback();
state.app = app;
}
Expand Down
14 changes: 14 additions & 0 deletions plugins/server-error-plugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/* eslint-env node */

const renderError = require('../build/server-error').renderError;

module.exports = function() {
return async function middleware(ctx, next) {
try {
await next();
} catch (err) {
ctx.status = err.statusCode || err.status || 500;
ctx.body = renderError(err);
}
};
};
12 changes: 10 additions & 2 deletions test/cli/dev.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,18 @@ test('`fusion dev` works with assets with cdnUrl', async t => {
test('`fusion dev` top-level error', async t => {
const dir = path.resolve(
__dirname,
'../fixtures/server-error-route-component'
'../fixtures/server-startup-error'
);
const {res, proc} = await dev(`--dir=${dir}`);
t.ok(res.includes('top-level-route-error'));
t.ok(res.includes('server-startup-error'));
proc.kill();
t.end();
});

test('`fusion dev` server render error', async t => {
const dir = path.resolve(__dirname, '../fixtures/server-render-error');
const {res, proc} = await dev(`--dir=${dir}`);
t.ok(res.includes('server-render-error'));
proc.kill();
t.end();
});
1 change: 0 additions & 1 deletion test/fixtures/server-error-route-component/src/home.js

This file was deleted.

7 changes: 7 additions & 0 deletions test/fixtures/server-render-error/src/home.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import React from 'react';

const Home = () => {
throw new Error('server-render-error');
return null;
};
export default Home;
13 changes: 13 additions & 0 deletions test/fixtures/server-render-error/src/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React from 'react';
import App from 'fusion-react';
import Router, {Route, Switch} from 'fusion-plugin-react-router';

import Home from './home.js';

export default () => {
const app = new App(<Switch>
<Route exact path="/" component={Home} />
</Switch>);
app.plugin(Router, {});
return app;
};
1 change: 1 addition & 0 deletions test/fixtures/server-startup-error/src/home.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
throw new Error('server-startup-error');

0 comments on commit e4a1b29

Please sign in to comment.