5

I have a problem with loading an image using webpack.

When I use an image tag on an html page, everything works fine:

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

But I also have a need to use inline styles:

<div style="background-image: url('../../content/images/logo.png')">

In this case, webpack doesn't resolve the images and leaves the string in the url() untouched.

Webpack config:

        module: {
        rules: [
            { test: /bootstrap\/dist\/js\/umd\//, loader: 'imports-loader?jQuery=jquery' },
            {
                test: /\.ts$/,
                loaders: [
                    'angular2-template-loader',
                    'awesome-typescript-loader'
                ],
                exclude: ['node_modules/generator-jhipster']
            },
            {
                test: /\.html$/,
                loader: 'html-loader',
                options: {
                    minimize: true,
                    caseSensitive: true,
                    removeAttributeQuotes:false,
                    minifyJS:false,
                    minifyCSS:false
                },
                exclude: ['./src/main/webapp/index.html']
            },
            {
                test: /\.scss$/,
                loaders: ['to-string-loader', 'css-loader', 'sass-loader'],
                exclude: /(vendor\.scss|global\.scss)/
            },
            {
                test: /(vendor\.scss|global\.scss)/,
                loaders: ['style-loader', 'css-loader', 'postcss-loader', 'sass-loader']
            },
            {
                test: /\.css$/,
                loaders: ['to-string-loader', 'css-loader'],
                exclude: /(vendor\.css|global\.css)/
            },
            {
                test: /(vendor\.css|global\.css)/,
                loaders: ['style-loader', 'css-loader']
            },
            {
                test: /\.(jpe?g|png|gif|svg|woff2?|ttf|eot)$/i,
                loaders: ['file-loader?hash=sha512&digest=hex&name=/images/[hash].[ext]']
            }
        ]
    },

I would be grateful if someone could help me with this issue.

Scotty Waggoner
  • 3,083
  • 2
  • 26
  • 40
Vladimir Topolev
  • 397
  • 3
  • 21
  • There's an unresolved issue about this https://github.com/webpack-contrib/html-loader/issues/131 – Scotty Waggoner Sep 08 '17 at 21:57
  • There's also a pull request about this, and it has been there since 2020, but still not get merged https://github.com/webpack-contrib/html-loader/pull/279 – Mizok.H Jan 19 '22 at 07:32
  • The alternative I am taking now is to use CopyWebpackPlugin to copy all my background-image source right into /dist, just check my answer below. – Mizok.H Jan 19 '22 at 07:40

7 Answers7

7

You might require your ´html´ file with interpolation flag enabled:

require("html-loader?interpolate!./your-file.html");

...and then require your inlined-style background image like:

<div style="background-image: url('${require(`../../content/images/logo.png`)}')">
Andrea Carraro
  • 9,731
  • 5
  • 33
  • 57
1

Googled myself for solution, and decided to make a loader. https://github.com/apotap2/url-replace-loader It's just 20 lines of code :D it just that replaces every 'url(.*)' with require() so you can use it with file-loader. If you need more complicated logic it seems it's faster to make a loader yourself.

  • Hi, I'm not sure how to install your loader. I'm only used to install with npm :/ Could you help me with that? I'm assuming you just need to rename the "url-replace-loader-master" to "url-replace-loader" and drop it in node_modules. But I can't make it work after that. – TheCat Jul 29 '18 at 17:43
  • you can install via npm install from git repos: `npm install url#branch`, so in my case it can be `npm install https://github.com/apotap2/url-replace-loader`. – Alexander Potapchuk Jul 30 '18 at 09:39
1

Other solution would be (if you dont want to use interpolate flag)

$scope.imageToUse =  require(`../../content/images/logo.png`)

in your controller

and use directly in your background: url({{imageToUse }})

Internally webpack will encode image to base64 and that will be assigned to imageToUse variable which than will rendered to your html page.

This solution is related to implementing webpack in Angular 1.X project. Similar approach can be applied in other cases.

1

On webpack 5, the correct answer will be to use your html-loader.

Change your inline styles:

 ## Heading ##<div background-image="../../content/images/logo.png">

and your html-loader:

  {
    test: /\.html$/i,
    loader: 'html-loader',
    options: {
      minimize: true,
      attributes: {
        list: [
          '...',// All default supported tags and attributes
          {
            tag: 'div',
            attribute: 'data-background',
            type: 'src',
          }
        ]
      }
    }
  }

Here for more details.

0

The most straightforward solution for me was to use interpolate option in Webpack as mentioned in this answer.

{
  test: /\.(html)$/,
  include: path.join(__dirname, 'src/views'),
  use: {
    loader: 'html-loader',
    options: {
      interpolate: true
    }
  }
}

And then in your HTML

 <div style="background-image: url('${require('../../content/images/logo.png')')">
user1319182
  • 481
  • 12
  • 26
0

Very basic just:

<div class="background-design-element" style="background-image: url('<%= require('./../assets/images/test.jpg') %>')"></div>

Key is to remember: <%= =%> It can actually be this simple - :-)

0

interpolate option is removed Since 1.0.0

check the change log here : https://github.com/webpack-contrib/html-loader/blob/master/CHANGELOG.md

Since 1.0.0 , interpolate option is removed, so using url('{require(...)}') is no longer possible.

The alternative I am taking now is to use CopyWebpackPlugin to clone all background-image source into dist (the ouput) folder, and use relative path to get source file in html.

<div style="background-image:url('../assets/images/xx.png')">

But using this way you will also lose the tree-shaking of those background-images source, and it's actually not possible to use source alias in url(), so it is just a temporary way :(

const CopyPlugin = require('copy-webpack-plugin');
...

plugins: [
   ...,
   new CopyPlugin(
      {
        patterns: [
          ...
          { 
            from: 'src/assets/images/background-image',
            to: 'assets/images/background-image',
          }
          
        ]
      }
    )

]
Mizok.H
  • 423
  • 5
  • 15