我创建了自定义的webpack-loader,并尝试在加载程序链中使用它,但是它似乎不接受先前加载程序的结果。
我的webpack-loader制作了所提供图像的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图像。这意味着它可以工作,但不会将结果传递给响应顺序。为什么?我做错了什么?