diff --git a/packages/next/build/webpack/loaders/next-image-loader.js b/packages/next/build/webpack/loaders/next-image-loader.js
index 06cce69a5469..af1fb8d0be60 100644
--- a/packages/next/build/webpack/loaders/next-image-loader.js
+++ b/packages/next/build/webpack/loaders/next-image-loader.js
@@ -28,6 +28,8 @@ function nextImageLoader(content) {
getImageSize(content, extension)
)
let blurDataURL
+ let blurWidth
+ let blurHeight
if (VALID_BLUR_EXT.includes(extension)) {
if (isDev) {
@@ -39,18 +41,21 @@ function nextImageLoader(content) {
blurDataURL = url.href.slice(prefix.length)
} else {
// Shrink the image's largest dimension
- const dimension =
- imageSize.width >= imageSize.height ? 'width' : 'height'
+ if (imageSize.width >= imageSize.height) {
+ blurWidth = BLUR_IMG_SIZE
+ blurHeight = Math.round(
+ (imageSize.height / imageSize.width) * BLUR_IMG_SIZE
+ )
+ } else {
+ blurWidth = Math.round(
+ (imageSize.width / imageSize.height) * BLUR_IMG_SIZE
+ )
+ blurHeight = BLUR_IMG_SIZE
+ }
const resizeImageSpan = imageLoaderSpan.traceChild('image-resize')
const resizedImage = await resizeImageSpan.traceAsyncFn(() =>
- resizeImage(
- content,
- dimension,
- BLUR_IMG_SIZE,
- extension,
- BLUR_QUALITY
- )
+ resizeImage(content, blurWidth, blurHeight, extension, BLUR_QUALITY)
)
const blurDataURLSpan = imageLoaderSpan.traceChild(
'image-base64-tostring'
@@ -70,6 +75,8 @@ function nextImageLoader(content) {
height: imageSize.height,
width: imageSize.width,
blurDataURL,
+ blurWidth,
+ blurHeight,
})
)
diff --git a/packages/next/client/future/image.tsx b/packages/next/client/future/image.tsx
index f3ffe5b7033e..f53be503d6d0 100644
--- a/packages/next/client/future/image.tsx
+++ b/packages/next/client/future/image.tsx
@@ -67,6 +67,8 @@ export interface StaticImageData {
height: number
width: number
blurDataURL?: string
+ blurWidth?: number
+ blurHeight?: number
}
interface StaticRequire {
@@ -578,6 +580,8 @@ export default function Image({
}
let staticSrc = ''
+ let blurWidth: number | undefined
+ let blurHeight: number | undefined
if (isStaticImport(src)) {
const staticImageData = isStaticRequire(src) ? src.default : src
@@ -588,6 +592,8 @@ export default function Image({
)}`
)
}
+ blurWidth = staticImageData.blurWidth
+ blurHeight = staticImageData.blurHeight
blurDataURL = blurDataURL || staticImageData.blurDataURL
staticSrc = staticImageData.src
@@ -785,16 +791,24 @@ export default function Image({
bottom: 0,
}
: {},
- showAltText || placeholder === 'blur' ? {} : { color: 'transparent' },
+ showAltText ? {} : { color: 'transparent' },
style
)
- const svgBlurPlaceholder = `url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http%3A//www.w3.org/2000/svg' viewBox='0 0 ${widthInt} ${heightInt}'%3E%3Cfilter id='b' color-interpolation-filters='sRGB'%3E%3CfeGaussianBlur stdDeviation='50'/%3E%3C/filter%3E%3Cimage filter='url(%23b)' x='0' y='0' height='100%25' width='100%25' href='${blurDataURL}'/%3E%3C/svg%3E")`
+ const std = blurWidth && blurHeight ? '1' : '20'
+ const svgWidth = blurWidth || widthInt
+ const svgHeight = blurHeight || heightInt
+ const feComponentTransfer = blurDataURL?.startsWith('data:image/jpeg')
+ ? `%3CfeComponentTransfer%3E%3CfeFuncA type='discrete' tableValues='1 1'/%3E%3C/feComponentTransfer%3E%`
+ : ''
+ const svgBlurPlaceholder = `url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http%3A//www.w3.org/2000/svg' viewBox='0 0 ${svgWidth} ${svgHeight}'%3E%3Cfilter id='b' color-interpolation-filters='sRGB'%3E%3CfeGaussianBlur stdDeviation='${std}'/%3E${feComponentTransfer}%3C/filter%3E%3Cimage filter='url(%23b)' x='0' y='0' height='100%25' width='100%25' href='${blurDataURL}'/%3E%3C/svg%3E")`
+
const blurStyle =
- placeholder === 'blur' && !blurComplete
+ placeholder === 'blur' && blurDataURL && !blurComplete
? {
backgroundSize: imgStyle.objectFit || 'cover',
- backgroundPosition: imgStyle.objectPosition || '0% 0%',
- ...(blurDataURL?.startsWith('data:image')
+ backgroundPosition: imgStyle.objectPosition || '50% 50%',
+ backgroundRepeat: 'no-repeat',
+ ...(blurDataURL.startsWith('data:image') && svgWidth && svgHeight
? {
backgroundImage: svgBlurPlaceholder,
}
diff --git a/packages/next/server/image-optimizer.ts b/packages/next/server/image-optimizer.ts
index 562e28d6aeb1..36d8921f8bbf 100644
--- a/packages/next/server/image-optimizer.ts
+++ b/packages/next/server/image-optimizer.ts
@@ -719,8 +719,8 @@ export function sendResponse(
export async function resizeImage(
content: Buffer,
- dimension: 'width' | 'height',
- size: number,
+ width: number,
+ height: number,
// Should match VALID_BLUR_EXT
extension: 'avif' | 'webp' | 'png' | 'jpeg',
quality: number
@@ -748,18 +748,11 @@ export async function resizeImage(
} else if (extension === 'jpeg') {
transformer.jpeg({ quality })
}
- if (dimension === 'width') {
- transformer.resize(size)
- } else {
- transformer.resize(null, size)
- }
+ transformer.resize(width, height)
const buf = await transformer.toBuffer()
return buf
} else {
- const resizeOperationOpts: Operation =
- dimension === 'width'
- ? { type: 'resize', width: size }
- : { type: 'resize', height: size }
+ const resizeOperationOpts: Operation = { type: 'resize', width, height }
const buf = await processBuffer(
content,
[resizeOperationOpts],
diff --git a/packages/next/server/lib/squoosh/impl.ts b/packages/next/server/lib/squoosh/impl.ts
index 8b5577304823..182664e7e35d 100644
--- a/packages/next/server/lib/squoosh/impl.ts
+++ b/packages/next/server/lib/squoosh/impl.ts
@@ -62,6 +62,7 @@ export async function rotate(
type ResizeOpts = { image: ImageData } & (
| { width: number; height?: never }
| { height: number; width?: never }
+ | { height: number; width: number }
)
export async function resize({ image, width, height }: ResizeOpts) {
diff --git a/packages/next/server/lib/squoosh/main.ts b/packages/next/server/lib/squoosh/main.ts
index 15cc49b3c1d7..2d326cbf1cc2 100644
--- a/packages/next/server/lib/squoosh/main.ts
+++ b/packages/next/server/lib/squoosh/main.ts
@@ -9,7 +9,11 @@ type RotateOperation = {
}
type ResizeOperation = {
type: 'resize'
-} & ({ width: number; height?: never } | { height: number; width?: never })
+} & (
+ | { width: number; height?: never }
+ | { height: number; width?: never }
+ | { width: number; height: number }
+)
export type Operation = RotateOperation | ResizeOperation
export type Encoding = 'jpeg' | 'png' | 'webp' | 'avif'
@@ -37,24 +41,24 @@ export async function processBuffer(
if (operation.type === 'rotate') {
imageData = await worker.rotate(imageData, operation.numRotations)
} else if (operation.type === 'resize') {
+ const opt = { image: imageData, width: 0, height: 0 }
if (
operation.width &&
imageData.width &&
imageData.width > operation.width
) {
- imageData = await worker.resize({
- image: imageData,
- width: operation.width,
- })
- } else if (
+ opt.width = operation.width
+ }
+ if (
operation.height &&
imageData.height &&
imageData.height > operation.height
) {
- imageData = await worker.resize({
- image: imageData,
- height: operation.height,
- })
+ opt.height = operation.height
+ }
+
+ if (opt.width > 0 || opt.height > 0) {
+ imageData = await worker.resize(opt)
}
}
}
diff --git a/test/integration/image-future/base-path/test/static.test.js b/test/integration/image-future/base-path/test/static.test.js
index 0a55ccc0d9a5..fa262880c619 100644
--- a/test/integration/image-future/base-path/test/static.test.js
+++ b/test/integration/image-future/base-path/test/static.test.js
@@ -5,9 +5,11 @@ import {
nextStart,
renderViaHTTP,
File,
+ launchApp,
waitFor,
} from 'next-test-utils'
import webdriver from 'next-webdriver'
+import cheerio from 'cheerio'
import { join } from 'path'
const appDir = join(__dirname, '../')
@@ -15,10 +17,11 @@ let appPort
let app
let browser
let html
+let $
const indexPage = new File(join(appDir, 'pages/static-img.js'))
-const runTests = () => {
+const runTests = (isDev) => {
it('Should allow an image with a static src to omit height and width', async () => {
expect(await browser.elementById('basic-static')).toBeTruthy()
expect(await browser.elementById('blur-png')).toBeTruthy()
@@ -31,42 +34,71 @@ const runTests = () => {
expect(await browser.elementById('static-ico')).toBeTruthy()
expect(await browser.elementById('static-unoptimized')).toBeTruthy()
})
- it('Should use immutable cache-control header for static import', async () => {
- await browser.eval(
- `document.getElementById("basic-static").scrollIntoView()`
- )
- await waitFor(1000)
- const url = await browser.eval(
- `document.getElementById("basic-static").src`
- )
- const res = await fetch(url)
- expect(res.headers.get('cache-control')).toBe(
- 'public, max-age=315360000, immutable'
- )
- })
- it('Should use immutable cache-control header even when unoptimized', async () => {
- await browser.eval(
- `document.getElementById("static-unoptimized").scrollIntoView()`
- )
- await waitFor(1000)
- const url = await browser.eval(
- `document.getElementById("static-unoptimized").src`
- )
- const res = await fetch(url)
- expect(res.headers.get('cache-control')).toBe(
- 'public, max-age=31536000, immutable'
- )
- })
+ if (!isDev) {
+ // cache-control is set to "0, no-store" in dev mode
+ it('Should use immutable cache-control header for static import', async () => {
+ await browser.eval(
+ `document.getElementById("basic-static").scrollIntoView()`
+ )
+ await waitFor(1000)
+ const url = await browser.eval(
+ `document.getElementById("basic-static").src`
+ )
+ const res = await fetch(url)
+ expect(res.headers.get('cache-control')).toBe(
+ 'public, max-age=315360000, immutable'
+ )
+ })
+
+ it('Should use immutable cache-control header even when unoptimized', async () => {
+ await browser.eval(
+ `document.getElementById("static-unoptimized").scrollIntoView()`
+ )
+ await waitFor(1000)
+ const url = await browser.eval(
+ `document.getElementById("static-unoptimized").src`
+ )
+ const res = await fetch(url)
+ expect(res.headers.get('cache-control')).toBe(
+ 'public, max-age=31536000, immutable'
+ )
+ })
+ }
it('Should automatically provide an image height and width', async () => {
- expect(html).toContain('width="400" height="300"')
+ const img = $('#basic-non-static')
+ expect(img.attr('width')).toBe('400')
+ expect(img.attr('height')).toBe('300')
})
it('Should allow provided width and height to override intrinsic', async () => {
- expect(html).toContain('width="150" height="150"')
+ const img = $('#defined-size-static')
+ expect(img.attr('width')).toBe('150')
+ expect(img.attr('height')).toBe('150')
})
- it('Should add a blur to a statically imported image', async () => {
- expect(html).toContain(
- `style="background-size:cover;background-position:0% 0%;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http%3A//www.w3.org/2000/svg' viewBox='0 0 400 300'%3E%3Cfilter id='b' color-interpolation-filters='sRGB'%3E%3CfeGaussianBlur stdDeviation='50'/%3E%3C/filter%3E%3Cimage filter='url(%23b)' x='0' y='0' height='100%25' width='100%25' href='data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAoKCgoKCgsMDAsPEA4QDxYUExMUFiIYGhgaGCIzICUgICUgMy03LCksNy1RQDg4QFFeT0pPXnFlZXGPiI+7u/sBCgoKCgoKCwwMCw8QDhAPFhQTExQWIhgaGBoYIjMgJSAgJSAzLTcsKSw3LVFAODhAUV5PSk9ecWVlcY+Ij7u7+//CABEIAAYACAMBIgACEQEDEQH/xAAnAAEBAAAAAAAAAAAAAAAAAAAABwEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEAMQAAAAmgP/xAAcEAACAQUBAAAAAAAAAAAAAAASFBMAAQMFERX/2gAIAQEAAT8AZ1HjrKZX55JysIc4Ff/EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQIBAT8Af//EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQMBAT8Af//Z'/%3E%3C/svg%3E")`
- )
+
+ it('Should add a blur placeholder a statically imported jpg', async () => {
+ const style = $('#basic-static').attr('style')
+ if (isDev) {
+ expect(style).toBe(
+ `color:transparent;background-size:cover;background-position:50% 50%;background-repeat:no-repeat;filter:blur(20px);background-image:url("/docs/_next/image?url=%2Fdocs%2F_next%2Fstatic%2Fmedia%2Ftest-rect.f323a148.jpg&w=8&q=70")`
+ )
+ } else {
+ expect(style).toBe(
+ `color:transparent;background-size:cover;background-position:50% 50%;background-repeat:no-repeat;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http%3A//www.w3.org/2000/svg' viewBox='0 0 8 6'%3E%3Cfilter id='b' color-interpolation-filters='sRGB'%3E%3CfeGaussianBlur stdDeviation='1'/%3E%3CfeComponentTransfer%3E%3CfeFuncA type='discrete' tableValues='1 1'/%3E%3C/feComponentTransfer%3E%%3C/filter%3E%3Cimage filter='url(%23b)' x='0' y='0' height='100%25' width='100%25' href='data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAoKCgoKCgsMDAsPEA4QDxYUExMUFiIYGhgaGCIzICUgICUgMy03LCksNy1RQDg4QFFeT0pPXnFlZXGPiI+7u/sBCgoKCgoKCwwMCw8QDhAPFhQTExQWIhgaGBoYIjMgJSAgJSAzLTcsKSw3LVFAODhAUV5PSk9ecWVlcY+Ij7u7+//CABEIAAYACAMBIgACEQEDEQH/xAAnAAEBAAAAAAAAAAAAAAAAAAAABwEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEAMQAAAAmgP/xAAcEAACAQUBAAAAAAAAAAAAAAASFBMAAQMFERX/2gAIAQEAAT8AZ1HjrKZX55JysIc4Ff/EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQIBAT8Af//EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQMBAT8Af//Z'/%3E%3C/svg%3E")`
+ )
+ }
+ })
+
+ it('Should add a blur placeholder a statically imported png', async () => {
+ const style = $('#blur-png').attr('style')
+ if (isDev) {
+ expect(style).toBe(
+ `color:transparent;background-size:cover;background-position:50% 50%;background-repeat:no-repeat;filter:blur(20px);background-image:url("/docs/_next/image?url=%2Fdocs%2F_next%2Fstatic%2Fmedia%2Ftest.3f1a293b.png&w=8&q=70")`
+ )
+ } else {
+ expect(style).toBe(
+ `color:transparent;background-size:cover;background-position:50% 50%;background-repeat:no-repeat;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http%3A//www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cfilter id='b' color-interpolation-filters='sRGB'%3E%3CfeGaussianBlur stdDeviation='1'/%3E%3C/filter%3E%3Cimage filter='url(%23b)' x='0' y='0' height='100%25' width='100%25' href='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAAAAADhZOFXAAAAOklEQVR42iWGsQkAIBDE0iuIdiLOJjiGIzjiL/Meb4okiNYIlLjK3hJMzCQG1/0qmXXOUkjAV+m9wAMe3QiV6Ne8VgAAAABJRU5ErkJggg=='/%3E%3C/svg%3E")`
+ )
+ }
})
}
@@ -90,15 +122,32 @@ describe('Build Error Tests', () => {
})
})
describe('Future Static Image Component Tests for basePath', () => {
- beforeAll(async () => {
- await nextBuild(appDir)
- appPort = await findPort()
- app = await nextStart(appDir, appPort)
- html = await renderViaHTTP(appPort, '/docs/static-img')
- browser = await webdriver(appPort, '/docs/static-img')
+ describe('production mode', () => {
+ beforeAll(async () => {
+ await nextBuild(appDir)
+ appPort = await findPort()
+ app = await nextStart(appDir, appPort)
+ html = await renderViaHTTP(appPort, '/docs/static-img')
+ $ = cheerio.load(html)
+ browser = await webdriver(appPort, '/docs/static-img')
+ })
+ afterAll(() => {
+ killApp(app)
+ })
+ runTests(false)
})
- afterAll(() => {
- killApp(app)
+
+ describe('dev mode', () => {
+ beforeAll(async () => {
+ appPort = await findPort()
+ app = await launchApp(appDir, appPort)
+ html = await renderViaHTTP(appPort, '/docs/static-img')
+ $ = cheerio.load(html)
+ browser = await webdriver(appPort, '/docs/static-img')
+ })
+ afterAll(() => {
+ killApp(app)
+ })
+ runTests(true)
})
- runTests()
})
diff --git a/test/integration/image-future/default/pages/static-img.js b/test/integration/image-future/default/pages/static-img.js
index 6b6b4cfd5739..472c5906387e 100644
--- a/test/integration/image-future/default/pages/static-img.js
+++ b/test/integration/image-future/default/pages/static-img.js
@@ -32,15 +32,22 @@ const Page = () => {
+
+
+
+
+
+
+
)
diff --git a/test/integration/image-future/default/test/index.test.ts b/test/integration/image-future/default/test/index.test.ts
index 0b779d5fa4d8..d10c94adec38 100644
--- a/test/integration/image-future/default/test/index.test.ts
+++ b/test/integration/image-future/default/test/index.test.ts
@@ -536,7 +536,7 @@ function runTests(mode) {
)
expect(await browser.elementById('blur1').getAttribute('sizes')).toBeNull()
expect(await browser.elementById('blur1').getAttribute('style')).toMatch(
- 'background-size:cover;background-position:0% 0%;'
+ 'color:transparent;background-size:cover;background-position:50% 50%;background-repeat:no-repeat;'
)
expect(await browser.elementById('blur1').getAttribute('height')).toBe(
'400'
@@ -559,7 +559,9 @@ function runTests(mode) {
'lazy'
)
expect(await browser.elementById('blur1').getAttribute('sizes')).toBeNull()
- expect(await browser.elementById('blur1').getAttribute('style')).toMatch('')
+ expect(await browser.elementById('blur1').getAttribute('style')).toBe(
+ 'color: transparent;'
+ )
expect(await browser.elementById('blur1').getAttribute('height')).toBe(
'400'
)
@@ -579,7 +581,7 @@ function runTests(mode) {
'lazy'
)
expect(await browser.elementById('blur2').getAttribute('style')).toMatch(
- 'background-size:cover;background-position:0% 0%;'
+ 'color:transparent;background-size:cover;background-position:50% 50%;background-repeat:no-repeat'
)
expect(await browser.elementById('blur2').getAttribute('height')).toBe(
'400'
@@ -604,7 +606,9 @@ function runTests(mode) {
expect(await browser.elementById('blur2').getAttribute('loading')).toBe(
'lazy'
)
- expect(await browser.elementById('blur2').getAttribute('style')).toBe('')
+ expect(await browser.elementById('blur2').getAttribute('style')).toBe(
+ 'color: transparent;'
+ )
expect(await browser.elementById('blur2').getAttribute('height')).toBe(
'400'
)
@@ -1082,11 +1086,11 @@ function runTests(mode) {
$html('noscript > img').attr('id', 'unused')
expect($html('#blurry-placeholder-raw')[0].attribs.style).toContain(
- `background-size:cover;background-position:0% 0%;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http%3A//www.w3.org/2000/svg' viewBox='0 0 400 400'%3E%3Cfilter id='b' color-interpolation-filters='sRGB'%3E%3CfeGaussianBlur stdDeviation='50'/%3E%3C/filter%3E%3Cimage filter='url(%23b)' x='0' y='0' height='100%25' width='100%25' href='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8P4nhDwAGuAKPn6cicwAAAABJRU5ErkJggg=='/%3E%3C/svg%3E")`
+ `color:transparent;background-size:cover;background-position:50% 50%;background-repeat:no-repeat;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http%3A//www.w3.org/2000/svg' viewBox='0 0 400 400'%3E%3Cfilter id='b' color-interpolation-filters='sRGB'%3E%3CfeGaussianBlur stdDeviation='20'/%3E%3C/filter%3E%3Cimage filter='url(%23b)' x='0' y='0' height='100%25' width='100%25' href='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8P4nhDwAGuAKPn6cicwAAAABJRU5ErkJggg=='/%3E%3C/svg%3E")`
)
expect($html('#blurry-placeholder-with-lazy')[0].attribs.style).toContain(
- `background-size:cover;background-position:0% 0%;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http%3A//www.w3.org/2000/svg' viewBox='0 0 400 400'%3E%3Cfilter id='b' color-interpolation-filters='sRGB'%3E%3CfeGaussianBlur stdDeviation='50'/%3E%3C/filter%3E%3Cimage filter='url(%23b)' x='0' y='0' height='100%25' width='100%25' href='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mO0/8/wBwAE/wI85bEJ6gAAAABJRU5ErkJggg=='/%3E%3C/svg%3E")`
+ `color:transparent;background-size:cover;background-position:50% 50%;background-repeat:no-repeat;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http%3A//www.w3.org/2000/svg' viewBox='0 0 400 400'%3E%3Cfilter id='b' color-interpolation-filters='sRGB'%3E%3CfeGaussianBlur stdDeviation='20'/%3E%3C/filter%3E%3Cimage filter='url(%23b)' x='0' y='0' height='100%25' width='100%25' href='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mO0/8/wBwAE/wI85bEJ6gAAAABJRU5ErkJggg=='/%3E%3C/svg%3E")`
)
})
@@ -1096,7 +1100,7 @@ function runTests(mode) {
const img = $html('noscript > img')[0]
expect(img).toBeDefined()
expect(img.attribs.id).toBe('blurry-placeholder-raw')
- expect(img.attribs.style).toBeUndefined()
+ expect(img.attribs.style).toBe('color:transparent')
})
it('should remove blurry placeholder after image loads', async () => {
@@ -1117,7 +1121,7 @@ function runTests(mode) {
'background-image'
)
).toBe(
- `url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http%3A//www.w3.org/2000/svg' viewBox='0 0 400 400'%3E%3Cfilter id='b' color-interpolation-filters='sRGB'%3E%3CfeGaussianBlur stdDeviation='50'/%3E%3C/filter%3E%3Cimage filter='url(%23b)' x='0' y='0' height='100%25' width='100%25' href='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mO0/8/wBwAE/wI85bEJ6gAAAABJRU5ErkJggg=='/%3E%3C/svg%3E")`
+ `url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http%3A//www.w3.org/2000/svg' viewBox='0 0 400 400'%3E%3Cfilter id='b' color-interpolation-filters='sRGB'%3E%3CfeGaussianBlur stdDeviation='20'/%3E%3C/filter%3E%3Cimage filter='url(%23b)' x='0' y='0' height='100%25' width='100%25' href='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mO0/8/wBwAE/wI85bEJ6gAAAABJRU5ErkJggg=='/%3E%3C/svg%3E")`
)
await browser.eval('document.getElementById("spacer").remove()')
diff --git a/test/integration/image-future/default/test/static.test.ts b/test/integration/image-future/default/test/static.test.ts
index e40d548ba17d..2bd883d8976c 100644
--- a/test/integration/image-future/default/test/static.test.ts
+++ b/test/integration/image-future/default/test/static.test.ts
@@ -9,6 +9,7 @@ import {
launchApp,
} from 'next-test-utils'
import webdriver from 'next-webdriver'
+import cheerio from 'cheerio'
import { join } from 'path'
const appDir = join(__dirname, '../')
@@ -16,10 +17,11 @@ let appPort
let app
let browser
let html
+let $
const indexPage = new File(join(appDir, 'pages/static-img.js'))
-const runTests = (isDev = false) => {
+const runTests = (isDev) => {
it('Should allow an image with a static src to omit height and width', async () => {
expect(await browser.elementById('basic-static')).toBeTruthy()
expect(await browser.elementById('blur-png')).toBeTruthy()
@@ -68,22 +70,51 @@ const runTests = (isDev = false) => {
})
}
it('Should automatically provide an image height and width', async () => {
- expect(html).toContain('width="400" height="300"')
+ const img = $('#basic-non-static')
+ expect(img.attr('width')).toBe('400')
+ expect(img.attr('height')).toBe('300')
})
it('Should allow provided width and height to override intrinsic', async () => {
- expect(html).toContain('width="150" height="150"')
+ const img = $('#defined-size-static')
+ expect(img.attr('width')).toBe('150')
+ expect(img.attr('height')).toBe('150')
})
- it('Should add a blur to a statically imported image in "raw" mode', async () => {
- // next-image-loader uses different blur behavior for dev/prod mode
- // See next/build/webpack/loaders/next-image-loader
+ it('Should add a blur placeholder a statically imported jpg', async () => {
+ const style = $('#basic-static').attr('style')
if (isDev) {
- expect(html).toContain(
- `style="background-size:cover;background-position:0% 0%;filter:blur(20px);background-image:url("/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Ftest-rect.f323a148.jpg&w=8&q=70")"`
+ expect(style).toBe(
+ `color:transparent;background-size:cover;background-position:50% 50%;background-repeat:no-repeat;filter:blur(20px);background-image:url("/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Ftest-rect.f323a148.jpg&w=8&q=70")`
)
} else {
- expect(html).toContain(
- `style="background-size:cover;background-position:0% 0%;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http%3A//www.w3.org/2000/svg' viewBox='0 0 400 300'%3E%3Cfilter id='b' color-interpolation-filters='sRGB'%3E%3CfeGaussianBlur stdDeviation='50'/%3E%3C/filter%3E%3Cimage filter='url(%23b)' x='0' y='0' height='100%25' width='100%25' href='data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAoKCgoKCgsMDAsPEA4QDxYUExMUFiIYGhgaGCIzICUgICUgMy03LCksNy1RQDg4QFFeT0pPXnFlZXGPiI+7u/sBCgoKCgoKCwwMCw8QDhAPFhQTExQWIhgaGBoYIjMgJSAgJSAzLTcsKSw3LVFAODhAUV5PSk9ecWVlcY+Ij7u7+//CABEIAAYACAMBIgACEQEDEQH/xAAnAAEBAAAAAAAAAAAAAAAAAAAABwEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEAMQAAAAmgP/xAAcEAACAQUBAAAAAAAAAAAAAAASFBMAAQMFERX/2gAIAQEAAT8AZ1HjrKZX55JysIc4Ff/EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQIBAT8Af//EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQMBAT8Af//Z'/%3E%3C/svg%3E")`
+ expect(style).toBe(
+ `color:transparent;background-size:cover;background-position:50% 50%;background-repeat:no-repeat;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http%3A//www.w3.org/2000/svg' viewBox='0 0 8 6'%3E%3Cfilter id='b' color-interpolation-filters='sRGB'%3E%3CfeGaussianBlur stdDeviation='1'/%3E%3CfeComponentTransfer%3E%3CfeFuncA type='discrete' tableValues='1 1'/%3E%3C/feComponentTransfer%3E%%3C/filter%3E%3Cimage filter='url(%23b)' x='0' y='0' height='100%25' width='100%25' href='data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAoKCgoKCgsMDAsPEA4QDxYUExMUFiIYGhgaGCIzICUgICUgMy03LCksNy1RQDg4QFFeT0pPXnFlZXGPiI+7u/sBCgoKCgoKCwwMCw8QDhAPFhQTExQWIhgaGBoYIjMgJSAgJSAzLTcsKSw3LVFAODhAUV5PSk9ecWVlcY+Ij7u7+//CABEIAAYACAMBIgACEQEDEQH/xAAnAAEBAAAAAAAAAAAAAAAAAAAABwEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEAMQAAAAmgP/xAAcEAACAQUBAAAAAAAAAAAAAAASFBMAAQMFERX/2gAIAQEAAT8AZ1HjrKZX55JysIc4Ff/EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQIBAT8Af//EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQMBAT8Af//Z'/%3E%3C/svg%3E")`
+ )
+ }
+ })
+
+ it('Should add a blur placeholder a statically imported png', async () => {
+ const style = $('#blur-png').attr('style')
+ if (isDev) {
+ expect(style).toBe(
+ `color:transparent;background-size:cover;background-position:50% 50%;background-repeat:no-repeat;filter:blur(20px);background-image:url("/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Ftest.3f1a293b.png&w=8&q=70")`
+ )
+ } else {
+ expect(style).toBe(
+ `color:transparent;background-size:cover;background-position:50% 50%;background-repeat:no-repeat;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http%3A//www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cfilter id='b' color-interpolation-filters='sRGB'%3E%3CfeGaussianBlur stdDeviation='1'/%3E%3C/filter%3E%3Cimage filter='url(%23b)' x='0' y='0' height='100%25' width='100%25' href='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAAAAADhZOFXAAAAOklEQVR42iWGsQkAIBDE0iuIdiLOJjiGIzjiL/Meb4okiNYIlLjK3hJMzCQG1/0qmXXOUkjAV+m9wAMe3QiV6Ne8VgAAAABJRU5ErkJggg=='/%3E%3C/svg%3E")`
+ )
+ }
+ })
+
+ it('Should add a blur placeholder a statically imported png with fill', async () => {
+ const style = $('#blur-png-fill').attr('style')
+ if (isDev) {
+ expect(style).toBe(
+ `position:absolute;height:100%;width:100%;left:0;top:0;right:0;bottom:0;color:transparent;background-size:cover;background-position:50% 50%;background-repeat:no-repeat;filter:blur(20px);background-image:url("/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Ftest.3f1a293b.png&w=8&q=70")`
+ )
+ } else {
+ expect(style).toBe(
+ `position:absolute;height:100%;width:100%;left:0;top:0;right:0;bottom:0;color:transparent;background-size:cover;background-position:50% 50%;background-repeat:no-repeat;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http%3A//www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cfilter id='b' color-interpolation-filters='sRGB'%3E%3CfeGaussianBlur stdDeviation='1'/%3E%3C/filter%3E%3Cimage filter='url(%23b)' x='0' y='0' height='100%25' width='100%25' href='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAAAAADhZOFXAAAAOklEQVR42iWGsQkAIBDE0iuIdiLOJjiGIzjiL/Meb4okiNYIlLjK3hJMzCQG1/0qmXXOUkjAV+m9wAMe3QiV6Ne8VgAAAABJRU5ErkJggg=='/%3E%3C/svg%3E")`
)
}
})
@@ -115,6 +146,7 @@ describe('Future Static Image Component Tests', () => {
appPort = await findPort()
app = await nextStart(appDir, appPort)
html = await renderViaHTTP(appPort, '/static-img')
+ $ = cheerio.load(html)
browser = await webdriver(appPort, '/static-img')
})
afterAll(() => {
@@ -128,6 +160,7 @@ describe('Future Static Image Component Tests', () => {
appPort = await findPort()
app = await launchApp(appDir, appPort)
html = await renderViaHTTP(appPort, '/static-img')
+ $ = cheerio.load(html)
browser = await webdriver(appPort, '/static-img')
})
afterAll(() => {