40

I am using HTMLWebpackPlugin and in my template I have an img tag:

<img src="./images/logo/png">

If you notice, here I am using a relative path thinking webpack will trigger the file loader that's configured in my webpack.config.js file but after compilation I get the exact same src attribute in my html:

<img src="./images/logo/png">

How can I trigger webpack to dynamically replace these relative paths with, well whatever I've configured in my webpack configuration?

Anonymous
  • 1,658
  • 2
  • 14
  • 19

5 Answers5

41

I'm not a webpack expert, but i got it to work by doing this:

<img src="<%=require('./src/assets/logo.png')%>">

Plugin config

new HtmlWebpackPlugin({
    filename: 'index.html',
    template: 'index.html'
  }),

According to the docs: https://github.com/jantimon/html-webpack-plugin/blob/master/docs/template-option.md

By default (if you don't specify any loader in any way) a fallback lodash loader kicks in.

The <%= %> signifies a lodash template

Under the hood it is using a webpack child compilation which inherits all loaders from your main configuration.

Calling require on your img path will then call the file loader.

You may run into some path issues, but it should work.

Legends
  • 21,202
  • 16
  • 97
  • 123
Eric Guan
  • 15,474
  • 8
  • 50
  • 61
  • 1
    I got it to working like this, too. But the problem is I **am** using a custom loader. To be specific I am using handlebars. And it doesn't seem to support direct function calls inside templates. And secondly it looks pretty messy. I'd hate do it over and over again. I have dozens of html pages with lots of images in it. – Anonymous Nov 05 '17 at 22:36
  • 1
    Upvoted, but it bums me out that there's not an easy way to get non-required image sources playing nicely with this plugin. – Alexander Nied Mar 27 '19 at 04:26
  • 1
    Result: `src="[object Module]"` – Arthur Shlain Jul 09 '20 at 09:52
  • 5
    @arthur src="[object module]" is resolved by setting esModule: false in the rule.options section of the loader. See https://stackoverflow.com/a/62687448/2784280. – Anthony Sep 18 '20 at 10:15
32

Using html-loader with HTML webpack plugin worked for me.

module: {
    rules: [
      {
         test: /\.(html)$/,
         use: ['html-loader']
      }
    ]
},
plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    })
  ]
Norma Mendonca
  • 321
  • 3
  • 5
  • Hi Norma, I followed your advice, but it seems this is not enough. I get error "appropriate loader is needed". So you should have used something else apart from htmlwebpackplugin and html-loader – Denis Jun 10 '20 at 08:08
  • @Denis Yes, you'll need an additional loader depending on the file type. Check out https://webpack.js.org/guides/asset-management/ for some examples. – brettinternet Sep 15 '20 at 18:29
  • 2
    This worked as far as it allowed WebPack to pick up (import) the images from HTML tags without the use of require statements, but it prevented _lodash <%= %> being interpreted by HTMLWebpackPlugin (leaving the text untranslated) and I couldn't find a fix for that. See https://github.com/jantimon/html-webpack-plugin/issues/223 – Anthony Sep 18 '20 at 10:10
  • Exactly what I needed! I suppose if I was using lodash expressions (`<%=%>`) then I'd have to choose which way to go, but until then, this is excellent – lance.dolan Oct 13 '21 at 19:03
  • You may need to disable `esModule`: `use: [{ loader: 'html-loader', options: { esModule: false } }],` – Vahid Jul 01 '22 at 04:17
12

You should use the CopyWebpackPlugin.

const CopyWebpackPlugin = require('copy-webpack-plugin');

plugins:[
    ....
    new CopyWebpackPlugin({'patterns': [
        {from:'./src/assets/images', to:'images'}
    ]}),
    ....
]

This is copy the src/assets/images to your `distfolder/images'.

Themis
  • 409
  • 3
  • 13
Voro
  • 235
  • 1
  • 12
0

You could use url-loader in your webpack config to add images below a certain limit encoded as base64 uri's in your final bundle and images above the limit as regular image tags (relative to the publicPath)

module.rules.push({
  test: /\.(png|jp(e*)g|gif)$/,
  exclude: /node_modules/,
  use: [{ 
    loader: 'url-loader',
    options: {
      limit: 10000,
      publicPath: "/"
    }
  }]
})
varoons
  • 3,807
  • 1
  • 16
  • 20
0

I ran into this issue while following the Getting Started guide that Webpack provides. I was using the template code from the guide and bundling images. But then when migrating an existing vanilla html/js/css project to use Webpack, I discovered that in order to use the template HTML loading like I wanted -- with paths to image resource contained in the template -- I had to remove the asset loader usage from my webpack.config.js for the html-loader to properly resolve the new hashed paths it was creating in dist

To use Webpack doc syntax, remove the lines prefixed with "-" and add the lines prefixed with "+"

module: {
  rules: [
    {
      - test: /\.(png|svg|jpg|jpeg|gif)$/i,
      - type: 'asset/resource',
      + test: /\.(html)$/,
      + use: ['html-loader'],
    }
  ]
}
jseashell
  • 745
  • 9
  • 19