mirror of
https://github.com/kevin-DL/sapper.git
synced 2026-01-21 14:55:04 +00:00
simplify rendering of error pages
This commit is contained in:
@@ -162,8 +162,13 @@ function get_route_handler(App: Component, routes: RouteObject[], store_getter:
|
|||||||
? () => fs.readFileSync(`${locations.app()}/template.html`, 'utf-8')
|
? () => fs.readFileSync(`${locations.app()}/template.html`, 'utf-8')
|
||||||
: (str => () => str)(fs.readFileSync(`${locations.dest()}/template.html`, 'utf-8'));
|
: (str => () => str)(fs.readFileSync(`${locations.dest()}/template.html`, 'utf-8'));
|
||||||
|
|
||||||
function handle_route(route: RouteObject, req: Req, res: ServerResponse) {
|
const not_found_route = routes.find((route: RouteObject) => route.error === '4xx');
|
||||||
req.params = route.params(route.pattern.exec(req.path));
|
const error_route = routes.find((route: RouteObject) => route.error === '5xx');
|
||||||
|
|
||||||
|
function handle_route(route: RouteObject, req: Req, res: ServerResponse, status = 200, error: Error | string = null) {
|
||||||
|
req.params = error
|
||||||
|
? {}
|
||||||
|
: route.params(route.pattern.exec(req.path));
|
||||||
|
|
||||||
const handlers = route.handlers[Symbol.iterator]();
|
const handlers = route.handlers[Symbol.iterator]();
|
||||||
|
|
||||||
@@ -174,7 +179,14 @@ function get_route_handler(App: Component, routes: RouteObject[], store_getter:
|
|||||||
const { value: handler, done } = handlers.next();
|
const { value: handler, done } = handlers.next();
|
||||||
|
|
||||||
if (done) {
|
if (done) {
|
||||||
handle_error(req, res, 404, 'Not found');
|
if (route.error) {
|
||||||
|
// there was an error rendering the error page!
|
||||||
|
res.statusCode = status;
|
||||||
|
res.end(error instanceof Error ? error.message : error);
|
||||||
|
} else {
|
||||||
|
handle_route(not_found_route, req, res, 404, 'Not found');
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,7 +198,7 @@ function get_route_handler(App: Component, routes: RouteObject[], store_getter:
|
|||||||
// preload main.js and current route
|
// preload main.js and current route
|
||||||
// TODO detect other stuff we can preload? images, CSS, fonts?
|
// TODO detect other stuff we can preload? images, CSS, fonts?
|
||||||
const link = []
|
const link = []
|
||||||
.concat(chunks.main, chunks[route.id])
|
.concat(chunks.main, chunks[route.id] || chunks[`_${route.error}`]) // TODO this is gross
|
||||||
.filter(file => !file.match(/\.map$/))
|
.filter(file => !file.match(/\.map$/))
|
||||||
.map(file => `<${req.baseUrl}/client/${file}>;rel="preload";as="script"`)
|
.map(file => `<${req.baseUrl}/client/${file}>;rel="preload";as="script"`)
|
||||||
.join(', ');
|
.join(', ');
|
||||||
@@ -197,7 +209,7 @@ function get_route_handler(App: Component, routes: RouteObject[], store_getter:
|
|||||||
const props = { params: req.params, query: req.query, path: req.path };
|
const props = { params: req.params, query: req.query, path: req.path };
|
||||||
|
|
||||||
let redirect: { statusCode: number, location: string };
|
let redirect: { statusCode: number, location: string };
|
||||||
let error: { statusCode: number, message: Error | string };
|
let preload_error: { statusCode: number, message: Error | string };
|
||||||
|
|
||||||
Promise.resolve(
|
Promise.resolve(
|
||||||
mod.preload ? mod.preload.call({
|
mod.preload ? mod.preload.call({
|
||||||
@@ -205,7 +217,7 @@ function get_route_handler(App: Component, routes: RouteObject[], store_getter:
|
|||||||
redirect = { statusCode, location };
|
redirect = { statusCode, location };
|
||||||
},
|
},
|
||||||
error: (statusCode: number, message: Error | string) => {
|
error: (statusCode: number, message: Error | string) => {
|
||||||
error = { statusCode, message };
|
preload_error = { statusCode, message };
|
||||||
},
|
},
|
||||||
fetch: (url: string, opts?: any) => {
|
fetch: (url: string, opts?: any) => {
|
||||||
const parsed = new URL(url, `http://127.0.0.1:${process.env.PORT}${req.baseUrl ? req.baseUrl + '/' :''}`);
|
const parsed = new URL(url, `http://127.0.0.1:${process.env.PORT}${req.baseUrl ? req.baseUrl + '/' :''}`);
|
||||||
@@ -245,7 +257,7 @@ function get_route_handler(App: Component, routes: RouteObject[], store_getter:
|
|||||||
store
|
store
|
||||||
}, req) : {}
|
}, req) : {}
|
||||||
).catch(err => {
|
).catch(err => {
|
||||||
error = { statusCode: 500, message: err };
|
preload_error = { statusCode: 500, message: err };
|
||||||
}).then(preloaded => {
|
}).then(preloaded => {
|
||||||
if (redirect) {
|
if (redirect) {
|
||||||
res.statusCode = redirect.statusCode;
|
res.statusCode = redirect.statusCode;
|
||||||
@@ -255,8 +267,8 @@ function get_route_handler(App: Component, routes: RouteObject[], store_getter:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error) {
|
if (preload_error) {
|
||||||
handle_error(req, res, error.statusCode, error.message);
|
handle_route(error_route, req, res, preload_error.statusCode, preload_error.message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -370,84 +382,19 @@ function get_route_handler(App: Component, routes: RouteObject[], store_getter:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
handle_error(req, res, 500, error);
|
handle_route(error_route, req, res, 500, error || 'Internal server error');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
next();
|
next();
|
||||||
}
|
}
|
||||||
|
|
||||||
const not_found_route = routes.find((route: RouteObject) => route.error === '4xx');
|
|
||||||
const error_route = routes.find((route: RouteObject) => route.error === '5xx');
|
|
||||||
|
|
||||||
function handle_error(req: Req, res: ServerResponse, statusCode: number, message: Error | string) {
|
|
||||||
res.statusCode = statusCode;
|
|
||||||
res.setHeader('Content-Type', 'text/html');
|
|
||||||
|
|
||||||
const error = message instanceof Error ? message : new Error(message);
|
|
||||||
|
|
||||||
const not_found = statusCode >= 400 && statusCode < 500;
|
|
||||||
|
|
||||||
const route = not_found
|
|
||||||
? not_found_route
|
|
||||||
: error_route;
|
|
||||||
|
|
||||||
function render_page({ head, css, html }) {
|
|
||||||
const page = template()
|
|
||||||
.replace('%sapper.base%', `<base href="${req.baseUrl}/">`)
|
|
||||||
.replace('%sapper.scripts%', `<script>__SAPPER__={baseUrl: "${req.baseUrl}"}</script><script src='${req.baseUrl}/client/${get_chunks().main}'></script>`)
|
|
||||||
.replace('%sapper.html%', html)
|
|
||||||
.replace('%sapper.head%', `<noscript id='sapper-head-start'></noscript>${head}<noscript id='sapper-head-end'></noscript>`)
|
|
||||||
.replace('%sapper.styles%', (css && css.code ? `<style>${css.code}</style>` : ''));
|
|
||||||
|
|
||||||
res.end(page);
|
|
||||||
}
|
|
||||||
|
|
||||||
function handle_notfound() {
|
|
||||||
const title: string = not_found
|
|
||||||
? 'Not found'
|
|
||||||
: `Internal server error: ${error.message}`;
|
|
||||||
|
|
||||||
render_page({ head: '', css: null, html: title });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (route) {
|
|
||||||
const handlers = route.handlers[Symbol.iterator]();
|
|
||||||
|
|
||||||
function next() {
|
|
||||||
const { value: handler, done } = handlers.next();
|
|
||||||
|
|
||||||
if (done) {
|
|
||||||
handle_notfound();
|
|
||||||
} else if (handler.type === 'page') {
|
|
||||||
render_page(handler.module.render({
|
|
||||||
status: statusCode,
|
|
||||||
error
|
|
||||||
}, {
|
|
||||||
store: store_getter && store_getter(req)
|
|
||||||
}));
|
|
||||||
} else {
|
|
||||||
const handle_method = mod[method_export];
|
|
||||||
if (handle_method) {
|
|
||||||
handle_method(req, res, next);
|
|
||||||
} else {
|
|
||||||
next();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
next();
|
|
||||||
} else {
|
|
||||||
handle_notfound();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return function find_route(req: Req, res: ServerResponse) {
|
return function find_route(req: Req, res: ServerResponse) {
|
||||||
for (const route of routes) {
|
for (const route of routes) {
|
||||||
if (!route.error && route.pattern.test(req.path)) return handle_route(route, req, res);
|
if (!route.error && route.pattern.test(req.path)) return handle_route(route, req, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
handle_error(req, res, 404, 'Not found');
|
handle_route(not_found_route, req, res, 404, 'Not found');
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user