webdiscus / html-bundler-webpack-plugin

Renders Eta, EJS, Handlebars, Nunjucks, Pug, Twig templates "out of the box". Uses HTML template as entry point. Resolves source files of scripts, styles, images in HTML. Supports for Vue.
ISC License
119 stars 12 forks source link

Writing own adapter for responsive-loader #40

Closed webdiscus closed 8 months ago

webdiscus commented 8 months ago

I really liked custom adapters in responsive-loader. I think I would be happy with tools like this in the HTML Bundler Plugin.

vralle commented 8 months ago

Writing own adapter for responsive-loader

It's not correct. I don't have any issues for the responsive-loader and its adapters)

webdiscus commented 8 months ago

It's not correct. I don't have any issues for the responsive-loader and its adapters)

it was new question ;-) You can create new discussion or issue for a question, no problem :-)

=> I don't want to mix topics of conversation.

webdiscus commented 8 months ago

@vralle

did you know that the plugin can work with this responsive-loader?

Here is an example: How to resize and generate responsive images

Here are many test cases:

What exactly is stopping you from writing an adapter for the loader?

vralle commented 8 months ago

Ok. I stopped using this plugin. Responsive Images and Imagemin Webpack have compatibility issues. I settled on the latter, because it covers 100% of the necessary operations with images. Here is the latest adapter I used

// @ts-check

const sharp = require('sharp');

const args = require('../../args');

class SharpAdapter {
  /** @type {sharp.Sharp} */
  image;

  /** @param {string} imagePath */
  constructor(imagePath) {
    this.image = sharp(imagePath);
  }

  /** @returns {Promise<sharp.Metadata>} */
  metadata() {
    return this.image.metadata();
  }

  /**
   * @param {ResizeProps}
   * @returns {Promise<{ data: Buffer; width: number; height: number }>}
   */
  resize({ width, mime, options }) {
    console.log('load Sharp adapter with options:', options);
    return new Promise((resolve, reject) => {
      let resized = this.image.clone().resize(width, null);
      if (!options.rotate) {
        // .toBuffer() strips EXIF metadata like orientation, so portrait
        // images will become landscape. This updates the image to reflect
        // the EXIF metadata (if an EXIF orientation is set; otherwise unchanged).
        resized.rotate();
      }
      if (options.background) {
        resized = resized.flatten({
          background: options.background,
        });
      }

      if (mime === 'image/jpeg') {
        resized = resized.jpeg(args.sharpConfig.jpeg);
      }

      if (mime === 'image/png') {
        resized = resized.png(args.sharpConfig.png);
      }

      if (mime === 'image/webp') {
        resized = resized.webp(args.sharpConfig.webp);
      }

      // rotate
      if (options.rotate && options.rotate !== 0) {
        resized = resized.rotate(options.rotate);
      }

      resized.toBuffer((err, data, { height }) => {
        if (err) {
          reject(err);
        } else {
          resolve({
            data,
            width,
            height,
          });
        }
      });
    });
  }
}

/**
 * @param {string} imagePath
 * @returns {SharpAdapter}
 */
module.exports = (imagePath) => new SharpAdapter(imagePath);

sharp.config.js

// @ts-check

/**
 * @typedef {Object} SharpConfig
 * @property {import('sharp').JpegOptions} [jpeg]
 * @property {import('sharp').Jp2Options} [jp2]
 * @property {import('sharp').JxlOptions} [jxl]
 * @property {import('sharp').WebpOptions} [webp]
 * @property {import('sharp').AvifOptions} [avif]
 * @property {import('sharp').HeifOptions} [heif]
 * @property {import('sharp').GifOptions} [gif]
 * @property {import('sharp').TiffOptions} [tiff]
 * @property {import('sharp').PngOptions} [png]
 */

/**
 * Options for `sharp`
 * @link {https://sharp.pixelplumbing.com/api-output}
 *
 * @type {SharpConfig} config
 */
const config = {
  jpeg: {
    quality: 60,
    chromaSubsampling: '4:2:0',
  },
  png: {
    compressionLevel: 9,
    palette: true,
    adaptiveFiltering: true,
    quality: 92,
  },
  webp: {
    quality: 60, // default 80
    // lossless: true,
    // nearLossless: true,
    alphaQuality: 100,
    smartSubsample: true,
    preset: 'photo', // one of: default, photo, picture, drawing, icon, text
  },
};

module.exports = config;
webdiscus commented 8 months ago

@vralle

here is the usage example image-minimizer of the image-minimizer-webpack-plugin

It works with images in HTML, CSS and in JS.

You can use any asset loader with the Bundler plugin. The plugin works with the Webpack standard module types: