How do I load images with loadImage() and webpack?

Hello, I am using p5 in instance mode with an Express server in Node.js. I am importing the p5.js library via npm and webpack rather than with an inline script tag on an html document. This has been working fine, but I’ve hit a wall now that I’m trying to import images.
I worked through the Asset Management guide on webpack.js.org, and successfully loaded images via .css document, indicating that webpack and the file-loader module are configured correctly. However, when trying to load an image with p5 using loadImage(), webpack sends the following error upon building the bundle:

You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file.

Here’s how everything is configured (please excuse the silly image file names):

webpack.config.js:

const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist')
  },
  module:{
    rules: [
      {
        test: /\.css$/,
        use: [
          'style-loader',
          'css-loader'
        ],
      },
      {
        test: /\.(png|svg|jpg|gif)$/,
        use: [
          'file-loader'
        ]
      }
    ]
  }
};

index.js (see line 14, which causes the error):

import p5 from 'p5';
import Planet from './modules/Planet.js';
import './style.css';
import './assets/zuckervoid.jpg';

const containerElement = document.getElementById('p5-container');

const sketch = (p) => {
  let np = 5;

  let planets = [];
  let planet_texture;
  p.preload = function(){
    planet_texture = p.loadImage('./assets/zuckervoid.jpg',,(e) => {
      //if image fails...
      console.log(e);
    });
  };

  p.setup = function() {
    p.createCanvas(p.windowWidth, p.windowHeight, p.WEBGL);
    for(let i = 0; i < np; i++){
      let x = Math.floor(Math.random()*p.width);
      let y = Math.floor(Math.random()*p.height);
      planets.push(new Planet(p,x,y));
    }
  };

  p.draw = function() {
    p.background(0);
    p.push();
    p.translate(-p.width/2,-p.height/2);
    for(let i = 0; i < np; i++){
      planets[i].run();
    }
    p.pop();
  };
};

new p5(sketch, containerElement);


index.html:

<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>FictiveMusic</title>
  <link rel="shortcut icon" href="£"></link>
</head>
<body>
  <div id="p5-container"></div>
  <script src="main.js">
    </script>
</body>
</html>

Sorry in advance, I’m not familiar with Webpack, but I did find this, maybe it can start you off?

1 Like

To anyone having the same problem in the future, I’ve found the solution. I just wasn’t really understanding how webpack works.
When importing image assets using Webpack’s built-in Asset Modules loaders, a path to the image in the output directory is returned and stored in the name of the asset you’ve used in your import statement.
I’ve changed by above code to the following:

Relevant section of webpack.config.js:

const path = require('path');

module.exports = {
  module:{
    rules: [
      {
        test: /\.(png|svg|jpg|gif)$/,
        type: 'asset/resource'
      }
    ]
  },
  entry: {
    index: './src/index.js'
  },
  output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, 'dist'),
    publicPath: '/'
  },
};

Relevant section of index.js:

import zuckervoid from './assets/zuckervoid.jpg'; //zuckervoid will contain the path to the copy of this image emitted by webpack in the ouput folder

const sketch = (p) => {

  let planet_texture;

  p.preload = function(){
    planet_texture = p.loadImage(zuckervoid); //this works because zuckervoid is the path to an image file
  };
//etc....

Read the “Loading Images” section of this guide on Webpack’s website for more information on this.

2 Likes