Skip to content
This repository was archived by the owner on May 10, 2021. It is now read-only.

Commit b4c85b9

Browse files
initial support for next/image on netlify (#138)
* initial support for next/image on netlify * copy change to next/image caveat in readme Co-authored-by: Jason Lengstorf <[email protected]> Co-authored-by: Jason Lengstorf <[email protected]>
1 parent 853983b commit b4c85b9

14 files changed

+616
-28
lines changed

README.md

+6
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ The plugin can be found on [npm here](https://www.npmjs.com/package/@netlify/plu
5050
- [Using Netlify Identity](#using-netlify-identity)
5151
- [Caveats](#caveats)
5252
- [Fallbacks for Pages with `getStaticPaths`](#fallbacks-for-pages-with-getstaticpaths)
53+
- [next/image](#next/image)
5354
- [Credits](#credits)
5455
- [Showcase](#showcase)
5556

@@ -256,6 +257,11 @@ With `next-on-netlify`, when navigating to a path that is not defined in `getSta
256257

257258
For more on this, see: [Issue #7](https://github.com/netlify/next-on-netlify/issues/7#issuecomment-636883539)
258259

260+
### next/image
261+
262+
Our existing solution for next/image is not very performant. We have performance improvements on our roadmap, dependent on internal work.
263+
264+
To get better performance now, we recommend using a cloud provider like Cloudinary ([see the Next.js docs](https://nextjs.org/docs/basic-features/image-optimization#loader)).
259265

260266
## Credits
261267

index.js

+3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ const prepareFolders = require("./lib/steps/prepareFolders");
22
const copyPublicFiles = require("./lib/steps/copyPublicFiles");
33
const copyNextAssets = require("./lib/steps/copyNextAssets");
44
const setupPages = require("./lib/steps/setupPages");
5+
const setupImageFunction = require("./lib/steps/setupImageFunction");
56
const setupRedirects = require("./lib/steps/setupRedirects");
67
const {
78
NETLIFY_PUBLISH_PATH,
@@ -26,6 +27,8 @@ const nextOnNetlify = (options = {}) => {
2627

2728
setupPages({ functionsPath, publishPath });
2829

30+
setupImageFunction(functionsPath);
31+
2932
setupRedirects(publishPath);
3033
};
3134

lib/config.js

+5
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ const FUNCTION_TEMPLATE_PATH = join(TEMPLATES_DIR, "netlifyFunction.js");
2828
// This is the file where custom redirects can be configured
2929
const CUSTOM_REDIRECTS_PATH = join(".", "_redirects");
3030

31+
// This is the name used for copying our imageFunction template and for
32+
// creating the next/image redirect
33+
const NEXT_IMAGE_FUNCTION_NAME = "next_image";
34+
3135
module.exports = {
3236
NETLIFY_PUBLISH_PATH,
3337
NETLIFY_FUNCTIONS_PATH,
@@ -37,4 +41,5 @@ module.exports = {
3741
TEMPLATES_DIR,
3842
FUNCTION_TEMPLATE_PATH,
3943
CUSTOM_REDIRECTS_PATH,
44+
NEXT_IMAGE_FUNCTION_NAME,
4045
};

lib/steps/setupImageFunction.js

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
const { copySync } = require("fs-extra");
2+
const { join } = require("path");
3+
const { NEXT_IMAGE_FUNCTION_NAME, TEMPLATES_DIR } = require("../config");
4+
5+
// Move our next/image function into the correct functions directory
6+
const setupImageFunction = (functionsPath) => {
7+
const functionName = `${NEXT_IMAGE_FUNCTION_NAME}.js`;
8+
const functionDirectory = join(functionsPath, functionName);
9+
10+
copySync(join(TEMPLATES_DIR, "imageFunction.js"), functionDirectory, {
11+
overwrite: false,
12+
errorOnExist: true,
13+
});
14+
};
15+
16+
module.exports = setupImageFunction;

lib/steps/setupRedirects.js

+11-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
const { join } = require("path");
22
const { existsSync, readFileSync, writeFileSync } = require("fs-extra");
33
const { logTitle, logItem } = require("../helpers/logger");
4-
const { CUSTOM_REDIRECTS_PATH } = require("../config");
4+
const {
5+
CUSTOM_REDIRECTS_PATH,
6+
NEXT_IMAGE_FUNCTION_NAME,
7+
} = require("../config");
58
const getSortedRoutes = require("../helpers/getSortedRoutes");
69
const getNetlifyRoutes = require("../helpers/getNetlifyRoutes");
710
const isRootCatchAllRedirect = require("../helpers/isRootCatchAllRedirect");
@@ -29,8 +32,14 @@ const setupRedirects = (publishPath) => {
2932
...require("../pages/withoutProps/redirects"),
3033
];
3134

35+
// Add next/image redirect to our image function
36+
nextRedirects.push({
37+
route: "/_next/image* url=:url w=:width q=:quality",
38+
target: `/.netlify/functions/${NEXT_IMAGE_FUNCTION_NAME}?url=:url&w=:width&q=:quality`,
39+
});
40+
3241
// Add _redirect section heading
33-
if (nextRedirects.length >= 1) redirects.push("# Next-on-Netlify Redirects");
42+
redirects.push("# Next-on-Netlify Redirects");
3443

3544
// Sort routes: More-specific routes (e.g., static routing) precede
3645
// less-specific routes (e.g., catch-all)

lib/templates/imageFunction.js

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
const jimp = require("jimp");
2+
3+
// Function used to mimic next/image and sharp
4+
exports.handler = async (event) => {
5+
const { url, w = 500, q = 75 } = event.queryStringParameters;
6+
const width = parseInt(w);
7+
const quality = parseInt(q);
8+
9+
const imageUrl = url.startsWith("/")
10+
? `${process.env.URL || "http://localhost:8888"}${url}`
11+
: url;
12+
const image = await jimp.read(imageUrl);
13+
14+
image.resize(width, jimp.AUTO).quality(quality);
15+
16+
const imageBuffer = await image.getBufferAsync(image.getMIME());
17+
18+
return {
19+
statusCode: 200,
20+
headers: {
21+
"Content-Type": image.getMIME(),
22+
},
23+
body: imageBuffer.toString("base64"),
24+
isBase64Encoded: true,
25+
};
26+
};

0 commit comments

Comments
 (0)