Webpack: load images from inline style (background-image)
Asked Answered
A

7

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.

Absquatulate answered 21/5, 2017 at 12:17 Comment(3)
There's an unresolved issue about this github.com/webpack-contrib/html-loader/issues/131Mescal
There's also a pull request about this, and it has been there since 2020, but still not get merged github.com/webpack-contrib/html-loader/pull/279Botanomancy
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.Botanomancy
C
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`)}')">
Culp answered 21/5, 2017 at 18:38 Comment(1)
Nice, didn't know about ${require('')} in this case. Thanks!Enloe
P
2

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.

Perjured answered 8/11, 2020 at 7:40 Comment(1)
HTML should be <div data-background="../../content/images/logo.png">. Please notice attribute name data-background instead of background-image in this answer.Tumular
G
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.

Gingrich answered 2/7, 2018 at 16:54 Comment(2)
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.Gupton
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.Gingrich
D
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.

Dialogue answered 24/12, 2018 at 12:36 Comment(0)
G
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')')">
Grin answered 4/8, 2019 at 16:56 Comment(1)
the interpolate option is now removed, so this is no longer working.Botanomancy
D
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 - :-)

Didache answered 19/5, 2020 at 13:29 Comment(0)
B
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',
          }
          
        ]
      }
    )

]
Botanomancy answered 19/1, 2022 at 7:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.