Webpack file-loader outputs [object Module]
Per the file-loader docs:
By default, file-loader generates JS modules that use the ES modules syntax. There are some cases in which using ES modules is beneficial, like in the case of module concatenation and tree shaking.
It seems that webpack resolves ES module require()
calls to an object that looks like this: {default: module}
, instead of to the flattened module itself. This behavior is somewhat controversial and is discussed in this issue.
Therefore, to get your src
attribute to resolve correctly, you need to be able to access the default
property of the exported module. If you're using a framework, you should be able to do something like this:
<img src={require('assets/logo.png').default}/> <!-- React -->
<!-- OR -->
<img src="require('assets/logo.png').default"/> <!-- Vue -->
Alternatively, you can enable file-loader's CommonJS module syntax, which webpack will resolve directly to the module itself. Set esModule:false
in your webpack config.
webpack.config.js:
{
test: /\.(png|jpe?g|gif)$/i,
use: [
{
loader: 'file-loader',
options: {
esModule: false,
},
},
],
},
@stellr42's suggested fix of esModule: false
in your file-loader
configuration is the best workaround at the current time.
However, this is actually a bug in html-loader
which is being tracked here: https://github.com/webpack-contrib/html-loader/issues/203
It looks like ES Module support was added to file-loader
, css-loader
, and other friends, but html-loader
was missed.
Once this bug is fixed, it will be better to remove esModule: false
and simply upgrade html-loader
, as ES Modules offer some minor benefits (as mentioned in the docs)
Alternatively, if (like me), you found this issue because you were having trouble loading an image from CSS (instead of from HTML), then the fix is just to upgrade css-loader
, no need to disable ES Modules.