@netlify/plugin-nextjs 5.5.1 → 5.6.0

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.
@@ -169,7 +169,7 @@ var copyNextDependencies = async (ctx) => {
169
169
  await tracer.withActiveSpan("copyNextDependencies", async () => {
170
170
  const entries = await readdir(ctx.standaloneDir);
171
171
  const promises = entries.map(async (entry) => {
172
- if (entry === "package.json" || entry === ctx.nextDistDir) {
172
+ if (entry === ctx.nextDistDir) {
173
173
  return;
174
174
  }
175
175
  const src = join(ctx.standaloneDir, entry);
@@ -431,10 +431,7 @@ var writeHandlerFile = async (ctx, { matchers, name }) => {
431
431
  const handlerDirectory = join(ctx.edgeFunctionsDir, handlerName);
432
432
  const handlerRuntimeDirectory = join(handlerDirectory, "edge-runtime");
433
433
  await copyRuntime(ctx, handlerDirectory);
434
- await writeFile(
435
- join(handlerRuntimeDirectory, "matchers.json"),
436
- JSON.stringify(augmentMatchers(matchers, ctx))
437
- );
434
+ await writeFile(join(handlerRuntimeDirectory, "matchers.json"), JSON.stringify(matchers));
438
435
  const minimalNextConfig = {
439
436
  basePath: nextConfig.basePath,
440
437
  i18n: nextConfig.i18n,
@@ -61,10 +61,16 @@ var copyHandlerDependencies = async (ctx) => {
61
61
  )
62
62
  );
63
63
  }
64
+ promises.push(
65
+ writeFile(
66
+ join(ctx.serverHandlerRuntimeModulesDir, "package.json"),
67
+ JSON.stringify({ type: "module" })
68
+ )
69
+ );
64
70
  const fileList = await (0, import_fast_glob.glob)("dist/**/*", { cwd: ctx.pluginDir });
65
71
  for (const filePath of fileList) {
66
72
  promises.push(
67
- cp(join(ctx.pluginDir, filePath), join(ctx.serverHandlerDir, ".netlify", filePath), {
73
+ cp(join(ctx.pluginDir, filePath), join(ctx.serverHandlerRuntimeModulesDir, filePath), {
68
74
  recursive: true,
69
75
  force: true
70
76
  })
@@ -90,12 +96,6 @@ var writeHandlerManifest = async (ctx) => {
90
96
  "utf-8"
91
97
  );
92
98
  };
93
- var writePackageMetadata = async (ctx) => {
94
- await writeFile(
95
- join(ctx.serverHandlerRootDir, "package.json"),
96
- JSON.stringify({ type: "module" })
97
- );
98
- };
99
99
  var applyTemplateVariables = (template, variables) => {
100
100
  return Object.entries(variables).reduce((acc, [key, value]) => {
101
101
  return acc.replaceAll(key, value);
@@ -126,12 +126,11 @@ var clearStaleServerHandlers = async (ctx) => {
126
126
  };
127
127
  var createServerHandler = async (ctx) => {
128
128
  await tracer.withActiveSpan("createServerHandler", async () => {
129
- await mkdir(join(ctx.serverHandlerDir, ".netlify"), { recursive: true });
129
+ await mkdir(join(ctx.serverHandlerRuntimeModulesDir), { recursive: true });
130
130
  await copyNextServerCode(ctx);
131
131
  await copyNextDependencies(ctx);
132
132
  await copyHandlerDependencies(ctx);
133
133
  await writeHandlerManifest(ctx);
134
- await writePackageMetadata(ctx);
135
134
  await writeHandlerFile(ctx);
136
135
  await verifyHandlerDirStructure(ctx);
137
136
  });
@@ -133,6 +133,9 @@ var PluginContext = class {
133
133
  }
134
134
  return join(this.serverHandlerRootDir, this.distDirParent);
135
135
  }
136
+ get serverHandlerRuntimeModulesDir() {
137
+ return join(this.serverHandlerDir, ".netlify");
138
+ }
136
139
  get nextServerHandler() {
137
140
  if (this.relativeAppDir.length !== 0) {
138
141
  return join(this.lambdaWorkingDirectory, ".netlify/dist/run/handlers/server.js");
@@ -103,11 +103,10 @@ async function verifyNetlifyFormsWorkaround(ctx) {
103
103
  }
104
104
  }
105
105
  function verifyNetlifyForms(ctx, html) {
106
- if (!verifications.has("netlifyForms") && !verifications.has("netlifyFormsWorkaround") && formDetectionRegex.test(html)) {
107
- console.warn(
106
+ if (process.env.NETLIFY_NEXT_VERIFY_FORMS !== "0" && process.env.NETLIFY_NEXT_VERIFY_FORMS?.toUpperCase() !== "FALSE" && !verifications.has("netlifyFormsWorkaround") && formDetectionRegex.test(html)) {
107
+ ctx.failBuild(
108
108
  "@netlify/plugin-nextjs@5 requires migration steps to support Netlify Forms. Refer to https://ntl.fyi/next-runtime-forms-migration for migration example."
109
109
  );
110
- verifications.add("netlifyForms");
111
110
  }
112
111
  }
113
112
  export {
@@ -8,7 +8,7 @@ import "./chunk-OEQOKJGE.js";
8
8
 
9
9
  // package.json
10
10
  var name = "@netlify/plugin-nextjs";
11
- var version = "5.5.1";
11
+ var version = "5.6.0";
12
12
  var description = "Run Next.js seamlessly on Netlify";
13
13
  var main = "./dist/index.js";
14
14
  var type = "module";
@@ -60,10 +60,10 @@ var devDependencies = {
60
60
  "@netlify/blobs": "^7.3.0",
61
61
  "@netlify/build": "^29.50.2",
62
62
  "@netlify/edge-bundler": "^12.1.1",
63
- "@netlify/edge-functions": "^2.8.1",
63
+ "@netlify/edge-functions": "^2.10.0",
64
64
  "@netlify/eslint-config-node": "^7.0.1",
65
65
  "@netlify/functions": "^2.8.1",
66
- "@netlify/serverless-functions-api": "^1.19.1",
66
+ "@netlify/serverless-functions-api": "^1.22.0",
67
67
  "@netlify/zip-it-and-ship-it": "^9.37.3",
68
68
  "@opentelemetry/api": "^1.8.0",
69
69
  "@opentelemetry/exporter-trace-otlp-http": "^0.51.0",
@@ -67385,7 +67385,7 @@ var import_semantic_conventions = __toESM(require_src(), 1);
67385
67385
  import { getLogger } from "./request-context.cjs";
67386
67386
  var {
67387
67387
  default: { version, name }
67388
- } = await import("../../esm-chunks/package-SHOGGUO3.js");
67388
+ } = await import("../../esm-chunks/package-OHGYB5OD.js");
67389
67389
  var sdk = new import_sdk_node.NodeSDK({
67390
67390
  resource: new import_resources.Resource({
67391
67391
  [import_semantic_conventions.SEMRESATTRS_SERVICE_NAME]: name,
@@ -2,6 +2,7 @@ import type { Context } from '@netlify/edge-functions'
2
2
 
3
3
  import {
4
4
  addBasePath,
5
+ addLocale,
5
6
  addTrailingSlash,
6
7
  normalizeDataUrl,
7
8
  normalizeLocalePath,
@@ -73,6 +74,33 @@ const normalizeRequestURL = (
73
74
  }
74
75
  }
75
76
 
77
+ export const localizeRequest = (
78
+ url: URL,
79
+ nextConfig?: {
80
+ basePath?: string
81
+ i18n?: I18NConfig | null
82
+ },
83
+ ): { localizedUrl: URL; locale?: string } => {
84
+ const localizedUrl = new URL(url)
85
+ localizedUrl.pathname = removeBasePath(localizedUrl.pathname, nextConfig?.basePath)
86
+
87
+ // Detect the locale from the URL
88
+ const { detectedLocale } = normalizeLocalePath(localizedUrl.pathname, nextConfig?.i18n?.locales)
89
+
90
+ // Add the locale to the URL if not already present
91
+ localizedUrl.pathname = addLocale(
92
+ localizedUrl.pathname,
93
+ detectedLocale ?? nextConfig?.i18n?.defaultLocale,
94
+ )
95
+
96
+ localizedUrl.pathname = addBasePath(localizedUrl.pathname, nextConfig?.basePath)
97
+
98
+ return {
99
+ localizedUrl,
100
+ locale: detectedLocale,
101
+ }
102
+ }
103
+
76
104
  export const buildNextRequest = (
77
105
  request: Request,
78
106
  context: Context,
@@ -29,6 +29,20 @@ export const addBasePath = (path: string, basePath?: string) => {
29
29
  return path
30
30
  }
31
31
 
32
+ // add locale prefix if not present, allowing for locale fallbacks
33
+ export const addLocale = (path: string, locale?: string) => {
34
+ if (
35
+ locale &&
36
+ path.toLowerCase() !== `/${locale.toLowerCase()}` &&
37
+ !path.toLowerCase().startsWith(`/${locale.toLowerCase()}/`) &&
38
+ !path.startsWith(`/api/`) &&
39
+ !path.startsWith(`/_next/`)
40
+ ) {
41
+ return `/${locale}${path}`
42
+ }
43
+ return path
44
+ }
45
+
32
46
  // https://github.com/vercel/next.js/blob/canary/packages/next/src/shared/lib/i18n/normalize-locale-path.ts
33
47
 
34
48
  export interface PathLocale {
@@ -5,7 +5,7 @@ import nextConfig from './next.config.json' with { type: 'json' }
5
5
 
6
6
  import { InternalHeaders } from './lib/headers.ts'
7
7
  import { logger, LogLevel } from './lib/logging.ts'
8
- import { buildNextRequest, RequestData } from './lib/next-request.ts'
8
+ import { buildNextRequest, localizeRequest, RequestData } from './lib/next-request.ts'
9
9
  import { buildResponse, FetchEventResult } from './lib/response.ts'
10
10
  import {
11
11
  getMiddlewareRouteMatcher,
@@ -31,8 +31,8 @@ export async function handleMiddleware(
31
31
  context: Context,
32
32
  nextHandler: NextHandler,
33
33
  ) {
34
- const nextRequest = buildNextRequest(request, context, nextConfig)
35
34
  const url = new URL(request.url)
35
+
36
36
  const reqLogger = logger
37
37
  .withLogLevel(
38
38
  request.headers.has(InternalHeaders.NFDebugLogging) ? LogLevel.Debug : LogLevel.Log,
@@ -40,16 +40,20 @@ export async function handleMiddleware(
40
40
  .withFields({ url_path: url.pathname })
41
41
  .withRequestID(request.headers.get(InternalHeaders.NFRequestID))
42
42
 
43
+ const { localizedUrl } = localizeRequest(url, nextConfig)
43
44
  // While we have already checked the path when mapping to the edge function,
44
45
  // Next.js supports extra rules that we need to check here too, because we
45
46
  // might be running an edge function for a path we should not. If we find
46
47
  // that's the case, short-circuit the execution.
47
- if (!matchesMiddleware(url.pathname, request, searchParamsToUrlQuery(url.searchParams))) {
48
+ if (
49
+ !matchesMiddleware(localizedUrl.pathname, request, searchParamsToUrlQuery(url.searchParams))
50
+ ) {
48
51
  reqLogger.debug('Aborting middleware due to runtime rules')
49
52
 
50
53
  return
51
54
  }
52
55
 
56
+ const nextRequest = buildNextRequest(request, context, nextConfig)
53
57
  try {
54
58
  const result = await nextHandler({ request: nextRequest })
55
59
  const response = await buildResponse({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@netlify/plugin-nextjs",
3
- "version": "5.5.1",
3
+ "version": "5.6.0",
4
4
  "description": "Run Next.js seamlessly on Netlify",
5
5
  "main": "./dist/index.js",
6
6
  "type": "module",