Skip to content

Commit

Permalink
Rename iconSizes to imageSizes, remove size limitation (#18294)
Browse files Browse the repository at this point in the history
This does two things:

- Rename `iconSizes` to `imageSizes`.
- Give priority to `imageSizes` regardless of `deviceSizes` as a means to opt-out of the srcset behavior.
  • Loading branch information
styfle committed Oct 27, 2020
1 parent 774286f commit f773a1a
Show file tree
Hide file tree
Showing 9 changed files with 28 additions and 29 deletions.
6 changes: 3 additions & 3 deletions docs/basic-features/image-optimization.md
Expand Up @@ -62,14 +62,14 @@ module.exports = {
}
```

### Icon Sizes
### Image 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.
You can specify a list of exact image widths using the `imageSizes` property. These widths should be different than the widths defined in `deviceSizes`. The purpose is for images that don't scale with the browser window, such as icons, badges, or profile images. If the `width` property of a [`next/image`](/docs/api-reference/next/image.md) component matches a value in `imageSizes`, the image will be rendered at that exact width.

```js
module.exports = {
images: {
iconSizes: [16, 32, 64],
imageSizes: [16, 32, 64],
},
}
```
Expand Down
4 changes: 2 additions & 2 deletions packages/next/build/index.ts
Expand Up @@ -1111,8 +1111,8 @@ export default async function build(
}

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

await promises.writeFile(
path.join(distDir, IMAGES_MANIFEST),
Expand Down
2 changes: 1 addition & 1 deletion packages/next/build/webpack-config.ts
Expand Up @@ -992,7 +992,7 @@ export default async function getBaseWebpackConfig(
),
'process.env.__NEXT_IMAGE_OPTS': JSON.stringify({
deviceSizes: config.images.deviceSizes,
iconSizes: config.images.iconSizes,
imageSizes: config.images.imageSizes,
path: config.images.path,
loader: config.images.loader,
...(dev
Expand Down
9 changes: 4 additions & 5 deletions packages/next/client/image.tsx
Expand Up @@ -15,7 +15,7 @@ type LoaderKey = 'imgix' | 'cloudinary' | 'akamai' | 'default'

type ImageData = {
deviceSizes: number[]
iconSizes: number[]
imageSizes: number[]
loader: LoaderKey
path: string
domains?: string[]
Expand All @@ -38,14 +38,14 @@ type ImageProps = Omit<
const imageData: ImageData = process.env.__NEXT_IMAGE_OPTS as any
const {
deviceSizes: configDeviceSizes,
iconSizes: configIconSizes,
imageSizes: configImageSizes,
loader: configLoader,
path: configPath,
domains: configDomains,
} = imageData
// sort smallest to largest
configDeviceSizes.sort((a, b) => a - b)
configIconSizes.sort((a, b) => a - b)
configImageSizes.sort((a, b) => a - b)

let cachedObserver: IntersectionObserver
const IntersectionObserver =
Expand Down Expand Up @@ -87,8 +87,7 @@ function getDeviceSizes(width: number | undefined): number[] {
if (typeof width !== 'number') {
return configDeviceSizes
}
const smallest = configDeviceSizes[0]
if (width < smallest && configIconSizes.includes(width)) {
if (configImageSizes.includes(width)) {
return [width]
}
const widths: number[] = []
Expand Down
18 changes: 9 additions & 9 deletions packages/next/next-server/server/config.ts
Expand Up @@ -26,7 +26,7 @@ const defaultConfig: { [key: string]: any } = {
analyticsId: process.env.VERCEL_ANALYTICS_ID || '',
images: {
deviceSizes: [320, 420, 768, 1024, 1200],
iconSizes: [],
imageSizes: [],
domains: [],
path: '/_next/image',
loader: 'default',
Expand Down Expand Up @@ -280,27 +280,27 @@ function assignDefaults(userConfig: { [key: string]: any }) {
)
}
}
if (images.iconSizes) {
const { iconSizes } = images
if (!Array.isArray(iconSizes)) {
if (images.imageSizes) {
const { imageSizes } = images
if (!Array.isArray(imageSizes)) {
throw new Error(
`Specified images.iconSizes should be an Array received ${typeof iconSizes}`
`Specified images.imageSizes should be an Array received ${typeof imageSizes}`
)
}

if (iconSizes.length > 25) {
if (imageSizes.length > 25) {
throw new Error(
`Specified images.iconSizes exceeds length of 25, received length (${iconSizes.length}), please reduce the length of the array to continue`
`Specified images.imageSizes exceeds length of 25, received length (${imageSizes.length}), please reduce the length of the array to continue`
)
}

const invalid = iconSizes.filter((d: unknown) => {
const invalid = imageSizes.filter((d: unknown) => {
return typeof d !== 'number' || d < 1 || d > 10000
})

if (invalid.length > 0) {
throw new Error(
`Specified images.iconSizes should be an Array of numbers that are between 1 and 10000, received invalid values (${invalid.join(
`Specified images.imageSizes should be an Array of numbers that are between 1 and 10000, received invalid values (${invalid.join(
', '
)})`
)
Expand Down
6 changes: 3 additions & 3 deletions packages/next/next-server/server/image-optimizer.ts
Expand Up @@ -25,7 +25,7 @@ const VECTOR_TYPES = [SVG]

type ImageData = {
deviceSizes: number[]
iconSizes: number[]
imageSizes: number[]
loader: string
path: string
domains?: string[]
Expand All @@ -39,8 +39,8 @@ export async function imageOptimizer(
) {
const { nextConfig, distDir } = server
const imageData: ImageData = nextConfig.images
const { deviceSizes = [], iconSizes = [], domains = [], loader } = imageData
const sizes = [...deviceSizes, ...iconSizes]
const { deviceSizes = [], imageSizes = [], domains = [], loader } = imageData
const sizes = [...deviceSizes, ...imageSizes]

if (loader !== 'default') {
await server.render404(req, res, parsedUrl)
Expand Down
2 changes: 1 addition & 1 deletion test/integration/image-component/basic/next.config.js
@@ -1,7 +1,7 @@
module.exports = {
images: {
deviceSizes: [480, 1024, 1600, 2000],
iconSizes: [16, 64],
imageSizes: [16, 64],
path: 'https://example.com/myaccount/',
loader: 'imgix',
},
Expand Down
2 changes: 1 addition & 1 deletion test/integration/image-component/basic/test/index.test.js
Expand Up @@ -51,7 +51,7 @@ function runTests() {
await browser.elementById('preceding-slash-image').getAttribute('srcset')
).toBe('https://example.com/myaccount/fooslash.jpg?auto=format&w=480 480w')
})
it('should use iconSizes when width matches, not deviceSizes from next.config.js', async () => {
it('should use imageSizes when width matches, not deviceSizes from next.config.js', async () => {
expect(await browser.elementById('icon-image-16').getAttribute('src')).toBe(
'https://example.com/myaccount/icon.png?auto=format&w=16'
)
Expand Down
8 changes: 4 additions & 4 deletions test/integration/image-optimizer/test/index.test.js
Expand Up @@ -398,12 +398,12 @@ describe('Image Optimizer', () => {
)
})

it('should error when iconSizes contains invalid widths', async () => {
it('should error when imageSizes contains invalid widths', async () => {
await nextConfig.replace(
'{ /* replaceme */ }',
JSON.stringify({
images: {
iconSizes: [0, 16, 64, 12000],
imageSizes: [0, 16, 64, 12000],
},
})
)
Expand All @@ -419,7 +419,7 @@ describe('Image Optimizer', () => {
await nextConfig.restore()

expect(stderr).toContain(
'Specified images.iconSizes should be an Array of numbers that are between 1 and 10000, received invalid values (0, 12000)'
'Specified images.imageSizes should be an Array of numbers that are between 1 and 10000, received invalid values (0, 12000)'
)
})
})
Expand Down Expand Up @@ -447,7 +447,7 @@ describe('Image Optimizer', () => {
const json = JSON.stringify({
images: {
deviceSizes: [largeSize],
iconSizes: [size],
imageSizes: [size],
domains,
},
})
Expand Down

0 comments on commit f773a1a

Please sign in to comment.