Я создал собственный webpack-загрузчик и пытаюсь использовать его в цепочке загрузчиков, но он, похоже, не принимает результат предыдущего загрузчика.
Мой webpack-загрузчик имеет значение 1x, 2x,3x версии предоставленного изображения.Все работает нормально, если я использую его отдельно и переношу на него изображение png или webp.Проблемы начинаются, когда я вставляю его в цепочку загрузчиков.
Это мои правила:
const withResponsiveImages = () => {
config.module.rules.push({
test: /\.(jpe?g|png|webp)$/,
oneOf: [
{
resourceQuery: /(?=.*\?webp)(?=.*\?responsive)/g,
use: [responsiveLoaderConfig, urlLoaderConfig, webpLoaderConfig],
},
{
resourceQuery: /webp/,
use: [urlLoaderConfig, webpLoaderConfig],
},
{
resourceQuery: /responsive/,
use: [responsiveLoaderConfig],
},
],
})
}
Это все конфиги из кода выше:
const responsiveLoaderConfig = {
loader: path.resolve('./utils/loaders/responsive-loader.js'),
options: {
publicPath: '/_next',
},
}
const urlLoaderConfig = {
loader: 'url-loader',
options: {
publicPath: '/_next',
name: '[path][name]-[hash:8].webp',
limit: 8192,
mimetype: 'image/webp',
},
}
const webpLoaderConfig = {
loader: 'webp-loader',
options: {
quality: 20,
},
}
И этокод моего загрузчика:
const path = require('path')
const loaderUtils = require('loader-utils')
const sharp = require('sharp')
const getOutputAndPublicPaths = require('./getOutputAndPublicPaths')
const getLoaderResults = require('./getLoaderResults')
const MIMES = {
jpg: 'image/jpeg',
jpeg: 'image/jpeg',
png: 'image/png',
webp: 'image/webp',
}
module.exports = function loader(content) {
const config = Object.assign({}, loaderUtils.getOptions(this))
const ext = path.extname(this.resourcePath).replace(/\./, '')
const name = (config.name || '[path][name]-[hash:8][pixelDensity].[ext]').replace(
/\[ext\]/gi,
ext,
)
const createFile = ({ data, pixelDensity }) => {
const outputContext =
config.context || this.rootContext || (this.options && this.options.context)
const fileName = loaderUtils
.interpolateName(this, name, {
context: outputContext,
content: data,
})
.replace(/\[pixelDensity\]/gi, `@${pixelDensity}`)
const { outputPath, publicPath } = getOutputAndPublicPaths(fileName, config)
this.emitFile(outputPath, data)
return publicPath
}
const loaderCallback = this.async()
const mime = MIMES[ext]
if (!mime) {
return loaderCallback(new Error('No mime type for file with extension ' + ext + 'supported'))
}
const image = sharp(this.resourcePath)
if (config.disable) {
const publicPath = createFile({ data: content, pixelDensity: '3x' })
image.metadata().then(({ width, height }) => {
const file = {
path: publicPath,
width,
height,
pixelDensity: '1x',
}
const files = [{ ...file }, { ...file, pixelDensity: '2x' }, { ...file, pixelDensity: '3x' }]
loaderCallback(null, getLoaderResults(files))
})
}
return image
.metadata()
.then(({ width, height }) => {
let promises = []
const width1x = width / 3
const height1x = height / 3
if (!Number.isInteger(width1x) || !Number.isInteger(height1x)) {
console.warn(
`Width (${width}) or height (${height}) of the image ${
this.resourcePath
} is not divided by 3, additional compression losses are possible`,
)
}
const pixelDensities = ['1x', '2x', '3x']
pixelDensities.forEach(pixelDensity => {
const width1xNormalized = Math.floor(width / 3)
const height1xNormalized = Math.floor(height / 3)
const newWidth = width1xNormalized * parseInt(pixelDensity)
const newHeight = height1xNormalized * parseInt(pixelDensity)
promises.push(
new Promise((resolve, reject) => {
image
.clone()
.resize({
width: newWidth,
height: newHeight,
})
.toBuffer((err, data) => {
if (err) {
reject(err)
} else {
const publicPath = createFile({ data, pixelDensity })
resolve({
data,
path: publicPath,
width: newWidth,
height: newHeight,
pixelDensity,
})
}
})
}),
)
})
return Promise.all(promises).then(files => files)
})
.then(files => loaderCallback(null, getLoaderResults(files)))
.catch(err => loaderCallback(err))
}
module.exports.raw = true
Я ожидаю, что загрузчик вернет мне объект с путями к сгенерированным изображениям webp, например:
const images = {
images: [
{
path: '/_next/static/images/docs/desktop.all/ultramarine@3x-01241826@1x.webp',
width: 97,
height: 165,
pixelDensity: '1x',
},
{
path: '/_next/static/images/docs/desktop.all/ultramarine@3x-69f9dfb0@2x.webp',
width: 194,
height: 330,
pixelDensity: '2x',
},
{
path: '/_next/static/images/docs/desktop.all/ultramarine@3x-95b670d2@3x.webp',
width: 291,
height: 495,
pixelDensity: '3x',
},
],
imagesByResolution: {
'1x': {
path: '/_next/static/images/docs/desktop.all/ultramarine@3x-01241826@1x.webp',
width: 97,
height: 165,
},
'2x': {
path: '/_next/static/images/docs/desktop.all/ultramarine@3x-69f9dfb0@2x.webp',
width: 194,
height: 330,
},
'3x': {
path: '/_next/static/images/docs/desktop.all/ultramarine@3x-95b670d2@3x.webp',
width: 291,
height: 495,
},
},
image1x: '/_next/static/images/docs/desktop.all/ultramarine@3x-01241826@1x.webp',
image2x: '/_next/static/images/docs/desktop.all/ultramarine@3x-69f9dfb0@2x.webp',
image3x: '/_next/static/images/docs/desktop.all/ultramarine@3x-95b670d2@3x.webp',
srcSet:
'/_next/static/images/docs/desktop.all/ultramarine@3x-01241826@1x.webp 1x,/_next/static/images/docs/desktop.all/ultramarine@3x-69f9dfb0@2x.webp 2x,/_next/static/images/docs/desktop.all/ultramarine@3x-95b670d2@3x.webp 3x',
toString: [Function: toString]
}
, но он возвращает тот же объект,но с PNG изображениями.При этом url-загрузчик создает изображение webp в выходном каталоге.Это означает, что он работает, но не передает результат в отзывчивый порядок.Почему?Что я не так сделал?