How to use images from sharp module in React and Webpack project

Viewed 1058

Here is a codesandbox I would like the image in it to be processed by the sharp module. I want it to do this because I want this module to web optimize all the images in my React project, and to convert them to webm.

Here's the same codesandbox where I attempt to use ImageSharp

2 Answers

You will need to make some changes:

Webpack.config.js

  1. Move sharp-loader to rules:
const HtmlWebPackPlugin = require("html-webpack-plugin");

module.exports = {
  module: {
    rules: [
      ...
      {
        test: /\.(gif|jpe?g|png|svg|tiff)(\?.*)?$/,
        loader: "sharp-loader",
        query: {
          name: "[name].[hash:8].[ext]",
          cacheDirectory: true,
          presets: {
            // Preset 1
            thumbnail: {
              format: ["webp", "jpeg"],
              width: 200,
              quality: 60
            },
            // Preset 2
            prefetch: {
              // Format-specific options can be specified like this:
              format: { id: "jpeg", quality: 30 },
              mode: "cover",
              blur: 100,
              inline: true,
              size: 50
            }
          }
        }
      }
    ]
  },
  devServer: {
    ...
  },
  plugins: [
    ...
  ]
};

If you are using Webpack 5:

Rule.query is deprecated in favor of Rule.options and UseEntry.options.

Home.js

  1. The sharp-loader will transform logo into an array of one object because of this "outputs":[{"width": 500}]. You will need to use the corresponding object:
import React from "react";
import logo from '../../react-logo.png?{"outputs":[{"width": 500}]}';

export default function Home() {
  return (
    <div>
      <h2>Home</h2>
      <img src={logo[0].url} />
    </div>
  );
}

If you are using require.context it works the same way:


import React from "react";

function importAll(r) {
  return r.keys().reduce((curr, key) => ((curr[key] = r(key)), curr), {});
}

const images = importAll(require.context('./images/?{"outputs":[{"width": 200}, {"width": 150}]}', true, /\.png$/));


export default function Home() {
  return (
    <div>
      <h2>Home</h2>
      <img src={images['./react-logo.png'][0].url} />
    </div>
  );
}

I would create a convert.js in root directory to do the file conversion. check sharp docs.

Then in package.json simply add 'node convert' before any script which needs image conversion specially start and build

    "start": "node convert && react-scripts start",
    "build": "node convert && react-scripts build",

Now any time you start local server or build your app, it first converts the images and then does the rest.

Here is a simple example where convert.js only converts a file named 1.jpeg to output.webp with dimension 320x240. It's all up to you how you like to organize image sizes, folders and files in project so that covert.js can find them and properly convert them.

const sharp = require('sharp');
sharp('1.jpeg')
    .resize(320, 240)
    .toFile('output.webp', (err, info) => { });
Related