@netlify/plugin-nextjs 5.0.0-beta.6 → 5.0.0-beta.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -12,20 +12,34 @@ export const InternalHeaders = {
12
12
  // * https://github.com/vercel/next.js/blob/43c9d8940dc42337dd2f7d66aa90e6abf952278e/packages/next/server/web/spec-extension/response.ts#L10-L27
13
13
  export function updateModifiedHeaders(requestHeaders: Headers, responseHeaders: Headers) {
14
14
  const overriddenHeaders = responseHeaders.get('x-middleware-override-headers')
15
-
16
15
  if (!overriddenHeaders) {
17
16
  return
18
17
  }
19
18
 
20
- const headersToUpdate = overriddenHeaders.split(',').map((header) => header.trim())
19
+ const headersToUpdate = new Set(overriddenHeaders.split(',').map((header) => header.trim()))
20
+
21
+ // We can't iterate this directly, because we modify the headers in the loop.
22
+ // This was causing values to be skipped. By spreading them first we avoid that.
23
+ for (const key of [...requestHeaders.keys()]) {
24
+ if (!headersToUpdate.has(key)) {
25
+ requestHeaders.delete(key)
26
+ }
27
+ }
21
28
 
22
29
  for (const header of headersToUpdate) {
23
30
  const oldHeaderKey = 'x-middleware-request-' + header
24
31
  const headerValue = responseHeaders.get(oldHeaderKey) || ''
25
32
 
26
- requestHeaders.set(header, headerValue)
33
+ const oldValue = requestHeaders.get(header) || ''
34
+
35
+ if (oldValue !== headerValue) {
36
+ if (headerValue) {
37
+ requestHeaders.set(header, headerValue)
38
+ } else {
39
+ requestHeaders.delete(header)
40
+ }
41
+ }
27
42
  responseHeaders.delete(oldHeaderKey)
28
43
  }
29
-
30
44
  responseHeaders.delete('x-middleware-override-headers')
31
45
  }
@@ -1,6 +1,6 @@
1
1
  import type { Context } from '@netlify/edge-functions'
2
2
 
3
- import { normalizeDataUrl, removeBasePath, normalizeLocalePath } from './util.ts'
3
+ import { normalizeDataUrl, removeBasePath, normalizeLocalePath, addBasePath } from './util.ts'
4
4
 
5
5
  interface I18NConfig {
6
6
  defaultLocale: string
@@ -41,6 +41,7 @@ const normalizeRequestURL = (
41
41
  const url = new URL(originalURL)
42
42
 
43
43
  url.pathname = removeBasePath(url.pathname, nextConfig?.basePath)
44
+ const didRemoveBasePath = url.toString() !== originalURL
44
45
 
45
46
  let detectedLocale: string | undefined
46
47
 
@@ -64,6 +65,10 @@ const normalizeRequestURL = (
64
65
  url.pathname = `${url.pathname}/`
65
66
  }
66
67
 
68
+ if (didRemoveBasePath) {
69
+ url.pathname = addBasePath(url.pathname, nextConfig?.basePath)
70
+ }
71
+
67
72
  return {
68
73
  url: url.toString(),
69
74
  detectedLocale,
@@ -3,7 +3,13 @@ import { HTMLRewriter } from '../vendor/deno.land/x/html_rewriter@v0.1.0-pre.17/
3
3
 
4
4
  import { updateModifiedHeaders } from './headers.ts'
5
5
  import type { StructuredLogger } from './logging.ts'
6
- import { normalizeDataUrl, normalizeLocalePath, relativizeURL, rewriteDataPath } from './util.ts'
6
+ import {
7
+ addBasePath,
8
+ normalizeDataUrl,
9
+ normalizeLocalePath,
10
+ relativizeURL,
11
+ rewriteDataPath,
12
+ } from './util.ts'
7
13
  import { addMiddlewareHeaders, isMiddlewareRequest, isMiddlewareResponse } from './middleware.ts'
8
14
  import { RequestData } from './next-request.ts'
9
15
 
@@ -164,27 +170,33 @@ export const buildResponse = async ({
164
170
  newRoute: rewriteUrl.pathname,
165
171
  basePath: nextConfig?.basePath,
166
172
  })
173
+ if (rewriteUrl.toString() === request.url) {
174
+ logger.withFields({ rewrite_url: rewrite }).debug('Rewrite url is same as original url')
175
+ return
176
+ }
177
+ res.headers.set('x-middleware-rewrite', relativeUrl)
178
+ return addMiddlewareHeaders(fetch(new Request(rewriteUrl, request)), res)
179
+ }
180
+ const target = normalizeLocalizedTarget({ target: rewrite, request, nextConfig })
181
+ if (target === request.url) {
182
+ logger.withFields({ rewrite_url: rewrite }).debug('Rewrite url is same as original url')
183
+ return
167
184
  }
168
185
  res.headers.set('x-middleware-rewrite', relativeUrl)
169
- request.headers.set('x-middleware-rewrite', rewrite)
170
- return addMiddlewareHeaders(fetch(new Request(rewriteUrl, request)), res)
186
+ request.headers.set('x-middleware-rewrite', target)
187
+ return addMiddlewareHeaders(fetch(new Request(target, request)), res)
171
188
  }
172
189
 
173
190
  let redirect = res.headers.get('location')
174
191
 
175
192
  // If we are redirecting a request that had a locale in the URL, we need to add it back in
176
193
  if (redirect && requestLocale) {
177
- const redirectUrl = new URL(redirect, request.url)
178
-
179
- const normalizedRedirect = normalizeLocalePath(redirectUrl.pathname, nextConfig?.i18n?.locales)
180
-
181
- const locale = normalizedRedirect.detectedLocale ?? requestLocale
182
- // Pages router API routes don't have a locale in the URL
183
- if (locale && !redirectUrl.pathname.startsWith(`/api/`)) {
184
- redirectUrl.pathname = `/${locale}${normalizedRedirect.pathname}`
185
- redirect = redirectUrl.toString()
186
- res.headers.set('location', redirect)
194
+ redirect = normalizeLocalizedTarget({ target: redirect, request, nextConfig })
195
+ if (redirect === request.url) {
196
+ logger.withFields({ rewrite_url: rewrite }).debug('Rewrite url is same as original url')
197
+ return
187
198
  }
199
+ res.headers.set('location', redirect)
188
200
  }
189
201
 
190
202
  // Data requests shouldn't automatically redirect in the browser (they might be HTML pages): they're handled by the router
@@ -206,3 +218,34 @@ export const buildResponse = async ({
206
218
 
207
219
  return res
208
220
  }
221
+
222
+ /**
223
+ * Normalizes the locale in a URL.
224
+ */
225
+ function normalizeLocalizedTarget({
226
+ target,
227
+ request,
228
+ nextConfig,
229
+ requestLocale,
230
+ }: {
231
+ target: string
232
+ request: Request
233
+ nextConfig?: RequestData['nextConfig']
234
+ requestLocale?: string
235
+ }) {
236
+ const targetUrl = new URL(target, request.url)
237
+
238
+ const normalizedTarget = normalizeLocalePath(targetUrl.pathname, nextConfig?.i18n?.locales)
239
+
240
+ const locale = normalizedTarget.detectedLocale ?? requestLocale
241
+ if (
242
+ locale &&
243
+ !normalizedTarget.pathname.startsWith(`/api/`) &&
244
+ !normalizedTarget.pathname.startsWith(`/_next/static/`)
245
+ ) {
246
+ targetUrl.pathname = addBasePath(`/${locale}${normalizedTarget.pathname}`, nextConfig?.basePath)
247
+ } else {
248
+ targetUrl.pathname = addBasePath(normalizedTarget.pathname, nextConfig?.basePath)
249
+ }
250
+ return targetUrl.toString()
251
+ }
@@ -24,6 +24,13 @@ export const removeBasePath = (path: string, basePath?: string) => {
24
24
  return path
25
25
  }
26
26
 
27
+ export const addBasePath = (path: string, basePath?: string) => {
28
+ if (basePath && !path.startsWith(basePath)) {
29
+ return `${basePath}${path}`
30
+ }
31
+ return path
32
+ }
33
+
27
34
  // https://github.com/vercel/next.js/blob/canary/packages/next/src/shared/lib/i18n/normalize-locale-path.ts
28
35
 
29
36
  export interface PathLocale {
@@ -91,8 +98,11 @@ export function rewriteDataPath({
91
98
  }) {
92
99
  const normalizedDataUrl = normalizeDataUrl(removeBasePath(dataUrl, basePath))
93
100
 
94
- return dataUrl.replace(
95
- normalizeIndex(normalizedDataUrl),
96
- stripTrailingSlash(normalizeIndex(newRoute)),
101
+ return addBasePath(
102
+ dataUrl.replace(
103
+ normalizeIndex(normalizedDataUrl),
104
+ stripTrailingSlash(normalizeIndex(newRoute)),
105
+ ),
106
+ basePath,
97
107
  )
98
108
  }
@@ -59,6 +59,7 @@ export async function handleMiddleware(
59
59
  request,
60
60
  result,
61
61
  requestLocale: nextRequest.detectedLocale,
62
+ nextConfig,
62
63
  })
63
64
 
64
65
  return response
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@netlify/plugin-nextjs",
3
- "version": "5.0.0-beta.6",
3
+ "version": "5.0.0-beta.7",
4
4
  "description": "Run Next.js seamlessly on Netlify",
5
5
  "main": "./dist/index.js",
6
6
  "type": "module",