@netlify/plugin-nextjs 5.8.0 → 5.8.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.
@@ -147,11 +147,19 @@ var writeCacheEntry = async (route, value, lastModified, ctx) => {
147
147
  });
148
148
  await writeFile(path, entry, "utf-8");
149
149
  };
150
- var routeToFilePath = (path) => path === "/" ? "/index" : path;
151
- var buildPagesCacheValue = async (path, shouldUseEnumKind) => ({
150
+ var routeToFilePath = (path) => {
151
+ if (path === "/") {
152
+ return "/index";
153
+ }
154
+ if (path.startsWith("/")) {
155
+ return path;
156
+ }
157
+ return `/${path}`;
158
+ };
159
+ var buildPagesCacheValue = async (path, shouldUseEnumKind, shouldSkipJson = false) => ({
152
160
  kind: shouldUseEnumKind ? "PAGES" : "PAGE",
153
161
  html: await readFile(`${path}.html`, "utf-8"),
154
- pageData: JSON.parse(await readFile(`${path}.json`, "utf-8")),
162
+ pageData: shouldSkipJson ? {} : JSON.parse(await readFile(`${path}.json`, "utf-8")),
155
163
  headers: void 0,
156
164
  status: void 0
157
165
  });
@@ -203,8 +211,8 @@ var copyPrerenderedContent = async (ctx) => {
203
211
  const shouldUseEnumKind = ctx.nextVersion ? (0, import_semver.satisfies)(ctx.nextVersion, ">=15.0.0-canary.114 <15.0.0-d || >15.0.0-rc.0", {
204
212
  includePrerelease: true
205
213
  }) : false;
206
- await Promise.all(
207
- Object.entries(manifest.routes).map(
214
+ await Promise.all([
215
+ ...Object.entries(manifest.routes).map(
208
216
  ([route, meta]) => limitConcurrentPrerenderContentHandling(async () => {
209
217
  const lastModified = meta.initialRevalidateSeconds ? Date.now() - 31536e6 : Date.now();
210
218
  const key = routeToFilePath(route);
@@ -243,8 +251,18 @@ var copyPrerenderedContent = async (ctx) => {
243
251
  }
244
252
  await writeCacheEntry(key, value, lastModified, ctx);
245
253
  })
246
- )
247
- );
254
+ ),
255
+ ...ctx.getFallbacks(manifest).map(async (route) => {
256
+ const key = routeToFilePath(route);
257
+ const value = await buildPagesCacheValue(
258
+ join(ctx.publishDir, "server/pages", key),
259
+ shouldUseEnumKind,
260
+ true
261
+ // there is no corresponding json file for fallback, so we are skipping it for this entry
262
+ );
263
+ await writeCacheEntry(key, value, Date.now(), ctx);
264
+ })
265
+ ]);
248
266
  if (existsSync(join(ctx.publishDir, `server/app/_not-found.html`))) {
249
267
  const lastModified = Date.now();
250
268
  const key = "/404";
@@ -35,13 +35,19 @@ var copyStaticContent = async (ctx) => {
35
35
  cwd: srcDir,
36
36
  extglob: true
37
37
  });
38
+ const fallbacks = ctx.getFallbacks(await ctx.getPrerenderManifest());
38
39
  try {
39
40
  await mkdir(destDir, { recursive: true });
40
41
  await Promise.all(
41
42
  paths.filter((path) => !paths.includes(`${path.slice(0, -5)}.json`)).map(async (path) => {
42
43
  const html = await readFile(join(srcDir, path), "utf-8");
43
44
  verifyNetlifyForms(ctx, html);
44
- await writeFile(join(destDir, await encodeBlobKey(path)), html, "utf-8");
45
+ const isFallback = fallbacks.includes(path.slice(0, -5));
46
+ await writeFile(
47
+ join(destDir, await encodeBlobKey(path)),
48
+ JSON.stringify({ html, isFallback }),
49
+ "utf-8"
50
+ );
45
51
  })
46
52
  );
47
53
  } catch (error) {
@@ -266,6 +266,32 @@ var PluginContext = class {
266
266
  }
267
267
  return this.#nextVersion;
268
268
  }
269
+ #fallbacks = null;
270
+ /**
271
+ * Get an array of localized fallback routes
272
+ *
273
+ * Example return value for non-i18n site: `['blog/[slug]']`
274
+ *
275
+ * Example return value for i18n site: `['en/blog/[slug]', 'fr/blog/[slug]']`
276
+ */
277
+ getFallbacks(prerenderManifest) {
278
+ if (!this.#fallbacks) {
279
+ const locales = this.buildConfig.i18n?.locales ?? [""];
280
+ this.#fallbacks = Object.entries(prerenderManifest.dynamicRoutes).reduce(
281
+ (fallbacks, [route, meta]) => {
282
+ if (typeof meta.fallback === "string") {
283
+ for (const locale of locales) {
284
+ const localizedRoute = posixJoin(locale, route.replace(/^\/+/g, ""));
285
+ fallbacks.push(localizedRoute);
286
+ }
287
+ }
288
+ return fallbacks;
289
+ },
290
+ []
291
+ );
292
+ }
293
+ return this.#fallbacks;
294
+ }
269
295
  /** Fails a build with a message and an optional error */
270
296
  failBuild(message, error) {
271
297
  return this.utils.build.failBuild(message, error instanceof Error ? { error } : void 0);
@@ -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.8.0";
11
+ var version = "5.8.1";
12
12
  var description = "Run Next.js seamlessly on Netlify";
13
13
  var main = "./dist/index.js";
14
14
  var type = "module";
@@ -57,14 +57,14 @@ var bugs = {
57
57
  var homepage = "https://github.com/netlify/next-runtime#readme";
58
58
  var devDependencies = {
59
59
  "@fastly/http-compute-js": "1.1.4",
60
- "@netlify/blobs": "^8.0.1",
61
- "@netlify/build": "^29.55.2",
60
+ "@netlify/blobs": "^8.1.0",
61
+ "@netlify/build": "^29.55.3",
62
62
  "@netlify/edge-bundler": "^12.2.3",
63
63
  "@netlify/edge-functions": "^2.11.0",
64
64
  "@netlify/eslint-config-node": "^7.0.1",
65
65
  "@netlify/functions": "^2.8.2",
66
66
  "@netlify/serverless-functions-api": "^1.30.1",
67
- "@netlify/zip-it-and-ship-it": "^9.40.2",
67
+ "@netlify/zip-it-and-ship-it": "^9.41.0",
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,6 +87,7 @@ var devDependencies = {
87
87
  memfs: "^4.9.2",
88
88
  "mock-require": "^3.0.3",
89
89
  msw: "^2.0.7",
90
+ "netlify-cli": "^17.37.1",
90
91
  next: "^15.0.0-canary.28",
91
92
  os: "^0.1.2",
92
93
  outdent: "^0.8.0",
@@ -68866,7 +68866,7 @@ var import_semantic_conventions = __toESM(require_src(), 1);
68866
68866
  import { getLogger } from "./request-context.cjs";
68867
68867
  var {
68868
68868
  default: { version, name }
68869
- } = await import("../../esm-chunks/package-4GFWM3PF.js");
68869
+ } = await import("../../esm-chunks/package-AOKLDA5E.js");
68870
68870
  var sdk = new import_sdk_node.NodeSDK({
68871
68871
  resource: new import_resources.Resource({
68872
68872
  [import_semantic_conventions.SEMRESATTRS_SERVICE_NAME]: name,
@@ -174,13 +174,13 @@ var setCacheControlHeaders = ({ headers, status }, request, requestContext) => {
174
174
  headers.set("netlify-cdn-cache-control", cdnCacheControl);
175
175
  return;
176
176
  }
177
- if (cacheControl === null && !headers.has("cdn-cache-control") && !headers.has("netlify-cdn-cache-control") && requestContext.usedFsRead) {
177
+ if (cacheControl === null && !headers.has("cdn-cache-control") && !headers.has("netlify-cdn-cache-control") && requestContext.usedFsReadForNonFallback) {
178
178
  headers.set("cache-control", "public, max-age=0, must-revalidate");
179
179
  headers.set("netlify-cdn-cache-control", `max-age=31536000, durable`);
180
180
  }
181
181
  };
182
182
  var setCacheTagsHeaders = (headers, requestContext) => {
183
- if (requestContext.responseCacheTags) {
183
+ if (requestContext.responseCacheTags && (headers.has("cache-control") || headers.has("netlify-cdn-cache-control"))) {
184
184
  headers.set("netlify-cache-tag", requestContext.responseCacheTags.join(","));
185
185
  }
186
186
  };
package/dist/run/next.cjs CHANGED
@@ -554,13 +554,17 @@ async function getMockedRequestHandlers(...args) {
554
554
  if (typeof path === "string" && path.endsWith(".html")) {
555
555
  const store = (0, import_regional_blob_store.getRegionalBlobStore)();
556
556
  const relPath = (0, import_path.relative)((0, import_path.resolve)(".next/server/pages"), path);
557
- const file = await store.get(await encodeBlobKey(relPath));
557
+ const file = await store.get(await encodeBlobKey(relPath), {
558
+ type: "json"
559
+ });
558
560
  if (file !== null) {
559
- const requestContext = (0, import_request_context.getRequestContext)();
560
- if (requestContext) {
561
- requestContext.usedFsRead = true;
561
+ if (!file.isFallback) {
562
+ const requestContext = (0, import_request_context.getRequestContext)();
563
+ if (requestContext) {
564
+ requestContext.usedFsReadForNonFallback = true;
565
+ }
562
566
  }
563
- return file;
567
+ return file.html;
564
568
  }
565
569
  }
566
570
  throw error;
@@ -601,7 +601,7 @@ var getDeployStore = (input = {}) => {
601
601
  if (clientOptions.edgeURL || clientOptions.uncachedEdgeURL) {
602
602
  if (!context.primaryRegion) {
603
603
  throw new Error(
604
- "When accessing a deploy store, the Netlify Blobs client needs to be configured with a region, and one was not found in the environment. To manually set the region, set the `region` property in the `getDeployStore` options."
604
+ "When accessing a deploy store, the Netlify Blobs client needs to be configured with a region, and one was not found in the environment. To manually set the region, set the `region` property in the `getDeployStore` options. If you are using the Netlify CLI, you may have an outdated version; run `npm install -g netlify-cli@latest` to update and try again."
605
605
  );
606
606
  }
607
607
  clientOptions.region = context.primaryRegion;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@netlify/plugin-nextjs",
3
- "version": "5.8.0",
3
+ "version": "5.8.1",
4
4
  "description": "Run Next.js seamlessly on Netlify",
5
5
  "main": "./dist/index.js",
6
6
  "type": "module",