Working with images in multiple formats I've been doing some research around how to best make use of the WebP images (with fallback) in React. Most solutions point to something similar to what I've written below. That means if I have a lot of images I have to export the same image twice in assets.js (both PNG and WebP), import twice and provide two Image props for the same image.
This feels very inefficient. Is this an uncommon way of working with images? Is there a better way for working with images that live locally?
assets.js - where I collect all my assets and export them as strings. Imagine this list being really lengthy.
export { default as image1 } from &quot;./assets/image-1.png&quot;;
export { default as image1Webp } from &quot;./assets/image-1.webp&quot;;

In the file I import the assets I need for that page
import {
    image1,
    image1Webp
} from &quot;./assets&quot;;

The component + props
&lt;Image
  src={image1Webp}
  fallback={image1}
  alt=&quot;Lorem&quot;
/&gt;

Image.js component
const Image = ({
  src,
  fallback,
  type = 'image/webp',
  ...delegated
}) =&gt; {
  return (
    &lt;picture&gt;
      &lt;source srcSet={src} type={type} /&gt;
      &lt;img src={fallback} {...delegated} /&gt;
    &lt;/picture&gt;
  );
};


Some things I've tried:
Generally the recommended way is to add images to a React project is to use require(img/path). So I tried things like appending .png or .webp to the base URL, inside the Image component. so I only need to define one string and then the component handles the splitting.
e.g. pseudocode:
export const toWEBP = (src) =&gt; {
  const location = src.split(&quot;.&quot;)
  return `${location}.webp`
}
It would be great if the code could be simplified using dynamic imports.  I haven't tried this myself but if the image names could be put into an array then something like the following might work, where the exported images are set as properties on an object that can be exported. When this SO answer to Create a loop to import files dynamically in React was written only Chrome and Safari supported that feature but since then it appears that Edge and Firefox now offer support as well.
const images = {};
const nums = [1, 2];
for (const format of  ['png', 'webp']) {
  for (const num of nums) {
    const key = `image${num}` + format === 'webp' ? 'webp' : '';
    images[key] =  await import( `./assets/image-${num}.${format}`);
  }
}

But according to the Hacks blog post by Jason Orendorff ES6 In Depth: Modules

For a dynamic language, JavaScript has gotten itself a surprisingly static module system.

All flavors of import and export are allowed only at toplevel in a module. There are no conditional imports or exports, and you can’t use import in function scope.
All exported identifiers must be explicitly exported by name in the source code. You can’t programmatically loop through an array and export a bunch of names in a data-driven way.


So the function code above could be exported in an async function:
export async function getImages() {
    const images = {};
    //...set keys on images
    return images;
}

Then that function can be imported:
import { getImages } from './assets.js';

But to use that function it would need to be run in an async function:
(async () =&gt; {
  const images = await getImages();
  //use images
})();

Other approaches are listed in answers to this similar post on freecodecamp.org - e.g. from this answer by Dan Couper:

One pretty simple solution:


// images.js
const images = [
  { id: 1, src: './assets/image01.jpg', title: 'foo', description: 'bar' },
  { id: 2, src: './assets/image02.jpg', title: 'foo', description: 'bar' },
  { id: 3, src: './assets/image03.jpg', title: 'foo', description: 'bar' },
  { id: 4, src: './assets/image04.jpg', title: 'foo', description: 'bar' },
  { id: 5, src: './assets/image05.jpg', title: 'foo', description: 'bar' },
  ...etc
];
export default images;



// MyComponent.js
import images from './images'
//...snip
{ images.map(({id, src, title, description}) =&gt; &lt;img key={id} src={src} title={title} alt={description} /&gt;)

You’re basically writing a database of images that match the ones in assets.
Then you can be clever in images.js to pull the correct prefix based on the environment if you want. There will be a WebPack plugin that kinda does this as well if you have a google around (you want it to take a directory of files and generate an iterable set of paths to them).
The import as described is more for importing one-off images (logos etc) rather than importing lots of images from a directory.


Regarding the pseudocode at the end of the post:

export const toWEBP = (src) =&gt; {
  const location = src.split(&quot;.&quot;)
  return `${location}.webp`
}


if src contained an extension (e.g. png) then webp would be appended to that existing extension. One option would be to use pop to remove the existing extension and also push webp onto the array before using it in the return value.