Цепочка загрузчиков Webpack с настраиваемым webpack-загрузчиком - PullRequest
0 голосов
/ 28 сентября 2019

Я создал собственный 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 в выходном каталоге.Это означает, что он работает, но не передает результат в отзывчивый порядок.Почему?Что я не так сделал?

...