@netlify/plugin-nextjs 4.10.0 → 4.11.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.
- package/lib/helpers/edge.js +28 -21
- package/lib/helpers/functions.js +8 -9
- package/lib/index.js +4 -2
- package/package.json +4 -4
- package/src/templates/edge/ipx.ts +36 -16
package/lib/helpers/edge.js
CHANGED
|
@@ -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
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
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
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
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
|
};
|
package/lib/helpers/functions.js
CHANGED
|
@@ -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
|
|
56
|
-
if
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
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
|
@@ -34,6 +34,7 @@ const plugin = {
|
|
|
34
34
|
netlifyConfig.build.environment.NEXT_PRIVATE_TARGET = 'server';
|
|
35
35
|
},
|
|
36
36
|
async onBuild({ constants, netlifyConfig, utils: { build: { failBuild }, }, }) {
|
|
37
|
+
var _a;
|
|
37
38
|
if ((0, utils_1.shouldSkip)()) {
|
|
38
39
|
return;
|
|
39
40
|
}
|
|
@@ -85,16 +86,17 @@ const plugin = {
|
|
|
85
86
|
nextConfig: { basePath, i18n, trailingSlash, appDir },
|
|
86
87
|
buildId,
|
|
87
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);
|
|
88
91
|
if (process.env.NEXT_USE_NETLIFY_EDGE) {
|
|
89
92
|
console.log((0, outdent_1.outdent) `
|
|
90
93
|
✨ Deploying to ${(0, chalk_1.greenBright) `Netlify Edge Functions`} ✨
|
|
91
94
|
This feature is in beta. Please share your feedback here: https://ntl.fyi/next-netlify-edge
|
|
92
95
|
`);
|
|
93
|
-
await (0, edge_1.writeEdgeFunctions)(netlifyConfig);
|
|
94
96
|
await (0, edge_1.updateConfig)(publish);
|
|
95
97
|
}
|
|
96
98
|
const middlewareManifest = await (0, edge_1.loadMiddlewareManifest)(netlifyConfig);
|
|
97
|
-
if (!process.env.NEXT_USE_NETLIFY_EDGE && middlewareManifest.sortedMiddleware
|
|
99
|
+
if (!process.env.NEXT_USE_NETLIFY_EDGE && ((_a = middlewareManifest === null || middlewareManifest === void 0 ? void 0 : middlewareManifest.sortedMiddleware) === null || _a === void 0 ? void 0 : _a.length)) {
|
|
98
100
|
console.log((0, chalk_1.yellowBright)((0, outdent_1.outdent) `
|
|
99
101
|
You are using Next.js Middleware without Netlify Edge Functions.
|
|
100
102
|
This will soon be deprecated because it negatively affects performance and will disable ISR and static rendering.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@netlify/plugin-nextjs",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.11.1",
|
|
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.
|
|
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.
|
|
31
|
+
"@netlify/build": "^27.3.2",
|
|
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,52 @@
|
|
|
1
|
-
import { Accepts } from
|
|
2
|
-
import type { Context } from
|
|
1
|
+
import { Accepts } from "https://deno.land/x/accepts@2.1.1/mod.ts";
|
|
2
|
+
import type { Context } from "netlify:edge";
|
|
3
|
+
import imageconfig from "../functions-internal/_ipx/imageconfig.json" assert {
|
|
4
|
+
type: "json",
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
const defaultFormat = "webp"
|
|
3
8
|
|
|
4
9
|
/**
|
|
5
10
|
* Implement content negotiation for images
|
|
6
11
|
*/
|
|
7
12
|
|
|
13
|
+
// deno-lint-ignore require-await
|
|
8
14
|
const handler = async (req: Request, context: Context) => {
|
|
9
|
-
const { searchParams } = new URL(req.url)
|
|
10
|
-
const accept = new Accepts(req.headers)
|
|
11
|
-
const
|
|
15
|
+
const { searchParams } = new URL(req.url);
|
|
16
|
+
const accept = new Accepts(req.headers);
|
|
17
|
+
const { formats = [defaultFormat] } = imageconfig;
|
|
18
|
+
if (formats.length === 0) {
|
|
19
|
+
formats.push(defaultFormat);
|
|
20
|
+
}
|
|
21
|
+
let type = accept.types(formats) || defaultFormat;
|
|
22
|
+
if(Array.isArray(type)) {
|
|
23
|
+
type = type[0];
|
|
24
|
+
}
|
|
12
25
|
|
|
13
|
-
|
|
14
|
-
const
|
|
15
|
-
const
|
|
26
|
+
|
|
27
|
+
const source = searchParams.get("url");
|
|
28
|
+
const width = searchParams.get("w");
|
|
29
|
+
const quality = searchParams.get("q") ?? 75;
|
|
16
30
|
|
|
17
31
|
if (!source || !width) {
|
|
18
|
-
return new Response(
|
|
32
|
+
return new Response("Invalid request", {
|
|
19
33
|
status: 400,
|
|
20
|
-
})
|
|
34
|
+
});
|
|
21
35
|
}
|
|
22
36
|
|
|
23
|
-
const modifiers = [`w_${width}`, `q_${quality}`]
|
|
37
|
+
const modifiers = [`w_${width}`, `q_${quality}`];
|
|
24
38
|
|
|
25
39
|
if (type) {
|
|
26
|
-
|
|
40
|
+
if(type.includes('/')) {
|
|
41
|
+
// If this is a mimetype, strip "image/"
|
|
42
|
+
type = type.split('/')[1];
|
|
43
|
+
}
|
|
44
|
+
modifiers.push(`f_${type}`);
|
|
27
45
|
}
|
|
46
|
+
const target = `/_ipx/${modifiers.join(",")}/${encodeURIComponent(source)}`;
|
|
47
|
+
return context.rewrite(
|
|
48
|
+
target,
|
|
49
|
+
);
|
|
50
|
+
};
|
|
28
51
|
|
|
29
|
-
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export default handler
|
|
52
|
+
export default handler;
|