Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings
This repository was archived by the owner on May 10, 2021. It is now read-only.

Commit 479b7e7

Browse filesBrowse files
committed
Fix catch-all routes: Only match if at least one param is present
The default behavior of NextJS catch-all routes is to match only if at least one URL parameter is present. So far, next-on-netlify matched catch-all routes even when no URL parameter was present. For example, /pages/shows/[...slug] would match /shows/2, shows/3/my/path, but also /shows. This does not match the NextJS behavior described here: https://nextjs.org/docs/routing/dynamic-routes#catch-all-routes This commit matches catch-all routes only when at least one URL parameter is present. It is in preparation for #15, which will introduce support for optional catch-all routes. Optional catch-all routes also match the page's base path without URL parameters (e.g. /shows).
1 parent 0412b45 commit 479b7e7
Copy full SHA for 479b7e7

File tree

Expand file treeCollapse file tree

5 files changed

+123
-7
lines changed
Filter options
Expand file treeCollapse file tree

5 files changed

+123
-7
lines changed
+58Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import Error from 'next/error'
2+
import Link from 'next/link'
3+
4+
const Show = ({ errorCode, show }) => {
5+
6+
// If show item was not found, render 404 page
7+
if (errorCode) {
8+
return <Error statusCode={errorCode} />
9+
}
10+
11+
// Otherwise, render show
12+
return (
13+
<div>
14+
<p>
15+
This page uses getInitialProps() to fetch the show with the ID
16+
provided in the URL: /shows/:id
17+
<br/>
18+
Refresh the page to see server-side rendering in action.
19+
<br/>
20+
You can also try changing the ID to any other number between 1-10000.
21+
</p>
22+
23+
<hr/>
24+
25+
<h1>Show #{show.id}</h1>
26+
<p>
27+
{show.name}
28+
</p>
29+
30+
<hr/>
31+
32+
<Link href="/">
33+
<a>Go back home</a>
34+
</Link>
35+
</div>
36+
)
37+
}
38+
39+
export const getServerSideProps = async ({ params }) => {
40+
// The ID to render
41+
const { slug } = params
42+
const id = slug[0]
43+
44+
const res = await fetch(`https://api.tvmaze.com/shows/${id}`);
45+
const data = await res.json();
46+
47+
// Set error code if show item could not be found
48+
const errorCode = res.status > 200 ? res.status : false
49+
50+
return {
51+
props: {
52+
errorCode,
53+
show: data
54+
}
55+
}
56+
}
57+
58+
export default Show

‎cypress/fixtures/pages/index.js

Copy file name to clipboardExpand all lines: cypress/fixtures/pages/index.js
+10Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,16 @@ const Index = ({ shows }) => (
163163
<a>getServerSideProps/1338 (dynamic route)</a>
164164
</Link>
165165
</li>
166+
<li>
167+
<Link href="/getServerSideProps/catch/all/[...slug]" as="/getServerSideProps/catch/all/1337">
168+
<a>getServerSideProps/catch/all/1337 (catch-all route)</a>
169+
</Link>
170+
</li>
171+
<li>
172+
<Link href="/getServerSideProps/catch/all/[...slug]" as="/getServerSideProps/catch/all/1338">
173+
<a>getServerSideProps/catch/all/1338 (catch-all route)</a>
174+
</Link>
175+
</li>
166176
</ul>
167177

168178
<h1>6. Static Pages Stay Static</h1>

‎cypress/integration/default_spec.js

Copy file name to clipboardExpand all lines: cypress/integration/default_spec.js
+50-2Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,14 +153,14 @@ describe('getServerSideProps', () => {
153153

154154
context('with dynamic route', () => {
155155
it('loads TV show', () => {
156-
cy.visit('/shows/1337')
156+
cy.visit('/getServerSideProps/1337')
157157

158158
cy.get('h1').should('contain', 'Show #1337')
159159
cy.get('p').should('contain', 'Whodunnit?')
160160
})
161161

162162
it('loads TV show when SSR-ing', () => {
163-
cy.ssr('/shows/1337')
163+
cy.ssr('/getServerSideProps/1337')
164164

165165
cy.get('h1').should('contain', 'Show #1337')
166166
cy.get('p').should('contain', 'Whodunnit?')
@@ -186,6 +186,54 @@ describe('getServerSideProps', () => {
186186
cy.window().should('have.property', 'noReload', true)
187187
})
188188
})
189+
190+
context('with catch-all route', () => {
191+
it('does not match base path (without params)', () => {
192+
cy.request({
193+
url: '/getServerSideProps/catch/all',
194+
failOnStatusCode: false
195+
}).then(response => {
196+
expect(response.status).to.eq(404)
197+
cy.state('document').write(response.body)
198+
})
199+
200+
cy.get('h2').should('contain', 'This page could not be found.')
201+
})
202+
203+
it('loads TV show with one param', () => {
204+
cy.visit('/getServerSideProps/catch/all/1337')
205+
206+
cy.get('h1').should('contain', 'Show #1337')
207+
cy.get('p').should('contain', 'Whodunnit?')
208+
})
209+
210+
it('loads TV show with multiple params', () => {
211+
cy.visit('/getServerSideProps/catch/all/1337/multiple/params')
212+
213+
cy.get('h1').should('contain', 'Show #1337')
214+
cy.get('p').should('contain', 'Whodunnit?')
215+
})
216+
217+
it('loads page props from data .json file when navigating to it', () => {
218+
cy.visit('/')
219+
cy.window().then(w => w.noReload = true)
220+
221+
// Navigate to page and test that no reload is performed
222+
// See: https://glebbahmutov.com/blog/detect-page-reload/
223+
cy.contains('getServerSideProps/catch/all/1337').click()
224+
225+
cy.get('h1').should('contain', 'Show #1337')
226+
cy.get('p').should('contain', 'Whodunnit?')
227+
228+
cy.contains('Go back home').click()
229+
cy.contains('getServerSideProps/catch/all/1338').click()
230+
231+
cy.get('h1').should('contain', 'Show #1338')
232+
cy.get('p').should('contain', 'The Whole Truth')
233+
234+
cy.window().should('have.property', 'noReload', true)
235+
})
236+
})
189237
})
190238

191239
describe('getStaticProps', () => {

‎lib/getNetlifyRoute.js

Copy file name to clipboardExpand all lines: lib/getNetlifyRoute.js
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
// also handles catch all routes /[...param]/ -> /:*
1010
module.exports = dynamicRoute => {
1111
// replace any catch all group first
12-
const expressified = dynamicRoute.replace(/\[\.\.\.(.*)](.json)?$/, "*");
12+
const expressified = dynamicRoute.replace(/\[\.\.\.(.*)](.json)?$/, ":$1/*");
1313

1414
// now replace other dynamic route groups
1515
return expressified.replace(/\[(.*?)]/g, ":$1");

‎tests/__snapshots__/defaults.test.js.snap

Copy file name to clipboardExpand all lines: tests/__snapshots__/defaults.test.js.snap
+4-4Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,14 @@ exports[`Routing creates Netlify redirects 1`] = `
1717
/getStaticProps/withFallback/3 /getStaticProps/withFallback/3.html 200
1818
/getStaticProps/withFallback/4 /getStaticProps/withFallback/4.html 200
1919
/api/shows/:id /.netlify/functions/next_api_shows_id 200
20-
/api/shows/* /.netlify/functions/next_api_shows_params 200
20+
/api/shows/:params/* /.netlify/functions/next_api_shows_params 200
2121
/getServerSideProps/:id /.netlify/functions/next_getServerSideProps_id 200
2222
/_next/data/%BUILD_ID%/getServerSideProps/:id.json /.netlify/functions/next_getServerSideProps_id 200
2323
/getStaticProps/withFallback/:id /.netlify/functions/next_getStaticProps_withFallback_id 200
2424
/_next/data/%BUILD_ID%/getStaticProps/withFallback/:id.json /.netlify/functions/next_getStaticProps_withFallback_id 200
25-
/getStaticProps/withFallback/* /.netlify/functions/next_getStaticProps_withFallback_slug 200
26-
/_next/data/%BUILD_ID%/getStaticProps/withFallback/* /.netlify/functions/next_getStaticProps_withFallback_slug 200
25+
/getStaticProps/withFallback/:slug/* /.netlify/functions/next_getStaticProps_withFallback_slug 200
26+
/_next/data/%BUILD_ID%/getStaticProps/withFallback/:slug/* /.netlify/functions/next_getStaticProps_withFallback_slug 200
2727
/shows/:id /.netlify/functions/next_shows_id 200
28-
/shows/* /.netlify/functions/next_shows_params 200
28+
/shows/:params/* /.netlify/functions/next_shows_params 200
2929
/static/:id /static/[id].html 200"
3030
`;

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.