diff --git a/src/core/build.js b/src/core/build.js index aaf6999..89fdfe2 100644 --- a/src/core/build.js +++ b/src/core/build.js @@ -4,7 +4,7 @@ import * as fs from 'fs'; import * as path from 'path'; import mkdirp from 'mkdirp'; import rimraf from 'rimraf'; -import * as compilers from './utils/compilers.js'; +import get_compilers from './get_compilers.js'; import create_app from './utils/create_app.js'; import generate_asset_cache from './generate_asset_cache.js'; @@ -28,7 +28,7 @@ export default function build({ dest, dev, entry, src }) { } } - const { client, server } = compilers.get_compilers(); // TODO refactor + const { client, server } = get_compilers(); client.run((err, client_stats) => { handleErrors(err, client_stats); diff --git a/src/core/utils/create_routes.js b/src/core/create_routes.js similarity index 93% rename from src/core/utils/create_routes.js rename to src/core/create_routes.js index bf8d351..3a32870 100644 --- a/src/core/utils/create_routes.js +++ b/src/core/create_routes.js @@ -1,6 +1,7 @@ import * as path from 'path'; +import glob from 'glob'; -export default function create_routes(files) { +export default function create_routes({ src, files = glob.sync('**/*.+(html|js|mjs)', { cwd: src }) }) { const routes = files .map(file => { if (/(^|\/|\\)_/.test(file)) return; diff --git a/src/core/generate_asset_cache.js b/src/core/generate_asset_cache.js index ce82339..4a6ce9d 100644 --- a/src/core/generate_asset_cache.js +++ b/src/core/generate_asset_cache.js @@ -2,7 +2,7 @@ import * as fs from 'fs'; import * as path from 'path'; import glob from 'glob'; import { create_templates, render } from './templates.js'; -import * as route_manager from './route_manager.js'; +import create_routes from './create_routes.js'; function ensure_array(thing) { return Array.isArray(thing) ? thing : [thing]; // omg webpack what the HELL are you doing @@ -18,6 +18,8 @@ export default function generate_asset_cache({ src, dest, dev, client_info, serv const service_worker = generate_service_worker({ chunk_files, src }); const index = generate_index(main_file); + const routes = create_routes({ src }); // TODO rename update + if (dev) { fs.writeFileSync(path.join(dest, 'service-worker.js'), service_worker); fs.writeFileSync(path.join(dest, 'index.html'), index); @@ -34,7 +36,8 @@ export default function generate_asset_cache({ src, dest, dev, client_info, serv return lookup; }, {}), - routes: route_manager.routes.reduce((lookup, route) => { + // TODO confusing that `routes` refers to an array *and* a lookup + routes: routes.reduce((lookup, route) => { lookup[route.id] = `/client/${ensure_array(client_info.assetsByChunkName[route.id])[0]}`; return lookup; }, {}), @@ -54,10 +57,10 @@ export default function generate_asset_cache({ src, dest, dev, client_info, serv function generate_service_worker({ chunk_files, src }) { const assets = glob.sync('**', { cwd: 'assets', nodir: true }); - route_manager.update({ src }); // TODO refactor + const routes = create_routes({ src }); // TODO refactor const route_code = `[${ - route_manager.routes + routes .filter(route => route.type === 'page') .map(route => `{ pattern: ${route.pattern} }`) .join(', ') diff --git a/src/core/utils/compilers.js b/src/core/get_compilers.js similarity index 87% rename from src/core/utils/compilers.js rename to src/core/get_compilers.js index 9c10cab..c835229 100644 --- a/src/core/utils/compilers.js +++ b/src/core/get_compilers.js @@ -1,7 +1,7 @@ import * as path from 'path'; import relative from 'require-relative'; -export function get_compilers() { +export default function get_compilers() { const webpack = relative('webpack', process.cwd()); return { diff --git a/src/core/index.js b/src/core/index.js index ee0513c..b07a0b1 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -1,11 +1,10 @@ -import * as route_manager from './route_manager.js'; import * as templates from './templates.js'; -import * as compilers from './utils/compilers.js'; export { default as build } from './build.js'; export { default as export } from './export.js'; export { default as generate_asset_cache } from './generate_asset_cache.js'; +export { default as get_compilers } from './get_compilers.js'; +export { default as create_routes } from './create_routes.js'; export { default as create_app } from './utils/create_app.js'; -export { default as create_routes } from './utils/create_routes.js'; -export { compilers, route_manager, templates }; \ No newline at end of file +export { templates }; \ No newline at end of file diff --git a/src/core/route_manager.js b/src/core/route_manager.js deleted file mode 100644 index 3d559b4..0000000 --- a/src/core/route_manager.js +++ /dev/null @@ -1,12 +0,0 @@ -import glob from 'glob'; -import create_routes from './utils/create_routes.js'; - -export let routes; - -export function update({ src }) { - routes = create_routes( - glob.sync('**/*.+(html|js|mjs)', { cwd: src }) - ); - - return routes; -} \ No newline at end of file diff --git a/src/core/utils/create_app.js b/src/core/utils/create_app.js index 003aa41..26c72a5 100644 --- a/src/core/utils/create_app.js +++ b/src/core/utils/create_app.js @@ -1,16 +1,14 @@ import * as fs from 'fs'; import * as path from 'path'; -import * as route_manager from '../route_manager.js'; -import { create_templates } from '../templates.js'; +import create_routes from '../create_routes.js'; +// import { create_templates } from '../templates.js'; function posixify(file) { return file.replace(/[/\\]/g, '/'); } function create_app({ src, dev, entry }) { - // const { routes } = route_manager; - route_manager.update({ src }); - const { routes } = route_manager; + const routes = create_routes({ src }); function create_client_main() { const template = fs.readFileSync('templates/main.js', 'utf-8'); @@ -68,31 +66,31 @@ function create_app({ src, dev, entry }) { create_server_routes(); } -export function start_watching({ src }) { - const chokidar = require('chokidar'); +// export function start_watching({ src }) { +// const chokidar = require('chokidar'); - const watch = (glob, callback) => { - const watcher = chokidar.watch(glob, { - ignoreInitial: true, - persistent: false - }); +// const watch = (glob, callback) => { +// const watcher = chokidar.watch(glob, { +// ignoreInitial: true, +// persistent: false +// }); - watcher.on('add', callback); - watcher.on('change', callback); - watcher.on('unlink', callback); - }; +// watcher.on('add', callback); +// watcher.on('change', callback); +// watcher.on('unlink', callback); +// }; - watch('templates/main.js', create_app); +// watch('templates/main.js', create_app); - watch('routes/**/*.+(html|js|mjs)', () => { - route_manager.update({ src }); - create_app(); - }); +// watch('routes/**/*.+(html|js|mjs)', () => { +// route_manager.update({ src }); +// create_app(); +// }); - watch('templates/**.html', () => { - create_templates(); - // TODO reload current page? - }); -} +// watch('templates/**.html', () => { +// create_templates(); +// // TODO reload current page? +// }); +// } export default create_app; diff --git a/src/middleware/create_watcher.js b/src/middleware/create_watcher.js index 6ae8f08..c0a61e4 100644 --- a/src/middleware/create_watcher.js +++ b/src/middleware/create_watcher.js @@ -1,7 +1,7 @@ import * as fs from 'fs'; import * as path from 'path'; import chalk from 'chalk'; -import { compilers, generate_asset_cache } from 'sapper/core.js'; +import { generate_asset_cache, create_routes } from 'sapper/core.js'; import { dest } from '../config.js'; function deferred() { @@ -15,7 +15,7 @@ function deferred() { return d; } -export default function create_watcher() { +export default function create_watcher({ compilers, src, onroutes }) { const deferreds = { client: deferred(), server: deferred() @@ -59,6 +59,36 @@ export default function create_watcher() { }); } + const chokidar = require('chokidar'); + + function watch_files(pattern, callback) { + const watcher = chokidar.watch(pattern, { + ignoreInitial: true, + persistent: false + }); + + watcher.on('add', callback); + watcher.on('change', callback); + watcher.on('unlink', callback); + + // watch('templates/main.js', create_app); + + // watch('routes/**/*.+(html|js|mjs)', () => { + // route_manager.update({ src }); + // create_app(); + // }); + + // watch('templates/**.html', () => { + // create_templates(); + // // TODO reload current page? + // }); + } + + watch_files('routes/**/*.+(html|js|mjs)', () => { + const routes = create_routes({ src }); + onroutes(routes); + }); + const watcher = { ready: invalidate(), client: watch_compiler('client'), diff --git a/src/middleware/index.js b/src/middleware/index.js index aadb35e..29d7ae6 100644 --- a/src/middleware/index.js +++ b/src/middleware/index.js @@ -4,7 +4,7 @@ import mkdirp from 'mkdirp'; import rimraf from 'rimraf'; import serialize from 'serialize-javascript'; import escape_html from 'escape-html'; -import { route_manager, templates, create_app, compilers, generate_asset_cache } from 'sapper/core.js'; +import { create_routes, templates, create_app, get_compilers, generate_asset_cache } from 'sapper/core.js'; import create_watcher from './create_watcher.js'; import { dest, dev, entry, src } from '../config.js'; @@ -14,7 +14,16 @@ function connect_dev() { create_app({ dev, entry, src }); - const watcher = create_watcher(); + const compilers = get_compilers(); + + let routes; + + const watcher = create_watcher({ + compilers, + on_routes_update: _ => { + routes = _; + } + }); let asset_cache; @@ -55,7 +64,7 @@ function connect_dev() { fn: pathname => asset_cache.client.chunks[pathname] }), - get_route_handler(() => asset_cache), + get_route_handler(() => asset_cache, () => routes), get_not_found_handler(() => asset_cache) ]); @@ -76,6 +85,8 @@ function connect_prod() { server_info: read_json(path.join(dest, 'stats.server.json')) }); + const routes = create_routes({ src }); // TODO rename update + const middleware = compose_handlers([ set_req_pathname, @@ -100,7 +111,7 @@ function connect_prod() { fn: pathname => asset_cache.client.chunks[pathname] }), - get_route_handler(() => asset_cache), + get_route_handler(() => asset_cache, () => routes), get_not_found_handler(() => asset_cache) ]); @@ -132,7 +143,7 @@ function get_asset_handler(opts) { const resolved = Promise.resolve(); -function get_route_handler(fn) { +function get_route_handler(get_assets, get_routes) { function handle_route(route, req, res, next, { client, server }) { req.params = route.exec(req.pathname); @@ -204,8 +215,9 @@ function get_route_handler(fn) { resolved .then(() => { - for (const route of route_manager.routes) { - if (route.test(url)) return handle_route(route, req, res, next, fn()); + const routes = get_routes(); + for (const route of routes) { + if (route.test(url)) return handle_route(route, req, res, next, get_assets()); } // no matching route — 404 diff --git a/test/unit/create_routes.test.js b/test/unit/create_routes.test.js index 2ece078..e2828ed 100644 --- a/test/unit/create_routes.test.js +++ b/test/unit/create_routes.test.js @@ -3,7 +3,9 @@ const { create_routes } = require('../../core.js'); describe('create_routes', () => { it('sorts routes correctly', () => { - const routes = create_routes(['index.html', 'about.html', '[wildcard].html', 'post/foo.html', 'post/[id].html', 'post/bar.html']); + const routes = create_routes({ + files: ['index.html', 'about.html', '[wildcard].html', 'post/foo.html', 'post/[id].html', 'post/bar.html'] + }); assert.deepEqual( routes.map(r => r.file), @@ -19,7 +21,9 @@ describe('create_routes', () => { }); it('generates params', () => { - const routes = create_routes(['index.html', 'about.html', '[wildcard].html', 'post/[id].html']); + const routes = create_routes({ + files: ['index.html', 'about.html', '[wildcard].html', 'post/[id].html'] + }); let file; let params; @@ -38,7 +42,9 @@ describe('create_routes', () => { }); it('ignores files and directories with leading underscores', () => { - const routes = create_routes(['index.html', '_foo.html', 'a/_b/c/d.html', 'e/f/g/h.html', 'i/_j.html']); + const routes = create_routes({ + files: ['index.html', '_foo.html', 'a/_b/c/d.html', 'e/f/g/h.html', 'i/_j.html'] + }); assert.deepEqual( routes.map(r => r.file), @@ -50,8 +56,12 @@ describe('create_routes', () => { }); it('matches /foo/:bar before /:baz/qux', () => { - const a = create_routes(['foo/[bar].html', '[baz]/qux.html']); - const b = create_routes(['[baz]/qux.html', 'foo/[bar].html']); + const a = create_routes({ + files: ['foo/[bar].html', '[baz]/qux.html'] + }); + const b = create_routes({ + files: ['[baz]/qux.html', 'foo/[bar].html'] + }); assert.deepEqual( a.map(r => r.file), @@ -66,16 +76,22 @@ describe('create_routes', () => { it('fails if routes are indistinguishable', () => { assert.throws(() => { - create_routes(['[foo].html', '[bar]/index.html']); + create_routes({ + files: ['[foo].html', '[bar]/index.html'] + }); }, /The \[foo\].html and \[bar\]\/index.html routes clash/); assert.throws(() => { - create_routes(['foo.html', 'foo.js']); + create_routes({ + files: ['foo.html', 'foo.js'] + }); }, /The foo.html and foo.js routes clash/); }); it('matches nested routes', () => { - const route = create_routes(['settings/[submenu].html'])[0]; + const route = create_routes({ + files: ['settings/[submenu].html'] + })[0]; assert.deepEqual(route.exec('/settings/foo'), { submenu: 'foo' @@ -87,7 +103,9 @@ describe('create_routes', () => { }); it('prefers index routes to nested routes', () => { - const routes = create_routes(['settings/[submenu].html', 'settings.html']); + const routes = create_routes({ + files: ['settings/[submenu].html', 'settings.html'] + }); assert.deepEqual( routes.map(r => r.file), @@ -96,7 +114,9 @@ describe('create_routes', () => { }); it('matches deeply nested routes', () => { - const route = create_routes(['settings/[a]/[b]/index.html'])[0]; + const route = create_routes({ + files: ['settings/[a]/[b]/index.html'] + })[0]; assert.deepEqual(route.exec('/settings/foo/bar'), { a: 'foo',