stream responses - fixes #19

This commit is contained in:
Rich Harris
2017-12-20 18:39:39 -05:00
parent 45e845ee92
commit a48afb77d3
2 changed files with 56 additions and 11 deletions

View File

@@ -140,19 +140,31 @@ function get_route_handler(fn) {
res.set('Link', `<${client.main_file}>;rel="preload";as="script", <${client.routes[route.id]}>;rel="preload";as="script"`); res.set('Link', `<${client.main_file}>;rel="preload";as="script", <${client.routes[route.id]}>;rel="preload";as="script"`);
let data = { params: req.params, query: req.query }; let data = { params: req.params, query: req.query };
if (mod.preload) data = Object.assign(data, await mod.preload(data));
const { html, head, css } = mod.render(data); if (mod.preload) {
const promise = Promise.resolve(mod.preload(data)).then(preloaded => {
Object.assign(data, preloaded);
return mod.render(data);
});
const page = templates.render(200, { templates.stream(res, 200, {
main: client.main_file, main: client.main_file,
html, html: promise.then(rendered => rendered.html),
head: `<noscript id='sapper-head-start'></noscript>${head}<noscript id='sapper-head-end'></noscript>`, head: promise.then(({ head }) => `<noscript id='sapper-head-start'></noscript>${head}<noscript id='sapper-head-end'></noscript>`),
styles: (css && css.code ? `<style>${css.code}</style>` : '') styles: promise.then(({ css }) => (css && css.code ? `<style>${css.code}</style>` : ''))
}); });
} else {
const { html, head, css } = mod.render(data);
res.status(200); const page = templates.render(200, {
res.end(page); main: client.main_file,
html,
head: `<noscript id='sapper-head-start'></noscript>${head}<noscript id='sapper-head-end'></noscript>`,
styles: (css && css.code ? `<style>${css.code}</style>` : '')
});
res.end(page);
}
} }
else { else {

View File

@@ -26,10 +26,36 @@ function create_templates() {
return { return {
test: status => pattern.test(status), test: status => pattern.test(status),
specificity, specificity,
render(data) { render: data => {
return template.replace(/%sapper\.(\w+)%/g, (match, key) => { return template.replace(/%sapper\.(\w+)%/g, (match, key) => {
return key in data ? data[key] : ''; return key in data ? data[key] : '';
}); });
},
stream: async (res, data) => {
let i = 0;
do {
const start = template.indexOf('%sapper', i);
if (start === -1) {
res.end(template.slice(start));
return;
}
res.write(template.slice(i, start));
const end = template.indexOf('%', start + 1);
if (end === -1) {
throw new Error(`Bad template`); // TODO validate ahead of time
}
const tag = template.slice(start + 1, end);
const match = /sapper\.(\w+)/.exec(tag);
if (!match || !(match[1] in data)) throw new Error(`Bad template`); // TODO ditto
res.write(await data[match[1]]);
i = end + 1;
} while (i < template.length);
} }
} }
}) })
@@ -52,5 +78,12 @@ exports.render = (status, data) => {
const template = templates.find(template => template.test(status)); const template = templates.find(template => template.test(status));
if (template) return template.render(data); if (template) return template.render(data);
return `Missing template for status code ${status}`;
};
exports.stream = (res, status, data) => {
const template = templates.find(template => template.test(status));
if (template) return template.stream(res, data);
return `Missing template for status code ${status}`; return `Missing template for status code ${status}`;
}; };