diff --git a/src/core/create_app.ts b/src/core/create_app.ts index ca405dbc5..fdab1f935 100644 --- a/src/core/create_app.ts +++ b/src/core/create_app.ts @@ -22,8 +22,11 @@ function generate_client(routes: Route[], src: string, dev: boolean, dev_port?: // This file is generated by Sapper — do not edit it! export const routes = [ ${routes - .filter(route => route.type === 'page') .map(route => { + if (route.type !== 'page') { + return `{ pattern: ${route.pattern}, ignore: true }`; + } + const file = posixify(`../../routes/${route.file}`); if (route.id === '_4xx' || route.id === '_5xx') { diff --git a/src/runtime/index.ts b/src/runtime/index.ts index 92fdd0e44..43e9ee4cd 100644 --- a/src/runtime/index.ts +++ b/src/runtime/index.ts @@ -26,6 +26,8 @@ function select_route(url: URL): Target { for (const route of routes) { const match = route.pattern.exec(url.pathname); if (match) { + if (route.ignore) return null; + const params = route.params(match); const query: Record = {}; diff --git a/src/runtime/interfaces.ts b/src/runtime/interfaces.ts index 30d90252c..e20349e47 100644 --- a/src/runtime/interfaces.ts +++ b/src/runtime/interfaces.ts @@ -14,7 +14,8 @@ export interface Component { export type Route = { pattern: RegExp; params: (match: RegExpExecArray) => Record; - load: () => Promise<{ default: ComponentConstructor }> + load: () => Promise<{ default: ComponentConstructor }>; + ignore?: boolean; }; export type ScrollPosition = { diff --git a/test/app/routes/api/blog/contents.js b/test/app/routes/blog.json.js similarity index 88% rename from test/app/routes/api/blog/contents.js rename to test/app/routes/blog.json.js index 0a426905b..6d2b5cb96 100644 --- a/test/app/routes/api/blog/contents.js +++ b/test/app/routes/blog.json.js @@ -1,4 +1,4 @@ -import posts from './_posts.js'; +import posts from './blog/_posts.js'; const contents = JSON.stringify(posts.map(post => { return { diff --git a/test/app/routes/blog/[slug].html b/test/app/routes/blog/[slug].html index 98e9f7a21..a1c3d2341 100644 --- a/test/app/routes/blog/[slug].html +++ b/test/app/routes/blog/[slug].html @@ -63,7 +63,7 @@

{{post.title}}

return this.error(500, 'something went wrong'); } - return fetch(`/api/blog/${slug}`).then(r => { + return fetch(`/blog/${slug}.json`).then(r => { if (r.status === 200) { return r.json().then(post => ({ post })); this.error(r.status, '') diff --git a/test/app/routes/api/blog/[slug].js b/test/app/routes/blog/[slug].json.js similarity index 100% rename from test/app/routes/api/blog/[slug].js rename to test/app/routes/blog/[slug].json.js diff --git a/test/app/routes/api/blog/_posts.js b/test/app/routes/blog/_posts.js similarity index 98% rename from test/app/routes/api/blog/_posts.js rename to test/app/routes/blog/_posts.js index f3520d1e6..75aa0a1ea 100644 --- a/test/app/routes/api/blog/_posts.js +++ b/test/app/routes/blog/_posts.js @@ -70,7 +70,7 @@ const posts = [ ` diff --git a/test/app/routes/blog/index.html b/test/app/routes/blog/index.html index affe73fdd..d8deaf53e 100644 --- a/test/app/routes/blog/index.html +++ b/test/app/routes/blog/index.html @@ -32,7 +32,7 @@

Recent posts

}, preload({ params, query }) { - return fetch(`/api/blog/contents`).then(r => r.json()).then(posts => { + return fetch(`/blog.json`).then(r => r.json()).then(posts => { return { posts }; }); } diff --git a/test/common/test.js b/test/common/test.js index ff7b735bc..911939450 100644 --- a/test/common/test.js +++ b/test/common/test.js @@ -12,6 +12,10 @@ run('development'); Nightmare.action('page', { title(done) { this.evaluate_now(() => document.querySelector('h1').textContent, done); + }, + + text(done) { + this.evaluate_now(() => document.body.textContent, done); } }); @@ -193,7 +197,7 @@ function run(env) { }); }) .then(requests => { - assert.ok(!!requests.find(r => r.url === '/api/blog/why-the-name')); + assert.ok(!!requests.find(r => r.url === '/blog/why-the-name.json')); }); }); @@ -219,7 +223,7 @@ function run(env) { }); }) .then(mouseover_requests => { - assert.ok(mouseover_requests.findIndex(r => r.url === '/api/blog/what-is-sapper') !== -1); + assert.ok(mouseover_requests.findIndex(r => r.url === '/blog/what-is-sapper.json') !== -1); return capture(() => { return nightmare @@ -228,7 +232,7 @@ function run(env) { }); }) .then(click_requests => { - assert.ok(click_requests.findIndex(r => r.url === '/api/blog/what-is-sapper') === -1); + assert.ok(click_requests.findIndex(r => r.url === '/blog/what-is-sapper.json') === -1); }); }); @@ -376,6 +380,17 @@ function run(env) { assert.equal(title, 'Internal server error'); }); }); + + it('does not attempt client-side navigation to server routes', () => { + return nightmare.goto(`${base}/blog/how-is-sapper-different-from-next`) + .init() + .click(`[href="/blog/how-is-sapper-different-from-next.json"]`) + .wait(200) + .page.text() + .then(text => { + JSON.parse(text); + }); + }); }); describe('headers', () => { @@ -415,13 +430,13 @@ function run(env) { 'blog/what-is-sapper/index.html', 'blog/why-the-name/index.html', - 'api/blog/contents', - 'api/blog/a-very-long-post', - 'api/blog/how-can-i-get-involved', - 'api/blog/how-is-sapper-different-from-next', - 'api/blog/how-to-use-sapper', - 'api/blog/what-is-sapper', - 'api/blog/why-the-name', + 'blog.json', + 'blog/a-very-long-post.json', + 'blog/how-can-i-get-involved.json', + 'blog/how-is-sapper-different-from-next.json', + 'blog/how-to-use-sapper.json', + 'blog/what-is-sapper.json', + 'blog/why-the-name.json', 'favicon.png', 'global.css',