rsnext/packages/next/build/webpack/loaders/next-image-loader.js

107 lines
3.4 KiB
JavaScript
Raw Normal View History

import loaderUtils from 'next/dist/compiled/loader-utils3'
import { resizeImage, getImageSize } from '../../../server/image-optimizer'
const BLUR_IMG_SIZE = 8
const BLUR_QUALITY = 70
const VALID_BLUR_EXT = ['jpeg', 'png', 'webp', 'avif'] // should match next/client/image.tsx
function nextImageLoader(content) {
const imageLoaderSpan = this.currentTraceSpan.traceChild('next-image-loader')
return imageLoaderSpan.traceAsyncFn(async () => {
const { isServer, isDev, assetPrefix, basePath } = this.getOptions()
const context = this.rootContext
const opts = { context, content }
const interpolatedName = loaderUtils.interpolateName(
this,
'/static/media/[name].[hash:8].[ext]',
opts
)
const outputPath = assetPrefix + '/_next' + interpolatedName
let extension = loaderUtils.interpolateName(this, '[ext]', opts)
if (extension === 'jpg') {
extension = 'jpeg'
}
const imageSizeSpan = imageLoaderSpan.traceChild('image-size-calculation')
const imageSize = await imageSizeSpan.traceAsyncFn(() =>
getImageSize(content, extension).catch((err) => err)
)
if (imageSize instanceof Error) {
const err = imageSize
err.name = 'InvalidImageFormatError'
throw err
}
let blurDataURL
let blurWidth
let blurHeight
if (VALID_BLUR_EXT.includes(extension)) {
// Shrink the image's largest dimension
if (imageSize.width >= imageSize.height) {
blurWidth = BLUR_IMG_SIZE
blurHeight = Math.max(
Math.round((imageSize.height / imageSize.width) * BLUR_IMG_SIZE),
1
)
} else {
blurWidth = Math.max(
Math.round((imageSize.width / imageSize.height) * BLUR_IMG_SIZE),
1
)
blurHeight = BLUR_IMG_SIZE
}
if (isDev) {
// During `next dev`, we don't want to generate blur placeholders with webpack
// because it can delay starting the dev server. Instead, we inline a
// special url to lazily generate the blur placeholder at request time.
const prefix = 'http://localhost'
const url = new URL(`${basePath || ''}/_next/image`, prefix)
url.searchParams.set('url', outputPath)
url.searchParams.set('w', blurWidth)
url.searchParams.set('q', BLUR_QUALITY)
blurDataURL = url.href.slice(prefix.length)
} else {
const resizeImageSpan = imageLoaderSpan.traceChild('image-resize')
const resizedImage = await resizeImageSpan.traceAsyncFn(() =>
resizeImage(content, blurWidth, blurHeight, extension, BLUR_QUALITY)
)
const blurDataURLSpan = imageLoaderSpan.traceChild(
'image-base64-tostring'
)
blurDataURL = blurDataURLSpan.traceFn(
() =>
`data:image/${extension};base64,${resizedImage.toString('base64')}`
)
}
}
const stringifiedData = imageLoaderSpan
.traceChild('image-data-stringify')
.traceFn(() =>
JSON.stringify({
src: outputPath,
height: imageSize.height,
width: imageSize.width,
blurDataURL,
blurWidth,
blurHeight,
})
)
Imageloader: collect images serverside to include images from staticp… (#41554) In #41548, I show that I would like to provide an object with images in getStaticProps. The StaticImageData is parsed correctly and provided as a prop to the page. Nonetheless, the image is not available in the static directory. Therefore the image is not shown. This is also addressed in issue #29571. The underlying cause is that the import of the image is removed from the client bundle and only present in the server bundle. Evaluating the next-image-loader shows that the file is only placed in the static directory if emitted from the client bundle by firing this.emitFile. By changing this to only emitting the file from the serverside bundle in the webpackloader, static images loaded in the getStaticProps are made available properly as well as images directly used in componts (so present in server and client bundle). This would PR would prevent the circumventing solution which enforces that the StaticImageData should be present in the client side bundle while it will also be present in the staticprops. <!-- Thanks for opening a PR! Your contribution is much appreciated. To make sure your PR is handled as smoothly as possible we request that you follow the checklist sections below. Choose the right checklist for the change that you're making: --> ## Bug - [x] Related issues linked using `fixes #number` - [x] Integration tests added - [ ] Errors have a helpful link attached, see `contributing.md` Closes #42783, Fixes #42443 Co-authored-by: Diederik <diederik@digitalpatrol.nl>
2022-11-23 15:28:53 +01:00
if (isServer) {
this.emitFile(
`../${isDev ? '' : '../'}${interpolatedName}`,
content,
null
)
}
return `export default ${stringifiedData};`
})
}
export const raw = true
export default nextImageLoader