@netlify/plugin-nextjs 5.4.0-canary-perf-debug.0 → 5.5.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.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
- ![Next.js Runtime](https://github.com/netlify/next-runtime/raw/main/next-js-runtime.png)
1
+ ![Next.js Runtime](next-js-runtime.png)
2
2
 
3
- # `@netlify/plugin-nextjs`
3
+ # Next.js Runtime
4
4
 
5
5
  <p align="center">
6
6
  <a aria-label="npm version" href="https://www.npmjs.com/package/@netlify/plugin-nextjs">
@@ -16,3 +16,63 @@ Netlify. You should not normally need to install it yourself, as it is used auto
16
16
  builds of Next.js sites. See
17
17
  [the docs for using Next.js on Netlify](https://docs.netlify.com/frameworks/next-js/overview/) for
18
18
  more details.
19
+
20
+ Next.js is supported natively on Netlify, and in most cases you will not need to install or
21
+ configure anything. This repo includes the packages used to support Next.js on Netlify.
22
+
23
+ ## Prerequisites
24
+
25
+ - Next.js 13.5 or later
26
+ - Node.js 18 or later
27
+ - The latest version of the [Netlify CLI](https://docs.netlify.com/cli/get-started/)
28
+
29
+ ## Deploying
30
+
31
+ If you build on Netlify, the Next.js Runtime will work with no additional configuration.
32
+
33
+ ## Manually installing the Next.js Runtime
34
+
35
+ The Next.js Runtime installs automatically for new Next.js sites on Netlify. You can also install it
36
+ manually in the following ways:
37
+
38
+ ### From the UI (Recommended)
39
+
40
+ You can go to the [UI](https://app.netlify.com/plugins/@netlify/plugin-nextjs/install) and choose
41
+ the site to install the Next.js Runtime on. This method is recommended because you will benefit from
42
+ auto-upgrades to important fixes and feature updates.
43
+
44
+ ### From `npm`
45
+
46
+ ```shell
47
+ npm install -D @netlify/plugin-nextjs
48
+ ```
49
+
50
+ ...then add the following to your `netlify.toml` file:
51
+
52
+ ```toml
53
+ [[plugins]]
54
+ package = "@netlify/plugin-nextjs"
55
+ ```
56
+
57
+ This method is recommended if you wish to pin the Next.js Runtime to a specific version.
58
+
59
+ ## v4
60
+
61
+ If you are using Next.js 10-13.4 or Node.js < 18, you must use v4 of the Next.js Runtime.
62
+
63
+ If you are still using v4, you can find
64
+ [its README here](https://github.com/netlify/next-runtime/blob/v4/README.md) and the
65
+ [v4 Runtime docs here](https://docs.netlify.com/frameworks/next-js/runtime-v4/overview/).
66
+
67
+ ### Upgrading from v4 to v5
68
+
69
+ To upgrade from v4 to v5, please visit
70
+ [the v5 documentation](https://docs.netlify.com/frameworks/next-js/overview/).
71
+
72
+ ## Feedback
73
+
74
+ If you think you have found a bug in Next.js on Netlify,
75
+ [please open an issue](https://github.com/netlify/next-runtime/issues). If you have comments or
76
+ feature requests, [see the discussion board](https://github.com/netlify/next-runtime/discussions)
77
+
78
+ Please note that v4 will only receive security fixes and critical bug fixes.
@@ -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,12 @@ 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
+ import {
18
+ require_semver
19
+ } from "../../esm-chunks/chunk-EFGWM7RS.js";
17
20
  import {
18
21
  __toESM
19
22
  } from "../../esm-chunks/chunk-OEQOKJGE.js";
@@ -132,7 +135,9 @@ function pLimit(concurrency) {
132
135
  }
133
136
 
134
137
  // src/build/content/prerendered.ts
138
+ var import_semver = __toESM(require_semver(), 1);
135
139
  import { encodeBlobKey } from "../../shared/blobkey.js";
140
+ import { verifyNetlifyForms } from "../verification.js";
136
141
  var tracer = wrapTracer(trace.getTracer("Next runtime"));
137
142
  var writeCacheEntry = async (route, value, lastModified, ctx) => {
138
143
  const path = join(ctx.blobDir, await encodeBlobKey(route));
@@ -147,21 +152,31 @@ var buildPagesCacheValue = async (path) => ({
147
152
  kind: "PAGE",
148
153
  html: await readFile(`${path}.html`, "utf-8"),
149
154
  pageData: JSON.parse(await readFile(`${path}.json`, "utf-8")),
150
- postponed: void 0,
151
155
  headers: void 0,
152
156
  status: void 0
153
157
  });
154
- var buildAppCacheValue = async (path) => {
158
+ var buildAppCacheValue = async (path, shouldUseAppPageKind) => {
155
159
  const meta = JSON.parse(await readFile(`${path}.meta`, "utf-8"));
160
+ const html = await readFile(`${path}.html`, "utf-8");
161
+ if (shouldUseAppPageKind) {
162
+ return {
163
+ kind: "APP_PAGE",
164
+ html,
165
+ rscData: await readFile(`${path}.rsc`, "base64").catch(
166
+ () => readFile(`${path}.prefetch.rsc`, "base64")
167
+ ),
168
+ ...meta
169
+ };
170
+ }
156
171
  const rsc = await readFile(`${path}.rsc`, "utf-8").catch(
157
172
  () => readFile(`${path}.prefetch.rsc`, "utf-8")
158
173
  );
159
- if (!meta.status && rsc.includes("NEXT_NOT_FOUND")) {
174
+ if (!meta.status && rsc.includes("NEXT_NOT_FOUND") && !meta.headers["x-next-cache-tags"].includes("/@")) {
160
175
  meta.status = 404;
161
176
  }
162
177
  return {
163
178
  kind: "PAGE",
164
- html: await readFile(`${path}.html`, "utf-8"),
179
+ html,
165
180
  pageData: rsc,
166
181
  ...meta
167
182
  };
@@ -182,6 +197,9 @@ var copyPrerenderedContent = async (ctx) => {
182
197
  await mkdir(ctx.blobDir, { recursive: true });
183
198
  const manifest = await ctx.getPrerenderManifest();
184
199
  const limitConcurrentPrerenderContentHandling = pLimit(10);
200
+ const shouldUseAppPageKind = ctx.nextVersion ? (0, import_semver.satisfies)(ctx.nextVersion, ">=15.0.0-canary.13 <15.0.0-d || >15.0.0-rc.0", {
201
+ includePrerelease: true
202
+ }) : false;
185
203
  await Promise.all(
186
204
  Object.entries(manifest.routes).map(
187
205
  ([route, meta]) => limitConcurrentPrerenderContentHandling(async () => {
@@ -198,7 +216,10 @@ var copyPrerenderedContent = async (ctx) => {
198
216
  value = await buildPagesCacheValue(join(ctx.publishDir, "server/pages", key));
199
217
  break;
200
218
  case meta.dataRoute?.endsWith(".rsc"):
201
- value = await buildAppCacheValue(join(ctx.publishDir, "server/app", key));
219
+ value = await buildAppCacheValue(
220
+ join(ctx.publishDir, "server/app", key),
221
+ shouldUseAppPageKind
222
+ );
202
223
  break;
203
224
  case meta.dataRoute === null:
204
225
  value = await buildRouteCacheValue(
@@ -209,6 +230,9 @@ var copyPrerenderedContent = async (ctx) => {
209
230
  default:
210
231
  throw new Error(`Unrecognized content: ${route}`);
211
232
  }
233
+ if (value.kind === "PAGE" || value.kind === "APP_PAGE") {
234
+ verifyNetlifyForms(ctx, value.html);
235
+ }
212
236
  await writeCacheEntry(key, value, lastModified, ctx);
213
237
  })
214
238
  )
@@ -216,7 +240,10 @@ var copyPrerenderedContent = async (ctx) => {
216
240
  if (existsSync(join(ctx.publishDir, `server/app/_not-found.html`))) {
217
241
  const lastModified = Date.now();
218
242
  const key = "/404";
219
- const value = await buildAppCacheValue(join(ctx.publishDir, "server/app/_not-found"));
243
+ const value = await buildAppCacheValue(
244
+ join(ctx.publishDir, "server/app/_not-found"),
245
+ shouldUseAppPageKind
246
+ );
220
247
  await writeCacheEntry(key, value, lastModified, ctx);
221
248
  }
222
249
  } catch (error) {
@@ -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";
@@ -28,8 +28,8 @@ import {
28
28
  access,
29
29
  cp,
30
30
  mkdir,
31
- readFile,
32
31
  readdir,
32
+ readFile,
33
33
  readlink,
34
34
  symlink,
35
35
  writeFile
@@ -40,8 +40,6 @@ import { join as posixJoin, sep as posixSep } from "node:path/posix";
40
40
  var import_fast_glob = __toESM(require_out(), 1);
41
41
  var import_semver = __toESM(require_semver(), 1);
42
42
  import { RUN_CONFIG } from "../../run/constants.js";
43
- import { logger } from "../../run/systemlog.cjs";
44
- import { verifyNextVersion } from "../verification.js";
45
43
  var tracer = wrapTracer(trace.getTracer("Next runtime"));
46
44
  var toPosixPath = (path) => path.split(sep).join(posixSep);
47
45
  function isError(error) {
@@ -192,17 +190,8 @@ var copyNextDependencies = async (ctx) => {
192
190
  }
193
191
  await Promise.all(promises);
194
192
  const serverHandlerRequire = createRequire(posixJoin(ctx.serverHandlerDir, ":internal:"));
195
- let nextVersion;
196
- try {
197
- const { version } = serverHandlerRequire("next/package.json");
198
- if (version) {
199
- nextVersion = version;
200
- }
201
- } catch {
202
- }
203
- if (nextVersion) {
204
- verifyNextVersion(ctx, nextVersion);
205
- await patchNextModules(ctx, nextVersion, serverHandlerRequire.resolve);
193
+ if (ctx.nextVersion) {
194
+ await patchNextModules(ctx, ctx.nextVersion, serverHandlerRequire.resolve);
206
195
  }
207
196
  try {
208
197
  const nextEntryAbsolutePath = serverHandlerRequire.resolve("next");
@@ -215,36 +204,6 @@ var copyNextDependencies = async (ctx) => {
215
204
  }
216
205
  });
217
206
  };
218
- var writeTagsManifest = async (ctx) => {
219
- const manifest = await ctx.getPrerenderManifest();
220
- const routes = Object.entries(manifest.routes).map(async ([route, definition]) => {
221
- let tags;
222
- if (definition.dataRoute?.endsWith(".rsc")) {
223
- const path = join(ctx.publishDir, `server/app/${route === "/" ? "/index" : route}.meta`);
224
- try {
225
- const file = await readFile(path, "utf-8");
226
- const meta = JSON.parse(file);
227
- tags = meta.headers["x-next-cache-tags"];
228
- } catch {
229
- if (!definition.dataRoute?.endsWith("/default.rsc")) {
230
- logger.log(`Unable to read cache tags for: ${path}`);
231
- }
232
- }
233
- }
234
- if (definition.dataRoute?.endsWith(".json")) {
235
- tags = `_N_T_${route}`;
236
- }
237
- if (definition.dataRoute === null) {
238
- tags = definition.initialHeaders?.["x-next-cache-tags"];
239
- }
240
- return [route, tags];
241
- });
242
- await writeFile(
243
- join(ctx.serverHandlerDir, ".netlify/tags-manifest.json"),
244
- JSON.stringify(Object.fromEntries(await Promise.all(routes))),
245
- "utf-8"
246
- );
247
- };
248
207
  var replaceMiddlewareManifest = async (sourcePath, destPath) => {
249
208
  await mkdir(dirname(destPath), { recursive: true });
250
209
  const data = await readFile(sourcePath, "utf8");
@@ -269,6 +228,5 @@ export {
269
228
  copyNextDependencies,
270
229
  copyNextServerCode,
271
230
  getPatchesToApply,
272
- verifyHandlerDirStructure,
273
- writeTagsManifest
231
+ verifyHandlerDirStructure
274
232
  };
@@ -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";
@@ -21,10 +21,11 @@ import {
21
21
  // src/build/content/static.ts
22
22
  init_esm();
23
23
  import { existsSync } from "node:fs";
24
- import { cp, mkdir, rename, rm } from "node:fs/promises";
24
+ 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 { verifyNetlifyForms } from "../verification.js";
28
29
  var tracer = wrapTracer(trace.getTracer("Next runtime"));
29
30
  var copyStaticContent = async (ctx) => {
30
31
  return tracer.withActiveSpan("copyStaticContent", async () => {
@@ -35,12 +36,12 @@ var copyStaticContent = async (ctx) => {
35
36
  extglob: true
36
37
  });
37
38
  try {
39
+ await mkdir(destDir, { recursive: true });
38
40
  await Promise.all(
39
41
  paths.filter((path) => !paths.includes(`${path.slice(0, -5)}.json`)).map(async (path) => {
40
- await cp(join(srcDir, path), join(destDir, await encodeBlobKey(path)), {
41
- recursive: true,
42
- force: true
43
- });
42
+ const html = await readFile(join(srcDir, path), "utf-8");
43
+ verifyNetlifyForms(ctx, html);
44
+ await writeFile(join(destDir, await encodeBlobKey(path)), html, "utf-8");
44
45
  })
45
46
  );
46
47
  } catch (error) {
@@ -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";
@@ -27,8 +27,7 @@ var import_fast_glob = __toESM(require_out(), 1);
27
27
  import {
28
28
  copyNextDependencies,
29
29
  copyNextServerCode,
30
- verifyHandlerDirStructure,
31
- writeTagsManifest
30
+ verifyHandlerDirStructure
32
31
  } from "../content/server.js";
33
32
  import { SERVER_HANDLER_NAME } from "../plugin-context.js";
34
33
  var tracer = wrapTracer(trace.getTracer("Next runtime"));
@@ -128,7 +127,6 @@ var createServerHandler = async (ctx) => {
128
127
  await mkdir(join(ctx.serverHandlerDir, ".netlify"), { recursive: true });
129
128
  await copyNextServerCode(ctx);
130
129
  await copyNextDependencies(ctx);
131
- await writeTagsManifest(ctx);
132
130
  await copyHandlerDependencies(ctx);
133
131
  await writeHandlerManifest(ctx);
134
132
  await writePackageMetadata(ctx);
@@ -15,7 +15,9 @@ import {
15
15
  var import_semver = __toESM(require_semver(), 1);
16
16
  import { existsSync, readFileSync } from "node:fs";
17
17
  import { readFile } from "node:fs/promises";
18
+ import { createRequire } from "node:module";
18
19
  import { join, relative, resolve } from "node:path";
20
+ import { join as posixJoin } from "node:path/posix";
19
21
  import { fileURLToPath } from "node:url";
20
22
  var MODULE_DIR = fileURLToPath(new URL(".", import.meta.url));
21
23
  var PLUGIN_DIR = join(MODULE_DIR, "../..");
@@ -248,6 +250,22 @@ var PluginContext = class {
248
250
  async getRoutesManifest() {
249
251
  return JSON.parse(await readFile(join(this.publishDir, "routes-manifest.json"), "utf-8"));
250
252
  }
253
+ #nextVersion = void 0;
254
+ /**
255
+ * Get Next.js version that was used to build the site
256
+ */
257
+ get nextVersion() {
258
+ if (this.#nextVersion === void 0) {
259
+ try {
260
+ const serverHandlerRequire = createRequire(posixJoin(this.standaloneRootDir, ":internal:"));
261
+ const { version } = serverHandlerRequire("next/package.json");
262
+ this.#nextVersion = version;
263
+ } catch {
264
+ this.#nextVersion = null;
265
+ }
266
+ }
267
+ return this.#nextVersion;
268
+ }
251
269
  /** Fails a build with a message and an optional error */
252
270
  failBuild(message, error) {
253
271
  return this.utils.build.failBuild(message, error instanceof Error ? { error } : void 0);
@@ -1,4 +1,3 @@
1
- import { enableModuleImportTracing } from '{{cwd}}/.netlify/dist/run/handlers/import-time-debug.cjs'
2
1
  import {
3
2
  createRequestContext,
4
3
  runWithRequestContext,
@@ -11,17 +10,13 @@ process.chdir('{{cwd}}')
11
10
  // Set feature flag for regional blobs
12
11
  process.env.USE_REGIONAL_BLOBS = '{{useRegionalBlobs}}'
13
12
 
14
- if (process.env.NETLIFY_OTLP_TRACE_EXPORTER_URL || process.env.NETLIFY_NEXT_PERF_DEBUG) {
15
- tracing.start()
16
- }
17
-
18
- if (process.env.NETLIFY_NEXT_PERF_DEBUG) {
19
- enableModuleImportTracing()
20
- }
21
-
22
13
  let cachedHandler
23
14
  export default async function (req, context) {
24
- const requestContext = createRequestContext(req.headers.get('x-next-debug-logging'))
15
+ if (process.env.NETLIFY_OTLP_TRACE_EXPORTER_URL) {
16
+ tracing.start()
17
+ }
18
+
19
+ const requestContext = createRequestContext(req)
25
20
  const tracer = getTracer()
26
21
 
27
22
  const handlerResponse = await runWithRequestContext(requestContext, () => {
@@ -1,4 +1,3 @@
1
- import { enableModuleImportTracing } from './.netlify/dist/run/handlers/import-time-debug.cjs'
2
1
  import {
3
2
  createRequestContext,
4
3
  runWithRequestContext,
@@ -10,16 +9,11 @@ import tracing from './.netlify/dist/run/handlers/tracing.js'
10
9
  // Set feature flag for regional blobs
11
10
  process.env.USE_REGIONAL_BLOBS = '{{useRegionalBlobs}}'
12
11
 
13
- if (process.env.NETLIFY_OTLP_TRACE_EXPORTER_URL || process.env.NETLIFY_NEXT_PERF_DEBUG) {
14
- tracing.start()
15
- }
16
-
17
- if (process.env.NETLIFY_NEXT_PERF_DEBUG) {
18
- enableModuleImportTracing()
19
- }
20
-
21
12
  export default async function handler(req, context) {
22
- const requestContext = createRequestContext(req.headers.get('x-next-debug-logging'))
13
+ if (process.env.NETLIFY_OTLP_TRACE_EXPORTER_URL) {
14
+ tracing.start()
15
+ }
16
+ const requestContext = createRequestContext(req)
23
17
  const tracer = getTracer()
24
18
 
25
19
  const handlerResponse = await runWithRequestContext(requestContext, () => {
@@ -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,11 +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";
25
+ var verifications = /* @__PURE__ */ new Set();
20
26
  function verifyPublishDir(ctx) {
21
27
  if (!existsSync(ctx.publishDir)) {
22
28
  ctx.failBuild(
@@ -46,6 +52,11 @@ function verifyPublishDir(ctx) {
46
52
  `Your publish directory does not contain expected Next.js build output. Please make sure you are using Next.js version (${SUPPORTED_NEXT_VERSIONS})`
47
53
  );
48
54
  }
55
+ if (ctx.nextVersion && !(0, import_semver.satisfies)(ctx.nextVersion, SUPPORTED_NEXT_VERSIONS, { includePrerelease: true })) {
56
+ ctx.failBuild(
57
+ `@netlify/plugin-nextjs@5 requires Next.js version ${SUPPORTED_NEXT_VERSIONS}, but found ${ctx.nextVersion}. Please upgrade your project's Next.js version.`
58
+ );
59
+ }
49
60
  }
50
61
  if (ctx.buildConfig.output === "export") {
51
62
  if (!ctx.exportDetail?.success) {
@@ -58,29 +69,50 @@ function verifyPublishDir(ctx) {
58
69
  }
59
70
  }
60
71
  }
61
- function verifyNextVersion(ctx, nextVersion) {
62
- if (!(0, import_semver.satisfies)(nextVersion, SUPPORTED_NEXT_VERSIONS, { includePrerelease: true })) {
63
- ctx.failBuild(
64
- `@netlify/plugin-next@5 requires Next.js version ${SUPPORTED_NEXT_VERSIONS}, but found ${nextVersion}. Please upgrade your project's Next.js version.`
65
- );
66
- }
67
- }
68
- async function verifyNoAdvancedAPIRoutes(ctx) {
72
+ async function verifyAdvancedAPIRoutes(ctx) {
69
73
  const apiRoutesConfigs = await getAPIRoutesConfigs(ctx);
70
74
  const unsupportedAPIRoutes = apiRoutesConfigs.filter((apiRouteConfig) => {
71
75
  return apiRouteConfig.config.type === ApiRouteType.BACKGROUND || apiRouteConfig.config.type === ApiRouteType.SCHEDULED;
72
76
  });
73
77
  if (unsupportedAPIRoutes.length !== 0) {
74
78
  ctx.failBuild(
75
- `@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:
76
80
  ${unsupportedAPIRoutes.map((apiRouteConfig) => ` - ${apiRouteConfig.apiRoute} (type: "${apiRouteConfig.config.type}")`).join("\n")}
77
81
 
78
82
  Refer to https://ntl.fyi/next-scheduled-bg-function-migration as migration example.`
79
83
  );
80
84
  }
81
85
  }
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)) {
107
+ console.warn(
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
+ );
110
+ verifications.add("netlifyForms");
111
+ }
112
+ }
82
113
  export {
83
- verifyNextVersion,
84
- verifyNoAdvancedAPIRoutes,
114
+ verifyAdvancedAPIRoutes,
115
+ verifyNetlifyForms,
116
+ verifyNetlifyFormsWorkaround,
85
117
  verifyPublishDir
86
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-canary-perf-debug.0";
11
+ var version = "5.5.0";
12
12
  var description = "Run Next.js seamlessly on Netlify";
13
13
  var main = "./dist/index.js";
14
14
  var type = "module";
@@ -42,7 +42,7 @@ var scripts = {
42
42
  };
43
43
  var repository = {
44
44
  type: "git",
45
- url: "git+https://github.com/netlify/next-runtime-minimal.git"
45
+ url: "git+https://github.com/netlify/next-runtime.git"
46
46
  };
47
47
  var keywords = [
48
48
  "nextjs",
@@ -52,19 +52,19 @@ var keywords = [
52
52
  ];
53
53
  var license = "MIT";
54
54
  var bugs = {
55
- url: "https://github.com/netlify/next-runtime-minimal/issues"
55
+ url: "https://github.com/netlify/next-runtime/issues"
56
56
  };
57
- var homepage = "https://github.com/netlify/next-runtime-minimal#readme";
57
+ 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.42.2",
62
- "@netlify/edge-bundler": "^12.0.1",
61
+ "@netlify/build": "^29.50.2",
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.7.0",
66
- "@netlify/serverless-functions-api": "^1.18.2",
67
- "@netlify/zip-it-and-ship-it": "^9.33.0",
65
+ "@netlify/functions": "^2.8.0",
66
+ "@netlify/serverless-functions-api": "^1.18.5",
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",
@@ -87,7 +87,7 @@ var devDependencies = {
87
87
  memfs: "^4.9.2",
88
88
  "mock-require": "^3.0.3",
89
89
  msw: "^2.0.7",
90
- next: "^14.0.4",
90
+ next: "^15.0.0-canary.28",
91
91
  os: "^0.1.2",
92
92
  outdent: "^0.8.0",
93
93
  "p-limit": "^5.0.0",
package/dist/index.js CHANGED
@@ -29,7 +29,11 @@ import { createEdgeHandlers } from "./build/functions/edge.js";
29
29
  import { 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 () => {
@@ -56,7 +60,8 @@ var onBuild = async (options) => {
56
60
  if (ctx.buildConfig.output === "export") {
57
61
  return copyStaticExport(ctx);
58
62
  }
59
- await verifyNoAdvancedAPIRoutes(ctx);
63
+ await verifyAdvancedAPIRoutes(ctx);
64
+ await verifyNetlifyFormsWorkaround(ctx);
60
65
  await Promise.all([
61
66
  copyStaticAssets(ctx),
62
67
  copyStaticContent(ctx),
@@ -21,17 +21,15 @@ var setRunConfig = (config) => {
21
21
  }
22
22
  config.experimental = {
23
23
  ...config.experimental,
24
+ // @ts-expect-error incrementalCacheHandlerPath was removed from config type
25
+ // but we still need to set it for older Next.js versions
24
26
  incrementalCacheHandlerPath: cacheHandler
25
27
  };
26
28
  config.cacheHandler = cacheHandler;
27
29
  config.cacheMaxMemorySize = 0;
28
30
  process.env.__NEXT_PRIVATE_STANDALONE_CONFIG = JSON.stringify(config);
29
31
  };
30
- var getTagsManifest = async () => {
31
- return JSON.parse(await readFile(resolve(PLUGIN_DIR, ".netlify/tags-manifest.json"), "utf-8"));
32
- };
33
32
  export {
34
33
  getRunConfig,
35
- getTagsManifest,
36
34
  setRunConfig
37
35
  };