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

2

6

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

Folse answered 10/5, 2021 at 19:53 Comment(3)
Thanks for your complete question alongside sandbox, I upvoted you.Gush
When I open you codesandbox link I get this error "Could not find module in path: '' relative to '/package.json'", this is what are you trying to fix?Mudpack
@Mudpack The second sandbox won't work because of the line '../../react-logo.png?{"outputs":[{"width": 500}]}'; this is how sharp reads images from what I've read thoughFolse
I
2

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) => { });
Inflate answered 15/5, 2021 at 16:59 Comment(3)
There's no convert.js example in that linkFolse
Where do the images get saved to?Folse
In the above example , original and converted images are in root directoryInflate
M
5

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>
  );
}
Mudpack answered 17/5, 2021 at 17:0 Comment(5)
I get this when I do that Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema. - configuration.module.rules[2] has an unknown property 'query'. These properties are valid:Folse
Hi @Folse what version of Webpack are you using?Mudpack
This is a fantastic solution! Any idea how one could import multiple images and do the same thing? Say for an image gallery with thumbnails? e.g importAll(require.context('../../photos', false, /\.(png|jpe?g|svg)$/));Antisana
Also - any guidance on getting this to work with webpack 5?Antisana
@Antisana I added an example using require.context. If you are using Webpack 5 just replace the property query with options.Mudpack
I
2

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) => { });
Inflate answered 15/5, 2021 at 16:59 Comment(3)
There's no convert.js example in that linkFolse
Where do the images get saved to?Folse
In the above example , original and converted images are in root directoryInflate

© 2022 - 2024 — McMap. All rights reserved.