From 51b4f9cbbf00393a5d163ffe4aebd1c052cc11d6 Mon Sep 17 00:00:00 2001 From: Luke Edwards Date: Sun, 29 Jul 2018 14:01:44 -0700 Subject: [PATCH 1/4] add `opts.ignore` support --- src/middleware.ts | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/middleware.ts b/src/middleware.ts index d764d42..dcf1ff6 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -73,9 +73,18 @@ interface Component { preload: (data: any) => any | Promise } +const IGNORE = '__SAPPER__IGNORE__'; +function toIgnore(uri: string, val: any) { + if (Array.isArray(val)) return val.some(x => toIgnore(uri, x)); + if (val instanceof RegExp) return val.test(uri); + if (typeof val === 'function') return val(uri); + return uri.startsWith(val.charCodeAt(0) === 47 ? val : `/${val}`); +} + export default function middleware(opts: { manifest: Manifest, store: (req: Req) => Store, + ignore?: any, routes?: any // legacy }) { if (opts.routes) { @@ -84,12 +93,19 @@ export default function middleware(opts: { const output = locations.dest(); - const { manifest, store } = opts; + const { manifest, store, ignore } = opts; let emitted_basepath = false; const middleware = compose_handlers([ + ignore && ((req: Req, res: ServerResponse, next: () => void) => { + req[IGNORE] = toIgnore(req.path, ignore); + next(); + }), + (req: Req, res: ServerResponse, next: () => void) => { + if (req[IGNORE]) return next(); + if (req.baseUrl === undefined) { let { originalUrl } = req; if (req.url === '/' && originalUrl[originalUrl.length - 1] !== '/') { @@ -163,6 +179,8 @@ function serve({ prefix, pathname, cache_control }: { : (file: string) => (cache.has(file) ? cache : cache.set(file, fs.readFileSync(path.resolve(output, file)))).get(file) return (req: Req, res: ServerResponse, next: () => void) => { + if (req[IGNORE]) return next(); + if (filter(req)) { const type = lookup(req.path); @@ -245,6 +263,8 @@ function get_server_route_handler(routes: ServerRoute[]) { } return function find_route(req: Req, res: ServerResponse, next: () => void) { + if (req[IGNORE]) return next(); + for (const route of routes) { if (route.pattern.test(req.path)) { handle_route(route, req, res, next); @@ -494,7 +514,9 @@ function get_page_handler(manifest: Manifest, store_getter: (req: Req) => Store) }); } - return function find_route(req: Req, res: ServerResponse) { + return function find_route(req: Req, res: ServerResponse, next: () => void) { + if (req[IGNORE]) return next(); + if (!server_routes.some(route => route.pattern.test(req.path))) { for (const page of pages) { if (page.pattern.test(req.path)) { From 3d77dacbd6791e0b410570bb1ef85009acb1ce5a Mon Sep 17 00:00:00 2001 From: Luke Edwards Date: Sun, 29 Jul 2018 14:02:18 -0700 Subject: [PATCH 2/4] attach `ignore` options to test app, w/ matching routes --- test/app/app/server.js | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/test/app/app/server.js b/test/app/app/server.js index 645699f..b02d82e 100644 --- a/test/app/app/server.js +++ b/test/app/app/server.js @@ -91,8 +91,14 @@ const middlewares = [ return new Store({ title: 'Stored title' }); - } - }) + }, + ignore: [ + /foo/i, + '/buzz', + 'fizz', + x => x === '/hello' + ] + }), ]; if (BASEPATH) { @@ -101,4 +107,8 @@ if (BASEPATH) { app.use(...middlewares); } -app.listen(PORT); \ No newline at end of file +['foobar', 'buzz', 'fizzer', 'hello'].forEach(uri => { + app.get('/'+uri, (req, res) => res.end(uri)); +}); + +app.listen(PORT); From 566addd406b2ac5f1284def8eab7a9819a5832a4 Mon Sep 17 00:00:00 2001 From: Luke Edwards Date: Sun, 29 Jul 2018 14:17:13 -0700 Subject: [PATCH 3/4] add tests for `opts.ignore` --- test/common/test.js | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/test/common/test.js b/test/common/test.js index 99aad94..300f94c 100644 --- a/test/common/test.js +++ b/test/common/test.js @@ -477,6 +477,42 @@ function run({ mode, basepath = '' }) { }); }); + // Ignores are meant for top-level escape. + // ~> Sapper **should** own the entire {basepath} when designated. + if (!basepath) { + it('respects `options.ignore` values (RegExp)', () => { + return nightmare.goto(`${base}/foobar`) + .evaluate(() => document.documentElement.textContent) + .then(text => { + assert.equal(text, 'foobar'); + }); + }); + + it('respects `options.ignore` values (String #1)', () => { + return nightmare.goto(`${base}/buzz`) + .evaluate(() => document.documentElement.textContent) + .then(text => { + assert.equal(text, 'buzz'); + }); + }); + + it('respects `options.ignore` values (String #2)', () => { + return nightmare.goto(`${base}/fizzer`) + .evaluate(() => document.documentElement.textContent) + .then(text => { + assert.equal(text, 'fizzer'); + }); + }); + + it('respects `options.ignore` values (Function)', () => { + return nightmare.goto(`${base}/hello`) + .evaluate(() => document.documentElement.textContent) + .then(text => { + assert.equal(text, 'hello'); + }); + }); + } + it('does not attempt client-side navigation to server routes', () => { return nightmare.goto(`${base}/blog/how-is-sapper-different-from-next`) .init() From 4b2b6440d02b27eee5d4e4d96ef38ba52dc7a543 Mon Sep 17 00:00:00 2001 From: Luke Edwards Date: Tue, 31 Jul 2018 16:54:29 -0700 Subject: [PATCH 4/4] fix: use more specific ignore pattern; MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ~> leaked into another test’s route --- test/app/app/server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/app/app/server.js b/test/app/app/server.js index b02d82e..eb36e5a 100644 --- a/test/app/app/server.js +++ b/test/app/app/server.js @@ -93,7 +93,7 @@ const middlewares = [ }); }, ignore: [ - /foo/i, + /foobar/i, '/buzz', 'fizz', x => x === '/hello'