Skip to content

Commit

Permalink
Merge branch 'canary' into docs/add-i18n-manifest-item
Browse files Browse the repository at this point in the history
  • Loading branch information
Timer authored Oct 27, 2020
2 parents 30ed292 + 2972c06 commit 88809bb
Show file tree
Hide file tree
Showing 43 changed files with 483 additions and 115 deletions.
36 changes: 21 additions & 15 deletions docs/basic-features/image-optimization.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
description: Next.js supports built-in image optimization, as well as third party loaders for Imgix, Cloudinary, and more! Learn more here.
---

# Image Optimization
# Image Component and Image Optimization

<details open>
<summary><b>Examples</b></summary>
Expand Down Expand Up @@ -50,14 +50,26 @@ export default Home

You can configure Image Optimization by using the `images` property in `next.config.js`.

### Sizes
### Device 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.
You can specify a list of device width breakpoints using the `deviceSizes` 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. These values will be used by the browser to determine which size image should load.

```js
module.exports = {
images: {
sizes: [320, 420, 768, 1024, 1200],
deviceSizes: [320, 420, 768, 1024, 1200],
},
}
```

### Icon Sizes

You can specify a list of icon image widths using the `iconSizes` property. These widths should be smaller than the smallest value in `deviceSizes`. The purpose is for images that don't scale with the browser window, such as icons or badges. If `iconSizes` is not defined, then `deviceSizes` will be used.

```js
module.exports = {
images: {
iconSizes: [16, 32, 64],
},
}
```
Expand Down Expand Up @@ -90,10 +102,11 @@ module.exports = {

The following Image Optimization cloud providers are supported:

- Imgix - `loader: 'imgix'`
- Cloudinary - `loader: 'cloudinary'`
- Akamai - `loader: 'akamai'`
- Vercel - No configuration necessary
- 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'`

## Related

Expand All @@ -105,10 +118,3 @@ For more information on what to do next, we recommend the following sections:
<small>See all available properties for the Image component</small>
</a>
</div>

<div class="card">
- 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'`
2 changes: 1 addition & 1 deletion lerna.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,5 @@
"registry": "https://registry.npmjs.org/"
}
},
"version": "9.5.6-canary.14"
"version": "9.5.6-canary.16"
}
2 changes: 1 addition & 1 deletion packages/create-next-app/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "create-next-app",
"version": "9.5.6-canary.14",
"version": "9.5.6-canary.16",
"keywords": [
"react",
"next",
Expand Down
2 changes: 1 addition & 1 deletion packages/eslint-plugin-next/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@next/eslint-plugin-next",
"version": "9.5.6-canary.14",
"version": "9.5.6-canary.16",
"description": "ESLint plugin for NextJS.",
"main": "lib/index.js",
"license": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion packages/next-bundle-analyzer/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@next/bundle-analyzer",
"version": "9.5.6-canary.14",
"version": "9.5.6-canary.16",
"main": "index.js",
"license": "MIT",
"repository": {
Expand Down
2 changes: 1 addition & 1 deletion packages/next-codemod/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@next/codemod",
"version": "9.5.6-canary.14",
"version": "9.5.6-canary.16",
"license": "MIT",
"dependencies": {
"chalk": "4.1.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/next-env/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@next/env",
"version": "9.5.6-canary.14",
"version": "9.5.6-canary.16",
"keywords": [
"react",
"next",
Expand Down
2 changes: 1 addition & 1 deletion packages/next-mdx/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@next/mdx",
"version": "9.5.6-canary.14",
"version": "9.5.6-canary.16",
"main": "index.js",
"license": "MIT",
"repository": {
Expand Down
2 changes: 1 addition & 1 deletion packages/next-plugin-google-analytics/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@next/plugin-google-analytics",
"version": "9.5.6-canary.14",
"version": "9.5.6-canary.16",
"repository": {
"url": "vercel/next.js",
"directory": "packages/next-plugin-google-analytics"
Expand Down
2 changes: 1 addition & 1 deletion packages/next-plugin-sentry/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@next/plugin-sentry",
"version": "9.5.6-canary.14",
"version": "9.5.6-canary.16",
"repository": {
"url": "vercel/next.js",
"directory": "packages/next-plugin-sentry"
Expand Down
2 changes: 1 addition & 1 deletion packages/next-plugin-storybook/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@next/plugin-storybook",
"version": "9.5.6-canary.14",
"version": "9.5.6-canary.16",
"repository": {
"url": "vercel/next.js",
"directory": "packages/next-plugin-storybook"
Expand Down
2 changes: 1 addition & 1 deletion packages/next-polyfill-module/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@next/polyfill-module",
"version": "9.5.6-canary.14",
"version": "9.5.6-canary.16",
"description": "A standard library polyfill for ES Modules supporting browsers (Edge 16+, Firefox 60+, Chrome 61+, Safari 10.1+)",
"main": "dist/polyfill-module.js",
"license": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion packages/next-polyfill-nomodule/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@next/polyfill-nomodule",
"version": "9.5.6-canary.14",
"version": "9.5.6-canary.16",
"description": "A polyfill for non-dead, nomodule browsers.",
"main": "dist/polyfill-nomodule.js",
"license": "MIT",
Expand Down
10 changes: 7 additions & 3 deletions packages/next/build/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -594,7 +594,7 @@ export default async function build(
ssgPageRoutes = workerResult.prerenderRoutes
}

if (workerResult.prerenderFallback === 'unstable_blocking') {
if (workerResult.prerenderFallback === 'blocking') {
ssgBlockingFallbackPages.add(page)
} else if (workerResult.prerenderFallback === true) {
ssgStaticFallbackPages.add(page)
Expand Down Expand Up @@ -1110,11 +1110,15 @@ export default async function build(
)
}

const images = { ...config.images }
const { deviceSizes, iconSizes } = images
images.sizes = [...deviceSizes, ...iconSizes]

await promises.writeFile(
path.join(distDir, IMAGES_MANIFEST),
JSON.stringify({
version: 1,
images: config.images,
images,
}),
'utf8'
)
Expand Down Expand Up @@ -1159,7 +1163,7 @@ export default async function build(
printCustomRoutes({ redirects, rewrites, headers })
}

if (config.experimental.analyticsId) {
if (config.analyticsId) {
console.log(
chalk.bold.green('Next.js Analytics') +
' is enabled for this production build. ' +
Expand Down
6 changes: 3 additions & 3 deletions packages/next/build/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -575,7 +575,7 @@ export async function buildStaticPaths(
if (
!(
typeof staticPathsResult.fallback === 'boolean' ||
staticPathsResult.fallback === 'unstable_blocking'
staticPathsResult.fallback === 'blocking'
)
) {
throw new Error(
Expand Down Expand Up @@ -700,7 +700,7 @@ export async function isPageStatic(
hasServerProps?: boolean
hasStaticProps?: boolean
prerenderRoutes?: string[] | undefined
prerenderFallback?: boolean | 'unstable_blocking' | undefined
prerenderFallback?: boolean | 'blocking' | undefined
}> {
try {
require('../next-server/lib/runtime-config').setConfig(runtimeEnvConfig)
Expand Down Expand Up @@ -775,7 +775,7 @@ export async function isPageStatic(
}

let prerenderRoutes: Array<string> | undefined
let prerenderFallback: boolean | 'unstable_blocking' | undefined
let prerenderFallback: boolean | 'blocking' | undefined
if (hasStaticProps && hasStaticPaths) {
;({
paths: prerenderRoutes,
Expand Down
7 changes: 3 additions & 4 deletions packages/next/build/webpack-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -991,7 +991,8 @@ export default async function getBaseWebpackConfig(
config.experimental.scrollRestoration
),
'process.env.__NEXT_IMAGE_OPTS': JSON.stringify({
sizes: config.images.sizes,
deviceSizes: config.images.deviceSizes,
iconSizes: config.images.iconSizes,
path: config.images.path,
loader: config.images.loader,
...(dev
Expand All @@ -1009,9 +1010,7 @@ export default async function getBaseWebpackConfig(
'process.env.__NEXT_I18N_DOMAINS': JSON.stringify(
config.experimental.i18n.domains
),
'process.env.__NEXT_ANALYTICS_ID': JSON.stringify(
config.experimental.analyticsId
),
'process.env.__NEXT_ANALYTICS_ID': JSON.stringify(config.analyticsId),
...(isServer
? {
// Fix bad-actors in the npm ecosystem (e.g. `node-formidable`)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -772,7 +772,7 @@ const nextServerlessLoader: loader.Loader = function () {
if (!renderMode) {
if (_nextData || getStaticProps || getServerSideProps) {
if (renderOpts.ssgNotFound) {
if (renderOpts.isNotFound) {
res.statusCode = 404
const NotFoundComponent = ${
Expand Down
25 changes: 17 additions & 8 deletions packages/next/client/image.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ const loaders = new Map<LoaderKey, (props: LoaderProps) => string>([
type LoaderKey = 'imgix' | 'cloudinary' | 'akamai' | 'default'

type ImageData = {
sizes: number[]
deviceSizes: number[]
iconSizes: number[]
loader: LoaderKey
path: string
domains?: string[]
Expand All @@ -36,12 +37,15 @@ type ImageProps = Omit<

const imageData: ImageData = process.env.__NEXT_IMAGE_OPTS as any
const {
sizes: configSizes,
deviceSizes: configDeviceSizes,
iconSizes: configIconSizes,
loader: configLoader,
path: configPath,
domains: configDomains,
} = imageData
configSizes.sort((a, b) => a - b) // smallest to largest
// sort smallest to largest
configDeviceSizes.sort((a, b) => a - b)
configIconSizes.sort((a, b) => a - b)

let cachedObserver: IntersectionObserver
const IntersectionObserver =
Expand Down Expand Up @@ -79,12 +83,16 @@ function getObserver(): IntersectionObserver | undefined {
))
}

function getWidthsFromConfig(width: number | undefined) {
function getDeviceSizes(width: number | undefined): number[] {
if (typeof width !== 'number') {
return configSizes
return configDeviceSizes
}
const smallest = configDeviceSizes[0]
if (width < smallest && configIconSizes.includes(width)) {
return [width]
}
const widths: number[] = []
for (let size of configSizes) {
for (let size of configDeviceSizes) {
widths.push(size)
if (size >= width) {
break
Expand All @@ -102,7 +110,7 @@ function computeSrc(
if (unoptimized) {
return src
}
const widths = getWidthsFromConfig(width)
const widths = getDeviceSizes(width)
const largest = widths[widths.length - 1]
return callLoader({ src, width: largest, quality })
}
Expand Down Expand Up @@ -136,7 +144,8 @@ function generateSrcSet({
if (unoptimized) {
return undefined
}
return getWidthsFromConfig(width)

return getDeviceSizes(width)
.map((w) => `${callLoader({ src, width: w, quality })} ${w}w`)
.join(', ')
}
Expand Down
4 changes: 2 additions & 2 deletions packages/next/export/worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ export default async function exportPage({
html = (result as any).html
}

if (!html && !(curRenderOpts as any).ssgNotFound) {
if (!html && !(curRenderOpts as any).isNotFound) {
throw new Error(`Failed to render serverless page`)
}
} else {
Expand Down Expand Up @@ -318,7 +318,7 @@ export default async function exportPage({
html = await renderMethod(req, res, page, query, curRenderOpts)
}
}
results.ssgNotFound = (curRenderOpts as any).ssgNotFound
results.ssgNotFound = (curRenderOpts as any).isNotFound

const validateAmp = async (
rawAmpHtml: string,
Expand Down
7 changes: 1 addition & 6 deletions packages/next/next-server/lib/router/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -813,12 +813,7 @@ export default class Router implements BaseRouter {
this._resolveHref(parsedHref, pages)

if (pages.includes(parsedHref.pathname)) {
return this.change(
'replaceState',
destination,
destination,
options
)
return this.change(method, destination, destination, options)
}
}

Expand Down
Loading

0 comments on commit 88809bb

Please sign in to comment.