Skip to content

Commit

Permalink
Temporary: SPR: Use Group Index Mapping (#9089)
Browse files Browse the repository at this point in the history
This pull request is a temporary addition that uses the `x-now-route-params` header in serverless.

This header returns the regex groups with indexes, not their named variants.
As a result, we must use the getRouteMatcher utility to reverse this into Next.js' expected names.

Since this got complex, I've added a test for it. We should probably remove this behavior sooner than later.
  • Loading branch information
Timer authored Oct 15, 2019
1 parent c77338b commit 0208356
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 1 deletion.
26 changes: 25 additions & 1 deletion packages/next/build/webpack/loaders/next-serverless-loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ const nextServerlessLoader: loader.Loader = function() {
} else {
return `
import {parse} from 'url'
import {parse as parseQs} from 'querystring'
import {renderToHTML} from 'next/dist/next-server/server/render';
import {sendHTML} from 'next/dist/next-server/server/send-html';
${
Expand Down Expand Up @@ -138,7 +139,30 @@ const nextServerlessLoader: loader.Loader = function() {
// removing reliance on `req.url` and using `req.query` instead
// (which is needed for "custom routes" anyway).
isDynamicRoute(page)
? `const nowParams = (req.headers && req.headers["x-now-route-params"]) ? querystring.parse(req.headers["x-now-route-params"]) : null;`
? `const nowParams = req.headers && req.headers["x-now-route-params"]
? getRouteMatcher(
(function() {
const { re, groups } = getRouteRegex("${page}");
return {
re: {
// Simulate a RegExp match from the \`req.url\` input
exec: str => {
const obj = parseQs(str);
return Object.keys(obj).reduce(
(prev, key) =>
Object.assign(prev, {
[key]: encodeURIComponent(obj[key])
}),
{}
);
}
},
groups
};
})()
)(req.headers["x-now-route-params"])
: null;
`
: `const nowParams = null;`
}
const result = await renderToHTML(req, res, "${page}", Object.assign({}, unstable_getStaticProps ? {} : parsedUrl.query, nowParams ? nowParams : params, sprData ? { _nextSprData: '1' } : {}), renderOpts)
Expand Down
5 changes: 5 additions & 0 deletions test/integration/serverless/pages/dr/[slug].js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const SlugPage = ({ query }) => <div>{JSON.stringify(query)}</div>

SlugPage.getInitialProps = ({ query }) => ({ query })

export default SlugPage
23 changes: 23 additions & 0 deletions test/integration/serverless/test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
fetchViaHTTP,
renderViaHTTP
} from 'next-test-utils'
import qs from 'querystring'
import fetch from 'node-fetch'

const appDir = join(__dirname, '../')
Expand Down Expand Up @@ -192,6 +193,28 @@ describe('Serverless', () => {
expect(res.status).toBe(404)
})

it('should have the correct query string for a dynamic route', async () => {
const paramRaw = 'test % 123'
const param = encodeURIComponent(paramRaw)

const html = await renderViaHTTP(appPort, `/dr/${param}`)
const $ = cheerio.load(html)
const data = JSON.parse($('#__NEXT_DATA__').html())

expect(data.query).toEqual({ slug: paramRaw })
})

it('should have the correct query string for a spr route', async () => {
const paramRaw = 'test % 123'
const html = await fetchViaHTTP(appPort, `/dr/[slug]`, '', {
headers: { 'x-now-route-params': qs.stringify({ 1: paramRaw }) }
}).then(res => res.text())
const $ = cheerio.load(html)
const data = JSON.parse($('#__NEXT_DATA__').html())

expect(data.query).toEqual({ slug: paramRaw })
})

describe('With basic usage', () => {
it('should allow etag header support', async () => {
const url = `http://localhost:${appPort}/`
Expand Down

0 comments on commit 0208356

Please sign in to comment.