Search code examples
webwebpackurlloadersvelte-3

Does the url-loader plugin inline URLs in <img> tags, how?


Udate:

Although I haven't been able to find out whether this is a feature or a bug. It seems url-loader can't process the assets used in the Svelte component unless those are loaded via require. So I would like to know what's the more common or recommended way to load/preprocess, using Webpack 4, a Svelte component source so that all image assets used in src/url in HTML tags and CSS styles get inlined, i.e. converted to use the embedded base64 data in the HTML or CSS output files.

Original Question

I want to have a tag <img src="./assets/logo.png"> in a svelte component to be converted to <img src="data:image/png;base64,iV...CC"> in the output, but if I add url-loader to my webpack.config.js file like so:

module: {
  rules: [
    //...
    {
      test: /logo.png/,
      loader: (process.stdout.write("!!!\n"), 'url-loader')
    }

The URL in src does still appear as "./assets/logo.png" in the output even is the console shows "!!!" during the webpack build process with no errors, why is url-loader not making the conversion? The file logo.png is about 3KB in size, but I'm not sure is that's the problem since it's small in size.

The image is being used here like so:

<div id="app">
{#if path === '/'}
  <span on:click={navigateToSettings} id="menu"><div class="hamburger" /></span>
{/if}
{#if path === '/settings' && isStored()}
  <span on:click={cancel} id="menu"><div class="close" /></span>
{/if}
  <img class='logo' src='./assets/img/logo.png' alt='Spark'>
{#if connected}
  <span id="status" class="green">•</span>
{:else}
  <span id="status" class="red">•</span>
{/if}
  <div id="content">
    <RouterView />
  </div>
</div>

And I'm adding the url-loader rule here before the rule for audio files:

module: {
  rules: [
    //...
    {
      test: /logo.png/,
      loader: (process.stdout.write("!!!\n"), 'url-loader')
    },
    {
      test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
      loader: 'url-loader'
    },

Solution

  • If you use webpack and url-loader with any of modern frontend frameworks it is a common practice to use images via require.
    Example from react world:

    import iconMore from “../path_to_image/name_of_image.jpg”;
    
    const Icon = (props) => {
      return <img src={iconMore} />
    }
    

    for more examples please see this question.

    Also I found svelte-assets-preprocessor - you can use it in pair with url-loader without direct require, but under the hood it is the same technique:

      module: {
        rules: [
          ...
          {
            test: /\.(png|svg|jpg|gif)$/,
            loader: 'file-loader',
            options: {
              outputPath: 'images',
            }
          },
          {
            test: /\.(html|svelte)$/,
            exclude: /node_modules/,
            use: {
              loader: 'svelte-loader',
              options: {
                preprocess: require('svelte-assets-preprocessor')({ /* options */ exclude: [ (attr) => !/\.(png|svg|jpg|gif)$/.test(attr)} ])
              },
            },
          },
          ...
        ]
      }
    

    Input

    <img src="./example.png">
    

    Output

    <script>
        import ___ASSET___1 from './example.png';
    </script> 
    
    <img src="{___ASSET___1}">