Skip to content

Commit

Permalink
Add err.sh for invalid multi-match usage (#9498)
Browse files Browse the repository at this point in the history
* Adds err.sh for multi-match error

* Fix missing apostrophe

* Update regex to catch other param names

* Add test for multi-match error

* Update test/integration/invalid-multi-match/test/index.test.js
  • Loading branch information
ijjk authored and timneutkens committed Nov 23, 2019
1 parent 874d3fd commit ff2d28c
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 1 deletion.
27 changes: 27 additions & 0 deletions errors/invalid-multi-match.md
@@ -0,0 +1,27 @@
# Invalid Multi-match

#### Why This Error Occurred

In one of your custom-routes you specified a multi-match `/:path*` and used it in your `destination` without adding the `*` in your `destination` e.g. `destination: '/another/:path'`

#### Possible Ways to Fix It

Add `*` to your usage of the multi-match param in your `destination`.

**Before**

```js
{
source: '/:path*',
destination: '/another/:path'
}
```

**After**

```js
{
source: '/:path*',
destination: '/another/:path*'
}
```
15 changes: 14 additions & 1 deletion packages/next/next-server/server/next-server.ts
Expand Up @@ -412,7 +412,20 @@ export default class Server {
name: `${route.type} ${route.source} route`,
fn: async (_req, res, params, _parsedUrl) => {
let destinationCompiler = pathToRegexp.compile(route.destination)
let newUrl = destinationCompiler(params)
let newUrl

try {
newUrl = destinationCompiler(params)
} catch (err) {
if (
err.message.match(/Expected .*? to not repeat, but got array/)
) {
throw new Error(
`To use a multi-match in the destination you must add \`*\` at the end of the param name to signify it should repeat. https://err.sh/zeit/next.js/invalid-multi-match`
)
}
throw err
}

if (route.type === 'redirect') {
res.setHeader('Location', newUrl)
Expand Down
12 changes: 12 additions & 0 deletions test/integration/invalid-multi-match/next.config.js
@@ -0,0 +1,12 @@
module.exports = {
experimental: {
rewrites() {
return [
{
source: '/:hello*',
destination: '/:hello',
},
]
},
},
}
15 changes: 15 additions & 0 deletions test/integration/invalid-multi-match/pages/hello.js
@@ -0,0 +1,15 @@
import { useRouter } from 'next/router'

console.log('hello from hello.js')

const Page = () => {
const { query } = useRouter()
return (
<>
<h3>hello world</h3>
<span>{JSON.stringify(query)}</span>
</>
)
}

export default Page
57 changes: 57 additions & 0 deletions test/integration/invalid-multi-match/test/index.test.js
@@ -0,0 +1,57 @@
/* eslint-env jest */
/* global jasmine */
import { join } from 'path'
import {
launchApp,
killApp,
findPort,
nextBuild,
nextStart,
renderViaHTTP,
} from 'next-test-utils'

jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000 * 60 * 2

let appDir = join(__dirname, '..')
let stderr = ''
let appPort
let app

const runTests = () => {
it('should show error for invalid mulit-match', async () => {
await renderViaHTTP(appPort, '/hello')
expect(stderr).toContain(
'To use a multi-match in the destination you must add'
)
expect(stderr).toContain('https://err.sh/zeit/next.js/invalid-multi-match')
})
}

describe('Custom routes', () => {
describe('dev mode', () => {
beforeAll(async () => {
appPort = await findPort()
app = await launchApp(appDir, appPort, {
onStderr: msg => {
stderr += msg
},
})
})
afterAll(() => killApp(app))
runTests(true)
})

describe('production mode', () => {
beforeAll(async () => {
await nextBuild(appDir)
appPort = await findPort()
app = await nextStart(appDir, appPort, {
onStderr: msg => {
stderr += msg
},
})
})
afterAll(() => killApp(app))
runTests()
})
})

0 comments on commit ff2d28c

Please sign in to comment.