@netlify/plugin-nextjs 4.10.1 → 4.11.2

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.
@@ -70,35 +70,30 @@ const writeEdgeFunction = async ({ edgeFunctionDefinition, edgeFunctionRoot, net
70
70
  * Writes Edge Functions for the Next middleware
71
71
  */
72
72
  const writeEdgeFunctions = async (netlifyConfig) => {
73
- const middlewareManifest = await (0, exports.loadMiddlewareManifest)(netlifyConfig);
74
- if (!middlewareManifest) {
75
- console.error("Couldn't find the middleware manifest");
76
- return;
77
- }
78
73
  const manifest = {
79
74
  functions: [],
80
75
  version: 1,
81
76
  };
82
77
  const edgeFunctionRoot = (0, path_1.resolve)('.netlify', 'edge-functions');
83
78
  await (0, fs_extra_1.emptyDir)(edgeFunctionRoot);
84
- await copyEdgeSourceFile({ edgeFunctionDir: edgeFunctionRoot, file: 'ipx.ts' });
85
- manifest.functions.push({
86
- function: 'ipx',
87
- path: '/_next/image*',
88
- });
89
- for (const middleware of middlewareManifest.sortedMiddleware) {
90
- const edgeFunctionDefinition = middlewareManifest.middleware[middleware];
91
- const functionDefinition = await writeEdgeFunction({
92
- edgeFunctionDefinition,
93
- edgeFunctionRoot,
94
- netlifyConfig,
79
+ if (!process.env.NEXT_DISABLE_EDGE_IMAGES) {
80
+ if (!process.env.NEXT_USE_NETLIFY_EDGE) {
81
+ console.log('Using Netlify Edge Functions for image format detection. Set env var "NEXT_DISABLE_EDGE_IMAGES=true" to disable.');
82
+ }
83
+ await copyEdgeSourceFile({ edgeFunctionDir: edgeFunctionRoot, file: 'ipx.ts' });
84
+ manifest.functions.push({
85
+ function: 'ipx',
86
+ path: '/_next/image*',
95
87
  });
96
- manifest.functions.push(functionDefinition);
97
88
  }
98
- // Older versions of the manifest format don't have the functions field
99
- // No, the version field was not incremented
100
- if (typeof middlewareManifest.functions === 'object') {
101
- for (const edgeFunctionDefinition of Object.values(middlewareManifest.functions)) {
89
+ if (process.env.NEXT_USE_NETLIFY_EDGE) {
90
+ const middlewareManifest = await (0, exports.loadMiddlewareManifest)(netlifyConfig);
91
+ if (!middlewareManifest) {
92
+ console.error("Couldn't find the middleware manifest");
93
+ return;
94
+ }
95
+ for (const middleware of middlewareManifest.sortedMiddleware) {
96
+ const edgeFunctionDefinition = middlewareManifest.middleware[middleware];
102
97
  const functionDefinition = await writeEdgeFunction({
103
98
  edgeFunctionDefinition,
104
99
  edgeFunctionRoot,
@@ -106,6 +101,18 @@ const writeEdgeFunctions = async (netlifyConfig) => {
106
101
  });
107
102
  manifest.functions.push(functionDefinition);
108
103
  }
104
+ // Older versions of the manifest format don't have the functions field
105
+ // No, the version field was not incremented
106
+ if (typeof middlewareManifest.functions === 'object') {
107
+ for (const edgeFunctionDefinition of Object.values(middlewareManifest.functions)) {
108
+ const functionDefinition = await writeEdgeFunction({
109
+ edgeFunctionDefinition,
110
+ edgeFunctionRoot,
111
+ netlifyConfig,
112
+ });
113
+ manifest.functions.push(functionDefinition);
114
+ }
115
+ }
109
116
  }
110
117
  await (0, fs_extra_1.writeJson)((0, path_1.join)(edgeFunctionRoot, 'manifest.json'), manifest);
111
118
  };
@@ -52,15 +52,14 @@ const setupImageFunction = async ({ constants: { INTERNAL_FUNCTIONS_SRC, FUNCTIO
52
52
  });
53
53
  await (0, fs_extra_1.copyFile)((0, pathe_1.join)(__dirname, '..', '..', 'lib', 'templates', 'ipx.js'), (0, pathe_1.join)(functionDirectory, functionName));
54
54
  const imagePath = imageconfig.path || '/_next/image';
55
- // If we have edge, we use content negotiation instead of the redirect
56
- if (!process.env.NEXT_USE_NETLIFY_EDGE) {
57
- netlifyConfig.redirects.push({
58
- from: `${imagePath}*`,
59
- query: { url: ':url', w: ':width', q: ':quality' },
60
- to: `${basePath}/${constants_1.IMAGE_FUNCTION_NAME}/w_:width,q_:quality/:url`,
61
- status: 301,
62
- });
63
- }
55
+ // If we have edge functions then the request will have already been rewritten
56
+ // so this won't match. This is matched if edge is disabled or unavailable.
57
+ netlifyConfig.redirects.push({
58
+ from: `${imagePath}*`,
59
+ query: { url: ':url', w: ':width', q: ':quality' },
60
+ to: `${basePath}/${constants_1.IMAGE_FUNCTION_NAME}/w_:width,q_:quality/:url`,
61
+ status: 301,
62
+ });
64
63
  netlifyConfig.redirects.push({
65
64
  from: `${basePath}/${constants_1.IMAGE_FUNCTION_NAME}/*`,
66
65
  to: `/.netlify/builders/${constants_1.IMAGE_FUNCTION_NAME}`,
package/lib/index.js CHANGED
@@ -86,12 +86,13 @@ const plugin = {
86
86
  nextConfig: { basePath, i18n, trailingSlash, appDir },
87
87
  buildId,
88
88
  });
89
+ // We call this even if we don't have edge functions enabled because we still use it for images
90
+ await (0, edge_1.writeEdgeFunctions)(netlifyConfig);
89
91
  if (process.env.NEXT_USE_NETLIFY_EDGE) {
90
92
  console.log((0, outdent_1.outdent) `
91
93
  ✨ Deploying to ${(0, chalk_1.greenBright) `Netlify Edge Functions`} ✨
92
94
  This feature is in beta. Please share your feedback here: https://ntl.fyi/next-netlify-edge
93
95
  `);
94
- await (0, edge_1.writeEdgeFunctions)(netlifyConfig);
95
96
  await (0, edge_1.updateConfig)(publish);
96
97
  }
97
98
  const middlewareManifest = await (0, edge_1.loadMiddlewareManifest)(netlifyConfig);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@netlify/plugin-nextjs",
3
- "version": "4.10.1",
3
+ "version": "4.11.2",
4
4
  "description": "Run Next.js seamlessly on Netlify",
5
5
  "main": "lib/index.js",
6
6
  "files": [
@@ -10,7 +10,7 @@
10
10
  ],
11
11
  "dependencies": {
12
12
  "@netlify/functions": "^1.0.0",
13
- "@netlify/ipx": "^1.1.2",
13
+ "@netlify/ipx": "^1.1.3",
14
14
  "@vercel/node-bridge": "^2.1.0",
15
15
  "chalk": "^4.1.2",
16
16
  "fs-extra": "^10.0.0",
@@ -22,13 +22,13 @@
22
22
  "p-limit": "^3.1.0",
23
23
  "pathe": "^0.2.0",
24
24
  "pretty-bytes": "^5.6.0",
25
- "semver": "^7.3.5",
26
25
  "slash": "^3.0.0",
26
+ "semver": "^7.3.5",
27
27
  "tiny-glob": "^0.2.9"
28
28
  },
29
29
  "devDependencies": {
30
30
  "@delucis/if-env": "^1.1.2",
31
- "@netlify/build": "^27.3.1",
31
+ "@netlify/build": "^27.3.3",
32
32
  "@types/fs-extra": "^9.0.13",
33
33
  "@types/jest": "^27.4.1",
34
34
  "@types/node": "^17.0.25",
@@ -1,32 +1,57 @@
1
- import { Accepts } from 'https://deno.land/x/accepts/mod.ts'
2
- import type { Context } from 'netlify:edge'
1
+ import { Accepts } from "https://deno.land/x/accepts@2.1.1/mod.ts";
2
+ import type { Context } from "netlify:edge";
3
+ // Available at build time
4
+ import imageconfig from "../functions-internal/_ipx/imageconfig.json" assert {
5
+ type: "json",
6
+ };
7
+
8
+ const defaultFormat = "webp"
9
+
10
+ interface ImageConfig extends Record<string, unknown> {
11
+ formats?: string[];
12
+ }
3
13
 
4
14
  /**
5
15
  * Implement content negotiation for images
6
16
  */
7
17
 
18
+ // deno-lint-ignore require-await
8
19
  const handler = async (req: Request, context: Context) => {
9
- const { searchParams } = new URL(req.url)
10
- const accept = new Accepts(req.headers)
11
- const type = accept.types(['avif', 'webp'])
20
+ const { searchParams } = new URL(req.url);
21
+ const accept = new Accepts(req.headers);
22
+ const { formats = [defaultFormat] } = imageconfig as ImageConfig;
23
+ if (formats.length === 0) {
24
+ formats.push(defaultFormat);
25
+ }
26
+ let type = accept.types(formats) || defaultFormat;
27
+ if(Array.isArray(type)) {
28
+ type = type[0];
29
+ }
30
+
12
31
 
13
- const source = searchParams.get('url')
14
- const width = searchParams.get('w')
15
- const quality = searchParams.get('q') ?? 75
32
+ const source = searchParams.get("url");
33
+ const width = searchParams.get("w");
34
+ const quality = searchParams.get("q") ?? 75;
16
35
 
17
36
  if (!source || !width) {
18
- return new Response('Invalid request', {
37
+ return new Response("Invalid request", {
19
38
  status: 400,
20
- })
39
+ });
21
40
  }
22
41
 
23
- const modifiers = [`w_${width}`, `q_${quality}`]
42
+ const modifiers = [`w_${width}`, `q_${quality}`];
24
43
 
25
44
  if (type) {
26
- modifiers.push(`f_${type}`)
45
+ if(type.includes('/')) {
46
+ // If this is a mimetype, strip "image/"
47
+ type = type.split('/')[1];
48
+ }
49
+ modifiers.push(`f_${type}`);
27
50
  }
51
+ const target = `/_ipx/${modifiers.join(",")}/${encodeURIComponent(source)}`;
52
+ return context.rewrite(
53
+ target,
54
+ );
55
+ };
28
56
 
29
- return context.rewrite(`/_ipx/${modifiers.join(',')}/${encodeURIComponent(source)}`)
30
- }
31
-
32
- export default handler
57
+ export default handler;