@netlify/plugin-nextjs 5.4.0 → 5.5.1

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.
@@ -4,9 +4,6 @@
4
4
  return createRequire(import.meta.url);
5
5
  })();
6
6
 
7
- import {
8
- require_out
9
- } from "../../esm-chunks/chunk-FHR56UHE.js";
10
7
  import {
11
8
  wrapTracer
12
9
  } from "../../esm-chunks/chunk-5QSXBV7L.js";
@@ -14,6 +11,9 @@ import {
14
11
  init_esm,
15
12
  trace
16
13
  } from "../../esm-chunks/chunk-GNGHTHMQ.js";
14
+ import {
15
+ require_out
16
+ } from "../../esm-chunks/chunk-FHR56UHE.js";
17
17
  import {
18
18
  require_semver
19
19
  } from "../../esm-chunks/chunk-EFGWM7RS.js";
@@ -137,7 +137,7 @@ function pLimit(concurrency) {
137
137
  // src/build/content/prerendered.ts
138
138
  var import_semver = __toESM(require_semver(), 1);
139
139
  import { encodeBlobKey } from "../../shared/blobkey.js";
140
- import { verifyNoNetlifyForms } from "../verification.js";
140
+ import { verifyNetlifyForms } from "../verification.js";
141
141
  var tracer = wrapTracer(trace.getTracer("Next runtime"));
142
142
  var writeCacheEntry = async (route, value, lastModified, ctx) => {
143
143
  const path = join(ctx.blobDir, await encodeBlobKey(route));
@@ -231,7 +231,7 @@ var copyPrerenderedContent = async (ctx) => {
231
231
  throw new Error(`Unrecognized content: ${route}`);
232
232
  }
233
233
  if (value.kind === "PAGE" || value.kind === "APP_PAGE") {
234
- verifyNoNetlifyForms(ctx, value.html);
234
+ verifyNetlifyForms(ctx, value.html);
235
235
  }
236
236
  await writeCacheEntry(key, value, lastModified, ctx);
237
237
  })
@@ -4,9 +4,6 @@
4
4
  return createRequire(import.meta.url);
5
5
  })();
6
6
 
7
- import {
8
- require_out
9
- } from "../../esm-chunks/chunk-FHR56UHE.js";
10
7
  import {
11
8
  wrapTracer
12
9
  } from "../../esm-chunks/chunk-5QSXBV7L.js";
@@ -14,6 +11,9 @@ import {
14
11
  init_esm,
15
12
  trace
16
13
  } from "../../esm-chunks/chunk-GNGHTHMQ.js";
14
+ import {
15
+ require_out
16
+ } from "../../esm-chunks/chunk-FHR56UHE.js";
17
17
  import {
18
18
  require_semver
19
19
  } from "../../esm-chunks/chunk-EFGWM7RS.js";
@@ -4,9 +4,6 @@
4
4
  return createRequire(import.meta.url);
5
5
  })();
6
6
 
7
- import {
8
- require_out
9
- } from "../../esm-chunks/chunk-FHR56UHE.js";
10
7
  import {
11
8
  wrapTracer
12
9
  } from "../../esm-chunks/chunk-5QSXBV7L.js";
@@ -14,6 +11,9 @@ import {
14
11
  init_esm,
15
12
  trace
16
13
  } from "../../esm-chunks/chunk-GNGHTHMQ.js";
14
+ import {
15
+ require_out
16
+ } from "../../esm-chunks/chunk-FHR56UHE.js";
17
17
  import {
18
18
  __toESM
19
19
  } from "../../esm-chunks/chunk-OEQOKJGE.js";
@@ -25,7 +25,7 @@ import { cp, mkdir, readFile, rename, rm, writeFile } from "node:fs/promises";
25
25
  import { basename, join } from "node:path";
26
26
  var import_fast_glob = __toESM(require_out(), 1);
27
27
  import { encodeBlobKey } from "../../shared/blobkey.js";
28
- import { verifyNoNetlifyForms } from "../verification.js";
28
+ import { verifyNetlifyForms } from "../verification.js";
29
29
  var tracer = wrapTracer(trace.getTracer("Next runtime"));
30
30
  var copyStaticContent = async (ctx) => {
31
31
  return tracer.withActiveSpan("copyStaticContent", async () => {
@@ -40,7 +40,7 @@ var copyStaticContent = async (ctx) => {
40
40
  await Promise.all(
41
41
  paths.filter((path) => !paths.includes(`${path.slice(0, -5)}.json`)).map(async (path) => {
42
42
  const html = await readFile(join(srcDir, path), "utf-8");
43
- verifyNoNetlifyForms(ctx, html);
43
+ verifyNetlifyForms(ctx, html);
44
44
  await writeFile(join(destDir, await encodeBlobKey(path)), html, "utf-8");
45
45
  })
46
46
  );
@@ -501,8 +501,10 @@ var buildHandlerDefinition = (ctx, { name, matchers, page }) => {
501
501
  generator
502
502
  }));
503
503
  };
504
- var createEdgeHandlers = async (ctx) => {
504
+ var clearStaleEdgeHandlers = async (ctx) => {
505
505
  await rm(ctx.edgeFunctionsDir, { recursive: true, force: true });
506
+ };
507
+ var createEdgeHandlers = async (ctx) => {
506
508
  const nextManifest = await ctx.getMiddlewareManifest();
507
509
  const nextDefinitions = [
508
510
  ...Object.values(nextManifest.middleware)
@@ -517,5 +519,6 @@ var createEdgeHandlers = async (ctx) => {
517
519
  await writeEdgeManifest(ctx, netlifyManifest);
518
520
  };
519
521
  export {
522
+ clearStaleEdgeHandlers,
520
523
  createEdgeHandlers
521
524
  };
@@ -4,9 +4,6 @@
4
4
  return createRequire(import.meta.url);
5
5
  })();
6
6
 
7
- import {
8
- require_out
9
- } from "../../esm-chunks/chunk-FHR56UHE.js";
10
7
  import {
11
8
  wrapTracer
12
9
  } from "../../esm-chunks/chunk-5QSXBV7L.js";
@@ -14,6 +11,9 @@ import {
14
11
  init_esm,
15
12
  trace
16
13
  } from "../../esm-chunks/chunk-GNGHTHMQ.js";
14
+ import {
15
+ require_out
16
+ } from "../../esm-chunks/chunk-FHR56UHE.js";
17
17
  import {
18
18
  __toESM
19
19
  } from "../../esm-chunks/chunk-OEQOKJGE.js";
@@ -121,9 +121,11 @@ var writeHandlerFile = async (ctx) => {
121
121
  const handler = await getHandlerFile(ctx);
122
122
  await writeFile(join(ctx.serverHandlerRootDir, `${SERVER_HANDLER_NAME}.mjs`), handler);
123
123
  };
124
+ var clearStaleServerHandlers = async (ctx) => {
125
+ await rm(ctx.serverFunctionsDir, { recursive: true, force: true });
126
+ };
124
127
  var createServerHandler = async (ctx) => {
125
128
  await tracer.withActiveSpan("createServerHandler", async () => {
126
- await rm(ctx.serverFunctionsDir, { recursive: true, force: true });
127
129
  await mkdir(join(ctx.serverHandlerDir, ".netlify"), { recursive: true });
128
130
  await copyNextServerCode(ctx);
129
131
  await copyNextDependencies(ctx);
@@ -135,5 +137,6 @@ var createServerHandler = async (ctx) => {
135
137
  });
136
138
  };
137
139
  export {
140
+ clearStaleServerHandlers,
138
141
  createServerHandler
139
142
  };
@@ -4,6 +4,9 @@
4
4
  return createRequire(import.meta.url);
5
5
  })();
6
6
 
7
+ import {
8
+ require_out
9
+ } from "../esm-chunks/chunk-FHR56UHE.js";
7
10
  import {
8
11
  require_semver
9
12
  } from "../esm-chunks/chunk-EFGWM7RS.js";
@@ -12,12 +15,14 @@ import {
12
15
  } from "../esm-chunks/chunk-OEQOKJGE.js";
13
16
 
14
17
  // src/build/verification.ts
18
+ var import_fast_glob = __toESM(require_out(), 1);
15
19
  var import_semver = __toESM(require_semver(), 1);
16
20
  import { existsSync } from "node:fs";
21
+ import { readFile } from "node:fs/promises";
17
22
  import { join } from "node:path";
18
23
  import { ApiRouteType, getAPIRoutesConfigs } from "./advanced-api-routes.js";
19
24
  var SUPPORTED_NEXT_VERSIONS = ">=13.5.0";
20
- var warnings = /* @__PURE__ */ new Set();
25
+ var verifications = /* @__PURE__ */ new Set();
21
26
  function verifyPublishDir(ctx) {
22
27
  if (!existsSync(ctx.publishDir)) {
23
28
  ctx.failBuild(
@@ -49,7 +54,7 @@ function verifyPublishDir(ctx) {
49
54
  }
50
55
  if (ctx.nextVersion && !(0, import_semver.satisfies)(ctx.nextVersion, SUPPORTED_NEXT_VERSIONS, { includePrerelease: true })) {
51
56
  ctx.failBuild(
52
- `@netlify/plugin-next@5 requires Next.js version ${SUPPORTED_NEXT_VERSIONS}, but found ${ctx.nextVersion}. Please upgrade your project's Next.js version.`
57
+ `@netlify/plugin-nextjs@5 requires Next.js version ${SUPPORTED_NEXT_VERSIONS}, but found ${ctx.nextVersion}. Please upgrade your project's Next.js version.`
53
58
  );
54
59
  }
55
60
  }
@@ -64,30 +69,50 @@ function verifyPublishDir(ctx) {
64
69
  }
65
70
  }
66
71
  }
67
- async function verifyNoAdvancedAPIRoutes(ctx) {
72
+ async function verifyAdvancedAPIRoutes(ctx) {
68
73
  const apiRoutesConfigs = await getAPIRoutesConfigs(ctx);
69
74
  const unsupportedAPIRoutes = apiRoutesConfigs.filter((apiRouteConfig) => {
70
75
  return apiRouteConfig.config.type === ApiRouteType.BACKGROUND || apiRouteConfig.config.type === ApiRouteType.SCHEDULED;
71
76
  });
72
77
  if (unsupportedAPIRoutes.length !== 0) {
73
78
  ctx.failBuild(
74
- `@netlify/plugin-next@5 does not support advanced API routes. The following API routes should be migrated to Netlify background or scheduled functions:
79
+ `@netlify/plugin-nextjs@5 does not support advanced API routes. The following API routes should be migrated to Netlify background or scheduled functions:
75
80
  ${unsupportedAPIRoutes.map((apiRouteConfig) => ` - ${apiRouteConfig.apiRoute} (type: "${apiRouteConfig.config.type}")`).join("\n")}
76
81
 
77
82
  Refer to https://ntl.fyi/next-scheduled-bg-function-migration as migration example.`
78
83
  );
79
84
  }
80
85
  }
81
- function verifyNoNetlifyForms(ctx, html) {
82
- if (!warnings.has("netlifyForms") && /<form[^>]*?\s(netlify|data-netlify)[=>\s]/.test(html)) {
86
+ var formDetectionRegex = /<form[^>]*?\s(netlify|data-netlify)[=>\s]/;
87
+ async function verifyNetlifyFormsWorkaround(ctx) {
88
+ const srcDir = ctx.resolveFromSiteDir("public");
89
+ const paths = await (0, import_fast_glob.glob)("**/*.html", {
90
+ cwd: srcDir,
91
+ dot: true
92
+ });
93
+ try {
94
+ for (const path of paths) {
95
+ const html = await readFile(join(srcDir, path), "utf-8");
96
+ if (formDetectionRegex.test(html)) {
97
+ verifications.add("netlifyFormsWorkaround");
98
+ return;
99
+ }
100
+ }
101
+ } catch (error) {
102
+ ctx.failBuild("Failed verifying public files", error);
103
+ }
104
+ }
105
+ function verifyNetlifyForms(ctx, html) {
106
+ if (!verifications.has("netlifyForms") && !verifications.has("netlifyFormsWorkaround") && formDetectionRegex.test(html)) {
83
107
  console.warn(
84
- "@netlify/plugin-next@5 does not support Netlify Forms. Refer to https://ntl.fyi/next-runtime-forms-migration for migration example."
108
+ "@netlify/plugin-nextjs@5 requires migration steps to support Netlify Forms. Refer to https://ntl.fyi/next-runtime-forms-migration for migration example."
85
109
  );
86
- warnings.add("netlifyForms");
110
+ verifications.add("netlifyForms");
87
111
  }
88
112
  }
89
113
  export {
90
- verifyNoAdvancedAPIRoutes,
91
- verifyNoNetlifyForms,
114
+ verifyAdvancedAPIRoutes,
115
+ verifyNetlifyForms,
116
+ verifyNetlifyFormsWorkaround,
92
117
  verifyPublishDir
93
118
  };
@@ -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.4.0";
11
+ var version = "5.5.1";
12
12
  var description = "Run Next.js seamlessly on Netlify";
13
13
  var main = "./dist/index.js";
14
14
  var type = "module";
@@ -58,13 +58,13 @@ var homepage = "https://github.com/netlify/next-runtime#readme";
58
58
  var devDependencies = {
59
59
  "@fastly/http-compute-js": "1.1.4",
60
60
  "@netlify/blobs": "^7.3.0",
61
- "@netlify/build": "^29.50.1",
61
+ "@netlify/build": "^29.50.2",
62
62
  "@netlify/edge-bundler": "^12.1.1",
63
63
  "@netlify/edge-functions": "^2.8.1",
64
64
  "@netlify/eslint-config-node": "^7.0.1",
65
- "@netlify/functions": "^2.8.0",
66
- "@netlify/serverless-functions-api": "^1.18.5",
67
- "@netlify/zip-it-and-ship-it": "^9.37.2",
65
+ "@netlify/functions": "^2.8.1",
66
+ "@netlify/serverless-functions-api": "^1.19.1",
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",
70
70
  "@opentelemetry/resources": "^1.24.0",
package/dist/index.js CHANGED
@@ -25,11 +25,15 @@ import {
25
25
  publishStaticDir,
26
26
  unpublishStaticDir
27
27
  } from "./build/content/static.js";
28
- import { createEdgeHandlers } from "./build/functions/edge.js";
29
- import { createServerHandler } from "./build/functions/server.js";
28
+ import { clearStaleEdgeHandlers, createEdgeHandlers } from "./build/functions/edge.js";
29
+ import { clearStaleServerHandlers, createServerHandler } from "./build/functions/server.js";
30
30
  import { setImageConfig } from "./build/image-cdn.js";
31
31
  import { PluginContext } from "./build/plugin-context.js";
32
- import { verifyNoAdvancedAPIRoutes, verifyPublishDir } from "./build/verification.js";
32
+ import {
33
+ verifyAdvancedAPIRoutes,
34
+ verifyNetlifyFormsWorkaround,
35
+ verifyPublishDir
36
+ } from "./build/verification.js";
33
37
  var tracer = wrapTracer(trace.getTracer("Next.js runtime"));
34
38
  var onPreDev = async (options) => {
35
39
  await tracer.withActiveSpan("onPreDev", async () => {
@@ -40,8 +44,12 @@ var onPreDev = async (options) => {
40
44
  var onPreBuild = async (options) => {
41
45
  await tracer.withActiveSpan("onPreBuild", async () => {
42
46
  process.env.NEXT_PRIVATE_STANDALONE = "true";
43
- if (!options.constants.IS_LOCAL) {
44
- await restoreBuildCache(new PluginContext(options));
47
+ const ctx = new PluginContext(options);
48
+ if (options.constants.IS_LOCAL) {
49
+ await clearStaleServerHandlers(ctx);
50
+ await clearStaleEdgeHandlers(ctx);
51
+ } else {
52
+ await restoreBuildCache(ctx);
45
53
  }
46
54
  });
47
55
  };
@@ -56,7 +64,8 @@ var onBuild = async (options) => {
56
64
  if (ctx.buildConfig.output === "export") {
57
65
  return copyStaticExport(ctx);
58
66
  }
59
- await verifyNoAdvancedAPIRoutes(ctx);
67
+ await verifyAdvancedAPIRoutes(ctx);
68
+ await verifyNetlifyFormsWorkaround(ctx);
60
69
  await Promise.all([
61
70
  copyStaticAssets(ctx),
62
71
  copyStaticContent(ctx),
@@ -3161,7 +3161,8 @@ var server_default = async (request, context) => {
3161
3161
  span.setAttribute("responseCacheKey", requestContext.responseCacheKey);
3162
3162
  }
3163
3163
  await adjustDateHeader({ headers: response.headers, request, span, tracer, requestContext });
3164
- setCacheControlHeaders(response.headers, request, requestContext);
3164
+ const useDurableCache = context.flags.get("serverless_functions_nextjs_durable_cache_disable") !== true;
3165
+ setCacheControlHeaders(response.headers, request, requestContext, useDurableCache);
3165
3166
  setCacheTagsHeaders(response.headers, requestContext);
3166
3167
  setVaryHeaders(response.headers, request, nextConfig);
3167
3168
  setCacheStatusHeader(response.headers);
@@ -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-7DG4KM7X.js");
67388
+ } = await import("../../esm-chunks/package-SHOGGUO3.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,
@@ -51,11 +51,6 @@ var omitHeaderValues = (header, values) => {
51
51
  );
52
52
  return filteredValues.join(", ");
53
53
  };
54
- var mapHeaderValues = (header, callback) => {
55
- const headerValues = getHeaderValueArray(header);
56
- const mappedValues = headerValues.map(callback);
57
- return mappedValues.join(", ");
58
- };
59
54
  var setVaryHeaders = (headers, request, { basePath, i18n }) => {
60
55
  const netlifyVaryValues = {
61
56
  header: ["x-nextjs-data", "x-next-debug-logging"],
@@ -147,11 +142,12 @@ var adjustDateHeader = async ({
147
142
  headers.set("x-nextjs-date", headers.get("date") ?? lastModifiedDate.toUTCString());
148
143
  headers.set("date", lastModifiedDate.toUTCString());
149
144
  };
150
- var setCacheControlHeaders = (headers, request, requestContext) => {
145
+ var setCacheControlHeaders = (headers, request, requestContext, useDurableCache) => {
146
+ const durableCacheDirective = useDurableCache ? ", durable" : "";
151
147
  if (typeof requestContext.routeHandlerRevalidate !== "undefined" && ["GET", "HEAD"].includes(request.method) && !headers.has("cdn-cache-control") && !headers.has("netlify-cdn-cache-control")) {
152
148
  const cdnCacheControl = (
153
149
  // if we are serving already stale response, instruct edge to not attempt to cache that response
154
- headers.get("x-nextjs-cache") === "STALE" ? "public, max-age=0, must-revalidate" : `s-maxage=${requestContext.routeHandlerRevalidate === false ? 31536e3 : requestContext.routeHandlerRevalidate}, stale-while-revalidate=31536000`
150
+ headers.get("x-nextjs-cache") === "STALE" ? "public, max-age=0, must-revalidate" : `s-maxage=${requestContext.routeHandlerRevalidate === false ? 31536e3 : requestContext.routeHandlerRevalidate}, stale-while-revalidate=31536000${durableCacheDirective}`
155
151
  );
156
152
  headers.set("netlify-cdn-cache-control", cdnCacheControl);
157
153
  return;
@@ -164,10 +160,12 @@ var setCacheControlHeaders = (headers, request, requestContext) => {
164
160
  ]);
165
161
  const cdnCacheControl = (
166
162
  // if we are serving already stale response, instruct edge to not attempt to cache that response
167
- headers.get("x-nextjs-cache") === "STALE" ? "public, max-age=0, must-revalidate" : mapHeaderValues(
168
- cacheControl,
169
- (value) => value === "stale-while-revalidate" ? "stale-while-revalidate=31536000" : value
170
- )
163
+ headers.get("x-nextjs-cache") === "STALE" ? "public, max-age=0, must-revalidate" : [
164
+ ...getHeaderValueArray(cacheControl).map(
165
+ (value) => value === "stale-while-revalidate" ? "stale-while-revalidate=31536000" : value
166
+ ),
167
+ ...useDurableCache ? ["durable"] : []
168
+ ].join(", ")
171
169
  );
172
170
  headers.set("cache-control", browserCacheControl || "public, max-age=0, must-revalidate");
173
171
  headers.set("netlify-cdn-cache-control", cdnCacheControl);
@@ -175,7 +173,7 @@ var setCacheControlHeaders = (headers, request, requestContext) => {
175
173
  }
176
174
  if (cacheControl === null && !headers.has("cdn-cache-control") && !headers.has("netlify-cdn-cache-control") && requestContext.usedFsRead) {
177
175
  headers.set("cache-control", "public, max-age=0, must-revalidate");
178
- headers.set("netlify-cdn-cache-control", `max-age=31536000`);
176
+ headers.set("netlify-cdn-cache-control", `max-age=31536000${durableCacheDirective}`);
179
177
  }
180
178
  };
181
179
  var setCacheTagsHeaders = (headers, requestContext) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@netlify/plugin-nextjs",
3
- "version": "5.4.0",
3
+ "version": "5.5.1",
4
4
  "description": "Run Next.js seamlessly on Netlify",
5
5
  "main": "./dist/index.js",
6
6
  "type": "module",