diff --git a/lerna.json b/lerna.json index f4f8fa29cf7c6..2ffac1b5f7622 100644 --- a/lerna.json +++ b/lerna.json @@ -17,5 +17,5 @@ "registry": "https://registry.npmjs.org/" } }, - "version": "10.0.8-canary.12" + "version": "10.0.8-canary.13" } diff --git a/packages/create-next-app/package.json b/packages/create-next-app/package.json index ade5788a3af20..ec436efe437bf 100644 --- a/packages/create-next-app/package.json +++ b/packages/create-next-app/package.json @@ -1,6 +1,6 @@ { "name": "create-next-app", - "version": "10.0.8-canary.12", + "version": "10.0.8-canary.13", "keywords": [ "react", "next", diff --git a/packages/eslint-plugin-next/package.json b/packages/eslint-plugin-next/package.json index ad9923fe5d490..68099e5c34316 100644 --- a/packages/eslint-plugin-next/package.json +++ b/packages/eslint-plugin-next/package.json @@ -1,6 +1,6 @@ { "name": "@next/eslint-plugin-next", - "version": "10.0.8-canary.12", + "version": "10.0.8-canary.13", "description": "ESLint plugin for NextJS.", "main": "lib/index.js", "license": "MIT", diff --git a/packages/next-bundle-analyzer/package.json b/packages/next-bundle-analyzer/package.json index 0c75fcf2ccdf2..f13d912eb9e7b 100644 --- a/packages/next-bundle-analyzer/package.json +++ b/packages/next-bundle-analyzer/package.json @@ -1,6 +1,6 @@ { "name": "@next/bundle-analyzer", - "version": "10.0.8-canary.12", + "version": "10.0.8-canary.13", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-codemod/package.json b/packages/next-codemod/package.json index 3a69e3dd47541..2599a1d3a7d14 100644 --- a/packages/next-codemod/package.json +++ b/packages/next-codemod/package.json @@ -1,6 +1,6 @@ { "name": "@next/codemod", - "version": "10.0.8-canary.12", + "version": "10.0.8-canary.13", "license": "MIT", "dependencies": { "chalk": "4.1.0", diff --git a/packages/next-env/package.json b/packages/next-env/package.json index 64cca11df1889..0d8b4af0379f1 100644 --- a/packages/next-env/package.json +++ b/packages/next-env/package.json @@ -1,6 +1,6 @@ { "name": "@next/env", - "version": "10.0.8-canary.12", + "version": "10.0.8-canary.13", "keywords": [ "react", "next", diff --git a/packages/next-mdx/package.json b/packages/next-mdx/package.json index b4aeacf24782b..170281ddd49fd 100644 --- a/packages/next-mdx/package.json +++ b/packages/next-mdx/package.json @@ -1,6 +1,6 @@ { "name": "@next/mdx", - "version": "10.0.8-canary.12", + "version": "10.0.8-canary.13", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-plugin-google-analytics/package.json b/packages/next-plugin-google-analytics/package.json index 4d44368becfd4..8ab2dc53c3a32 100644 --- a/packages/next-plugin-google-analytics/package.json +++ b/packages/next-plugin-google-analytics/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-google-analytics", - "version": "10.0.8-canary.12", + "version": "10.0.8-canary.13", "repository": { "url": "vercel/next.js", "directory": "packages/next-plugin-google-analytics" diff --git a/packages/next-plugin-sentry/package.json b/packages/next-plugin-sentry/package.json index 863e5a7e4f039..ffab1daf8b0b1 100644 --- a/packages/next-plugin-sentry/package.json +++ b/packages/next-plugin-sentry/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-sentry", - "version": "10.0.8-canary.12", + "version": "10.0.8-canary.13", "repository": { "url": "vercel/next.js", "directory": "packages/next-plugin-sentry" diff --git a/packages/next-plugin-storybook/package.json b/packages/next-plugin-storybook/package.json index 6e0a36805f303..5272713065cd0 100644 --- a/packages/next-plugin-storybook/package.json +++ b/packages/next-plugin-storybook/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-storybook", - "version": "10.0.8-canary.12", + "version": "10.0.8-canary.13", "repository": { "url": "vercel/next.js", "directory": "packages/next-plugin-storybook" diff --git a/packages/next-polyfill-module/package.json b/packages/next-polyfill-module/package.json index 437c644d76f71..6c58a0a601668 100644 --- a/packages/next-polyfill-module/package.json +++ b/packages/next-polyfill-module/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-module", - "version": "10.0.8-canary.12", + "version": "10.0.8-canary.13", "description": "A standard library polyfill for ES Modules supporting browsers (Edge 16+, Firefox 60+, Chrome 61+, Safari 10.1+)", "main": "dist/polyfill-module.js", "license": "MIT", diff --git a/packages/next-polyfill-nomodule/package.json b/packages/next-polyfill-nomodule/package.json index b5ea635fcebb4..384741fb9b8d1 100644 --- a/packages/next-polyfill-nomodule/package.json +++ b/packages/next-polyfill-nomodule/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-nomodule", - "version": "10.0.8-canary.12", + "version": "10.0.8-canary.13", "description": "A polyfill for non-dead, nomodule browsers.", "main": "dist/polyfill-nomodule.js", "license": "MIT", diff --git a/packages/next/next-server/server/next-server.ts b/packages/next/next-server/server/next-server.ts index 8aa3adc1e1c5a..c7ccd7113208d 100644 --- a/packages/next/next-server/server/next-server.ts +++ b/packages/next/next-server/server/next-server.ts @@ -369,10 +369,9 @@ export default class Server { // interpolate dynamic params and normalize URL if needed if (pageIsDynamic) { let params: ParsedUrlQuery | false = {} - const paramsResult = utils.normalizeDynamicRouteParams({ - ...parsedUrl.query, - ...query, - }) + + Object.assign(parsedUrl.query, query) + const paramsResult = utils.normalizeDynamicRouteParams(parsedUrl.query) if (paramsResult.hasValidParams) { params = paramsResult.params @@ -407,6 +406,7 @@ export default class Server { pathname: matchedPathname, }) } + Object.assign(parsedUrl.query, params) utils.normalizeVercelUrl(req, true) } diff --git a/packages/next/package.json b/packages/next/package.json index 07910a0b041b4..8ff2fe8eef1da 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "10.0.8-canary.12", + "version": "10.0.8-canary.13", "description": "The React Framework", "main": "./dist/server/next.js", "license": "MIT", @@ -62,10 +62,10 @@ "dependencies": { "@babel/runtime": "7.12.5", "@hapi/accept": "5.0.1", - "@next/env": "10.0.8-canary.12", - "@next/polyfill-module": "10.0.8-canary.12", - "@next/react-dev-overlay": "10.0.8-canary.12", - "@next/react-refresh-utils": "10.0.8-canary.12", + "@next/env": "10.0.8-canary.13", + "@next/polyfill-module": "10.0.8-canary.13", + "@next/react-dev-overlay": "10.0.8-canary.13", + "@next/react-refresh-utils": "10.0.8-canary.13", "@opentelemetry/api": "0.14.0", "ast-types": "0.13.2", "browserslist": "4.16.1", @@ -133,7 +133,7 @@ "@babel/preset-react": "7.12.10", "@babel/preset-typescript": "7.12.7", "@babel/types": "7.12.12", - "@next/polyfill-nomodule": "10.0.8-canary.12", + "@next/polyfill-nomodule": "10.0.8-canary.13", "@taskr/clear": "1.1.0", "@taskr/esnext": "1.1.0", "@taskr/watch": "1.1.0", diff --git a/packages/react-dev-overlay/package.json b/packages/react-dev-overlay/package.json index 236ca7ce533b0..e17e4a4d74487 100644 --- a/packages/react-dev-overlay/package.json +++ b/packages/react-dev-overlay/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-dev-overlay", - "version": "10.0.8-canary.12", + "version": "10.0.8-canary.13", "description": "A development-only overlay for developing React applications.", "repository": { "url": "vercel/next.js", diff --git a/packages/react-refresh-utils/package.json b/packages/react-refresh-utils/package.json index ed115bf71ae0c..8a31c983d479d 100644 --- a/packages/react-refresh-utils/package.json +++ b/packages/react-refresh-utils/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-refresh-utils", - "version": "10.0.8-canary.12", + "version": "10.0.8-canary.13", "description": "An experimental package providing utilities for React Refresh.", "repository": { "url": "vercel/next.js", diff --git a/test/integration/required-server-files/pages/api/optional/[[...rest]].js b/test/integration/required-server-files/pages/api/optional/[[...rest]].js new file mode 100644 index 0000000000000..a5395a602d14c --- /dev/null +++ b/test/integration/required-server-files/pages/api/optional/[[...rest]].js @@ -0,0 +1,7 @@ +export default (req, res) => { + console.log(req.url, 'query', req.query) + res.json({ + url: req.url, + query: req.query, + }) +} diff --git a/test/integration/required-server-files/pages/optional-ssg/[[...rest]].js b/test/integration/required-server-files/pages/optional-ssg/[[...rest]].js new file mode 100644 index 0000000000000..dbe91169f2a77 --- /dev/null +++ b/test/integration/required-server-files/pages/optional-ssg/[[...rest]].js @@ -0,0 +1,20 @@ +export const getStaticProps = ({ params }) => { + return { + props: { + random: Math.random(), + params: params || null, + }, + revalidate: 1, + } +} + +export const getStaticPaths = () => { + return { + paths: [], + fallback: true, + } +} + +export default function Page(props) { + return
{JSON.stringify(props)}
+} diff --git a/test/integration/required-server-files/pages/optional-ssp/[[...rest]].js b/test/integration/required-server-files/pages/optional-ssp/[[...rest]].js new file mode 100644 index 0000000000000..53a840b79e21d --- /dev/null +++ b/test/integration/required-server-files/pages/optional-ssp/[[...rest]].js @@ -0,0 +1,13 @@ +export const getServerSideProps = ({ query, params }) => { + return { + props: { + random: Math.random(), + query: query, + params: params || null, + }, + } +} + +export default function Page(props) { + return{JSON.stringify(props)}
+} diff --git a/test/integration/required-server-files/test/index.test.js b/test/integration/required-server-files/test/index.test.js index f5a0cafd9dfd9..399fcfedbc748 100644 --- a/test/integration/required-server-files/test/index.test.js +++ b/test/integration/required-server-files/test/index.test.js @@ -448,4 +448,58 @@ describe('Required Server Files', () => { expect(errors.length).toBe(1) expect(errors[0].message).toContain('gsp hit an oops') }) + + it('should normalize optional values correctly for SSP page', async () => { + const res = await fetchViaHTTP( + appPort, + '/optional-ssp', + { rest: '', another: 'value' }, + { + headers: { + 'x-matched-path': '/optional-ssp/[[...rest]]', + }, + } + ) + + const html = await res.text() + const $ = cheerio.load(html) + const props = JSON.parse($('#props').text()) + expect(props.params).toEqual({}) + expect(props.query).toEqual({ another: 'value' }) + }) + + it('should normalize optional values correctly for SSG page', async () => { + const res = await fetchViaHTTP( + appPort, + '/optional-ssg', + { rest: '', another: 'value' }, + { + headers: { + 'x-matched-path': '/optional-ssg/[[...rest]]', + }, + } + ) + + const html = await res.text() + const $ = cheerio.load(html) + const props = JSON.parse($('#props').text()) + expect(props.params).toEqual({}) + }) + + it('should normalize optional values correctly for API page', async () => { + const res = await fetchViaHTTP( + appPort, + '/api/optional', + { rest: '', another: 'value' }, + { + headers: { + 'x-matched-path': '/api/optional/[[...rest]]', + }, + } + ) + + const json = await res.json() + expect(json.query).toEqual({ another: 'value' }) + expect(json.url).toBe('/api/optional?another=value') + }) })