diff --git a/connect.js b/connect.js index c1d2f6f..9f45c0a 100644 --- a/connect.js +++ b/connect.js @@ -6,7 +6,7 @@ const glob = require('glob'); const rimraf = require('rimraf'); const mkdirp = require('mkdirp'); const create_routes = require('./utils/create_routes.js'); -const create_templates = require('./utils/create_templates.js'); +const templates = require('./lib/templates.js'); const create_app = require('./utils/create_app.js'); const create_webpack_compiler = require('./utils/create_webpack_compiler.js'); const escape_html = require('escape-html'); @@ -32,15 +32,13 @@ module.exports = function connect(opts) { dev ); - const templates = create_templates(); - return async function(req, res, next) { const url = req.url.replace(/\?.+/, ''); - if (url === '/service-worker.js' || url.startsWith('/client/')) { + if (url === '/service-worker.js' || url === '/index.html' || url.startsWith('/client/')) { await webpack_compiler.ready; res.set({ - 'Content-Type': 'application/javascript' + 'Content-Type': url === '/index.html' ? 'text/html' : 'application/javascript' }); fs.createReadStream(`${dest}${url}`).pipe(res); return; diff --git a/lib/templates.js b/lib/templates.js new file mode 100644 index 0000000..5f5e140 --- /dev/null +++ b/lib/templates.js @@ -0,0 +1,43 @@ +const fs = require('fs'); +const glob = require('glob'); + +const templates = glob.sync('*.html', { cwd: 'templates' }) + .map(file => { + const template = fs.readFileSync(`templates/${file}`, 'utf-8'); + const status = file.replace('.html', '').toLowerCase(); + + if (!/^[0-9x]{3}$/.test(status)) { + throw new Error(`Bad template — should be a valid status code like 404.html, or a wildcard like 2xx.html`); + } + + const specificity = ( + (status[0] === 'x' ? 0 : 4) + + (status[1] === 'x' ? 0 : 2) + + (status[2] === 'x' ? 0 : 1) + ); + + const pattern = new RegExp(`^${status.split('').map(d => d === 'x' ? '\\d' : d).join('')}$`); + + return { + test: status => pattern.test(status), + specificity, + render(data) { + return template.replace(/%sapper\.(\w+)%/g, (match, key) => { + return key in data ? data[key] : ''; + }); + } + } + }) + .sort((a, b) => b.specificity - a.specificity); + +exports.render = (status, data) => { + const template = templates.find(template => template.test(status)); + if (template) return template.render(data); + + return `Missing template for status code ${status}`; +}; + +exports.onchange = fn => { + // TODO in dev mode, keep this updated, and allow + // webpack compiler etc to hook into it +}; \ No newline at end of file diff --git a/utils/create_templates.js b/utils/create_templates.js deleted file mode 100644 index aecd177..0000000 --- a/utils/create_templates.js +++ /dev/null @@ -1,42 +0,0 @@ -const fs = require('fs'); -const glob = require('glob'); - -module.exports = function create_templates() { - const templates = glob.sync('*.html', { cwd: 'templates' }) - .map(file => { - const template = fs.readFileSync(`templates/${file}`, 'utf-8'); - const status = file.replace('.html', '').toLowerCase(); - - if (!/^[0-9x]{3}$/.test(status)) { - throw new Error(`Bad template — should be a valid status code like 404.html, or a wildcard like 2xx.html`); - } - - const specificity = ( - (status[0] === 'x' ? 0 : 4) + - (status[1] === 'x' ? 0 : 2) + - (status[2] === 'x' ? 0 : 1) - ); - - const pattern = new RegExp(`^${status.split('').map(d => d === 'x' ? '\\d' : d).join('')}$`); - - return { - test: status => pattern.test(status), - specificity, - render(data) { - return template.replace(/%sapper\.(\w+)%/g, (match, key) => { - return key in data ? data[key] : ''; - }); - } - } - }) - .sort((a, b) => b.specificity - a.specificity); - - return { - render: (status, data) => { - const template = templates.find(template => template.test(status)); - if (template) return template.render(data); - - return `Missing template for status code ${status}`; - } - }; -}; \ No newline at end of file diff --git a/utils/create_webpack_compiler.js b/utils/create_webpack_compiler.js index 9e7d8a8..a033d5c 100644 --- a/utils/create_webpack_compiler.js +++ b/utils/create_webpack_compiler.js @@ -2,6 +2,7 @@ const fs = require('fs'); const path = require('path'); const glob = require('glob'); const webpack = require('webpack'); +const templates = require('../lib/templates.js'); module.exports = function create_webpack_compiler(dest, routes, dev) { const compiler = {}; @@ -65,12 +66,29 @@ module.exports = function create_webpack_compiler(dest, routes, dev) { ]).then(() => { const assets = glob.sync('**', { cwd: 'assets' }); + const route_code = `[${ + routes + .filter(route => route.type === 'page') + .map(route => `{ pattern: ${route.pattern} }`) + .join(', ') + }]`; + const service_worker = fs.readFileSync('templates/service-worker.js', 'utf-8') .replace('__timestamp__', Date.now()) .replace('__assets__', JSON.stringify(assets)) - .replace('__javascript__', JSON.stringify(compiler.assets)); + .replace('__shell__', JSON.stringify(compiler.assets.concat('/index.html'))) + .replace('__routes__', route_code); fs.writeFileSync(path.resolve(dest, 'service-worker.js'), service_worker); + + const shell = templates.render(200, { + styles: '', + head: '', + html: '', + main: compiler.client_main + }); + + fs.writeFileSync(path.resolve(dest, 'index.html'), shell); }); compiler.get_chunk = async id => {