Webpack-encore: dynamic image not found in react component

Created on 1 May 2020  路  4Comments  路  Source: symfony/webpack-encore

Hello,
Here I try to import and use an image in a react component, but this one is never found :

GET http://localhost:8000/[object%20Module] 404 (Not Found)

I try to access to defaultLogo.png which is in this tree:
https://prnt.sc/s92g2r

Here is my part of the code which is supposed to call and use it:
const pathToLogo = require('../../images/user_logo/${userData.logo_name}'); <img src={pathToLogo} alt=""/>

And here's my webpack encore config :
var Encore = require('@symfony/webpack-encore'); if (!Encore.isRuntimeEnvironmentConfigured()) { Encore.configureRuntimeEnvironment(process.env.NODE_ENV || 'dev'); } Encore .setOutputPath('public/build/') .setPublicPath('/build') .addEntry('app', './assets/js/app.jsx') .splitEntryChunks() .enableSingleRuntimeChunk() .cleanupOutputBeforeBuild() .enableBuildNotifications() .enableSourceMaps(!Encore.isProduction()) .enableVersioning(Encore.isProduction()) .configureBabelPresetEnv((config) => { config.useBuiltIns = 'usage'; config.corejs = 3; }) .enableSassLoader() .enableReactPreset() .copyFiles({ from: './assets/images/', to: 'images/[path][name].[hash:8].[ext]', pattern: /\.(png|jpg|jpeg|svg)$/ }) ; module.exports = Encore.getWebpackConfig();

Knowing that I'm working with "dev-server", but even "dev" or "build" doesn't work...
Any ideas? Do I misunderstand the syntax? I confess I have some trouble with Webpack encore...

Thanks a lot

Most helpful comment

Hi,

I think the issue come from the file-loader where your require('...') is now seen as an ES module.
The issue happens because file-loader has been upgraded from v1 to v6 in #731 and released in Encore v0.29.0:

For now you have two solutions:

  1. use require('../../images/user_logo/${userData.logo_name}').default
  2. or configure the option esModule like this (I haven't tested it locally, but it should works):
Encore
  // if you want to keep using `file-loader`
  .configureLoaderRule('images', rule => {
      rule.options.esModule = false;
  })

  // OR if you want to use `url-loader`
  .configureUrlLoader({
    images: {
      esModule: false
    }
  });

However, I think we should configure esModule: false in Encore by defaut, we broke some builds, even if in the Encore 0.29.0 changelog it says:

Unless you're doing custom configuration, it's unlikely you're affected

馃槄

What do you think @Lyrkan?

All 4 comments

Hi,

I think the issue come from the file-loader where your require('...') is now seen as an ES module.
The issue happens because file-loader has been upgraded from v1 to v6 in #731 and released in Encore v0.29.0:

For now you have two solutions:

  1. use require('../../images/user_logo/${userData.logo_name}').default
  2. or configure the option esModule like this (I haven't tested it locally, but it should works):
Encore
  // if you want to keep using `file-loader`
  .configureLoaderRule('images', rule => {
      rule.options.esModule = false;
  })

  // OR if you want to use `url-loader`
  .configureUrlLoader({
    images: {
      esModule: false
    }
  });

However, I think we should configure esModule: false in Encore by defaut, we broke some builds, even if in the Encore 0.29.0 changelog it says:

Unless you're doing custom configuration, it's unlikely you're affected

馃槄

What do you think @Lyrkan?

@Kocal It works by adding .default to the require!

Thanks for the explanations, I admit it's one of the first projects I use webpack encore and I'm having a little trouble ^^'

Thank you very much!

However, I think we should configure esModule: true in Encore by defaut, we broke some builds

Hm, yeah that could be an issue.

But since Webpack seems to be moving everything to ES modules instead of CommonJS (for good reasons) it's probably better to encourage the same thing and keep the default esModule: true.

There is a third "solution" to this issue : use ES imports instead of require(...) (I think that should be changed in our doc as well... people tend to think they are interchangeable but that's not the case):

// Simple imports - needs to be at the top of your module
import '../images/foo.png' as fooPath;

// Dynamic import
// Edit: Note that it will create an async chunk by default which only
// contains the path. If that's an issue it can be fixed relatively
// easily using the `/* webpackMode: "eager" */ comment or through the
// MinChunkSizePlugin.
import('../images/foo.png').then(({ default: fooPath }) => {
  // use fooPath there
});

// Dynamic import if you can use async functions
const { default: fooPath } = await import('../images/foo.png');

in the Encore 0.29.0 changelog it says:

Unless you're doing custom configuration, it's unlikely you're affected

Maybe we could change that to something along the lines of:

If you are importing images/fonts using the CommonJS syntax (require('foo.png')), you will now need to explicitely retrieve the default export (require('foo.png').default) in order to get the path of the file.
Imports done using the import keyword should not be affected.

(ping @weaverryan)

Edit: actually using dynamic imports would also require .default... but that was already the case before.

I vote for updating the changelog and keeping the default esModule: true

Was this page helpful?
0 / 5 - 0 ratings

Related issues

weaverryan picture weaverryan  路  4Comments

heitorvrb picture heitorvrb  路  4Comments

Aerendir picture Aerendir  路  4Comments

EliuTimana picture EliuTimana  路  4Comments

zek0faws picture zek0faws  路  4Comments