From 3c6f421d99452fc7b978a6a3539585ff29e92c8f Mon Sep 17 00:00:00 2001 From: Steven Date: Sat, 24 Oct 2020 08:53:28 -0400 Subject: [PATCH] Add docs for Image Optimization (#18107) Co-authored-by: Lee Robinson Co-authored-by: Tim Neutkens --- docs/api-reference/next/image.md | 53 ++++++++++ docs/basic-features/image-optimization.md | 113 +++++++++++++++++++++ examples/image-component/.gitignore | 34 +++++++ examples/image-component/README.md | 23 +++++ examples/image-component/next.config.js | 5 + examples/image-component/package.json | 15 +++ examples/image-component/pages/index.js | 57 +++++++++++ examples/image-component/public/vercel.png | Bin 0 -> 30079 bytes examples/image-component/styles.module.css | 34 +++++++ 9 files changed, 334 insertions(+) create mode 100644 docs/api-reference/next/image.md create mode 100644 docs/basic-features/image-optimization.md create mode 100644 examples/image-component/.gitignore create mode 100644 examples/image-component/README.md create mode 100644 examples/image-component/next.config.js create mode 100644 examples/image-component/package.json create mode 100644 examples/image-component/pages/index.js create mode 100644 examples/image-component/public/vercel.png create mode 100644 examples/image-component/styles.module.css diff --git a/docs/api-reference/next/image.md b/docs/api-reference/next/image.md new file mode 100644 index 000000000000000..8fa4a86e7538846 --- /dev/null +++ b/docs/api-reference/next/image.md @@ -0,0 +1,53 @@ +--- +description: Enable image optimization with the built-in Image component. +--- + +# next/image + +
+ Examples + +
+ +> Before moving forward, we recommend you to read [Image Optimization](/docs/basic-features/image-optimization.md) first. + +Image Optimization can be enabled via the `Image` component exported by `next/image`. + +For an example, consider a project with the following files: + +- `pages/index.js` +- `public/me.png` + +We can serve an optimized image like so: + +```jsx +import Image from 'next/image' + +function Home() { + return ( + <> +

My Homepage

+ me +

Welcome to my homepage!

+ + ) +} + +export default Home +``` + +`Image` accepts the following props: + +- `src` - The path or URL to the source image. This is required. +- `width` - The intrinsic width of the source image in pixels. Must be an integer without a unit. Required unless `unsized` is true. +- `height` - The intrinsic height of the source image, in pixels. Must be an integer without a unit. Required unless `unsized` is true. +- `sizes` - Defines what proportion of the screen you expect the image to take up. Recommended, as it helps serve the correct sized image to each device. [More info](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#attr-sizes). +- `quality` - The quality of the optimized image, an integer between 1 and 100 where 100 is the best quality. Default 100. +- `loading` - The loading behavior. When `lazy`, defer loading the image until it reaches a calculated distance from the viewport. When `eager`, load the image immediately. Default `lazy`. [More info](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#attr-loading) +- `priority` - When true, the image will be considered high priority and [preload](https://web.dev/preload-responsive-images/). +- `unoptimized` - When true, the source image will be served as-is instead of resizing and changing quality. +- `unsized` - When true, the `width` and `height` requirement can by bypassed. Should _not_ be used with `priority` or above-the-fold images. + +Another other properties on the `` component be passed to the underlying `` element. diff --git a/docs/basic-features/image-optimization.md b/docs/basic-features/image-optimization.md new file mode 100644 index 000000000000000..77b6f85c4a615fd --- /dev/null +++ b/docs/basic-features/image-optimization.md @@ -0,0 +1,113 @@ +--- +description: Next.js supports built-in image optimization, as well as third party loaders for Imgix, Cloudinary, and more! Learn more here. +--- + +# Image Optimization + +
+ Examples + +
+ +Since version **10.0.0** Next.js has a built-in Image Component and Automatic Image Optimization. + +The Next.js Image Component (`next/image`) is an extension of the HTML `` element, evolved for the modern web. + +The Automatic Image Optimization allows for resizing, optimizing, and serving images in modern formats like [WebP](https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Image_types). This avoids shipping large images to devices with a smaller viewport. + +## Image Component + +To add an image to your application, import the `next/image` component: + +```jsx +import Image from 'next/image' + +function Home() { + return ( + <> +

My Homepage

+ Picture of the author +

Welcome to my homepage!

+ + ) +} + +export default Home +``` + +- `width` and `height` are required to prevent [Cumulative Layout Shift](https://web.dev/cls/), a [Core Web Vital](https://web.dev/vitals/) that Google is going to [use in their search ranking](https://webmasters.googleblog.com/2020/05/evaluating-page-experience.html) +- `width` and `height` are automatically responsive, unlike the HTML `` element + +## Configuration + +You can configure Image Optimization by using the `images` property in `next.config.js`. + +### Sizes + +You can specify a list of image widths to allow using the `sizes` property. Since images maintain their aspect ratio using the `width` and `height` attributes of the source image, there is no need to specify height in `next.config.js` – only the width. You can think of these as breakpoints. + +```js +module.exports = { + images: { + sizes: [320, 420, 768, 1024, 1200], + }, +} +``` + +### Domains + +To enable Image Optimization for images hosted on an external website, use an absolute url for the Image `src` and specify which +`domains` are allowed to be optimized. This is needed to ensure that external urls can't be abused. + +```js +module.exports = { + images: { + domains: ['example.com'], + }, +} +``` + +### Loader + +If you want to use a cloud image provider to optimize images instead of using the Next.js' built-in image optimization, you can configure the loader and path prefix. This allows you to use relative urls for the Image `src` and automatically generate the correct absolute url for your provider. + +```js +module.exports = { + images: { + loader: 'imgix', + path: 'https://example.com/myaccount/', + }, +} +``` + +The following Image Optimization cloud providers are supported: + +- Imgix: `loader: 'imgix'` +- Cloudinary: `loader: 'cloudinary'` +- Akamai: `loader: 'akamai'` +- Vercel: No configuration necessary + +## Related + +For more information on what to do next, we recommend the following sections: + + + +
+- When using `next start` or a custom server image optimization works automatically. +- [Vercel](https://vercel.com): Works automatically when you deploy on Vercel +- [Imgix](https://www.imgix.com): `loader: 'imgix'` +- [Cloudinary](https://cloudinary.com): `loader: 'cloudinary'` +- [Akamai](https://www.akamai.com): `loader: 'akamai'` diff --git a/examples/image-component/.gitignore b/examples/image-component/.gitignore new file mode 100644 index 000000000000000..1437c53f70bc211 --- /dev/null +++ b/examples/image-component/.gitignore @@ -0,0 +1,34 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env.local +.env.development.local +.env.test.local +.env.production.local + +# vercel +.vercel diff --git a/examples/image-component/README.md b/examples/image-component/README.md new file mode 100644 index 000000000000000..93f1a5bb78f2170 --- /dev/null +++ b/examples/image-component/README.md @@ -0,0 +1,23 @@ +# Image Component Example + +This example shows how to use the [Image Component in Next.js](https://nextjs.org/docs/api-reference/next/image) serve optimized, responsive images. + +The index page ([`pages/index.js`](pages/index.js)) has a couple images, one internal image and one external image. In [`next.config.js`](next.config.js), the `domains` property is used to enable external images. Run or deploy the app to see how it works! + +## Deploy your own + +Deploy the example using [Vercel](https://vercel.com): + +[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/import/project?template=https://github.com/vercel/next.js/tree/canary/examples/image-component) + +## How to use + +Execute [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init) or [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/) to bootstrap the example: + +```bash +npx create-next-app --example image-component image-app +# or +yarn create next-app --example image-component image-app +``` + +Deploy it to the cloud with [Vercel](https://vercel.com/import?filter=next.js&utm_source=github&utm_medium=readme&utm_campaign=next-example) ([Documentation](https://nextjs.org/docs/deployment)). diff --git a/examples/image-component/next.config.js b/examples/image-component/next.config.js new file mode 100644 index 000000000000000..a2abb2bc484e699 --- /dev/null +++ b/examples/image-component/next.config.js @@ -0,0 +1,5 @@ +module.exports = { + images: { + domains: ['assets.vercel.com'], + }, +} diff --git a/examples/image-component/package.json b/examples/image-component/package.json new file mode 100644 index 000000000000000..23c6c7e74db8ed7 --- /dev/null +++ b/examples/image-component/package.json @@ -0,0 +1,15 @@ +{ + "name": "rewrites", + "version": "1.0.0", + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start" + }, + "dependencies": { + "next": "latest", + "react": "^16.13.1", + "react-dom": "^16.13.1" + }, + "license": "MIT" +} diff --git a/examples/image-component/pages/index.js b/examples/image-component/pages/index.js new file mode 100644 index 000000000000000..faf642b77d6bef4 --- /dev/null +++ b/examples/image-component/pages/index.js @@ -0,0 +1,57 @@ +import styles from '../styles.module.css' +import Image from 'next/image' + +const Code = (p) => + +const Index = () => ( +
+
+

Image Component with Next.js

+

+ The images below use the{' '} + + <Image> + {' '} + component to ensure optimal format and size for this browser. +

+

+ Images are also lazy loaded by default which means they don't load until + scrolled into view. +

+

Try scolling down to try it out!

+
+

+ The following is an example of a reference to an interal image from the{' '} + public directory. +

+

+ Notice that the image is responsive. As you adjust your browser width, a + different sized image is loaded. +

+ Vercel logo +
+

+ The following is an example of a reference to an external image at{' '} + assets.vercel.com. +

+

+ External domains must be configured in next.config.js using + the domains. +

+ Next.js logo +
+ Checkout the documentation for{' '} + + Image Optimization + {' '} + to learn more. +
+
+) + +export default Index diff --git a/examples/image-component/public/vercel.png b/examples/image-component/public/vercel.png new file mode 100644 index 0000000000000000000000000000000000000000..cb137a989e5ffe5fe01eee70a4ad7a6e1798094a GIT binary patch literal 30079 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