responsive-loader icon indicating copy to clipboard operation
responsive-loader copied to clipboard

How to reference different sizes in a template

Open bparticle opened this issue 5 years ago • 6 comments

Responsive-loader is generating all my images beautifully with the correct names and sizes, but I can't figure out how to reference other sizes than the default (smallest one) in my template!

// webpack.config file
...
{
  test: /\.(jpe?g|png)$/i,
  loader: 'responsive-loader',
  options: {
    adapter: require('responsive-loader/sharp'),
    sizes: [600, 1200],
    placeholder: true,
    placeholderSize: 50,
    name: '/assets/img/[hash]-[width].[ext]'
  }
},
...

And this is how I'm referencing the images in my template html

  <img src="${require('./assets/img/image_0.jpg')}" alt="">

This gives me the 600px wide image and I would like to get different images based on screen size. Any pointers?

bparticle avatar Aug 23 '18 21:08 bparticle

@bparticle – do

<script>
  const responsiveImage = require( './assets/img/image_0.jpg');
</script>

And then use in your HTML

<img src={responsiveImage.src} srcset={responsiveImage.srcSet} alt="">

And your srcSet will be set up.

Melzmr avatar Aug 25 '18 20:08 Melzmr

@Melzmr Thanks for your reply! Your answer makes perfect sense, and it is one of the options out of many I tried, but somehow nothing works. I'm still scratching my head over this but can't let it go. I'm using Vue.js at the moment and this is the code I'm currently testing:

<template>
<div id="app">
  <h1>{{ greeting }}</h1>
  <p>{{srcTest}}</p>
  <p>{{src}}</p>
  <p>{{srcSet}}</p>
  <img :src="src">
  <br>
</div>
</template>

<script>
const responsiveImage = require("./assets/img/image_0.jpg");

export default {
  name: "app",
  data: function() {
    return {
      greeting: "Hello",
      srcTest: responsiveImage,
      src: responsiveImage.src,
      srcSet: responsiveImage.srcSet
    };
  }
};
</script>

The only positive response I get is the raw responsiveImage reference in the first <p> tag. It's outputting the base64 code that is supposed to contain the image (data:image/jpeg;base64,bW9kdWxlLmV4cG9ydH......). If I put this in the image tag however I get a broken image link. The other tests aren't outputting anything at all (responsiveImage.src and .srcSet).

bparticle avatar Aug 29 '18 17:08 bparticle

@bparticle looks like you have another loader hijacking your image (probably url-loader?) …

jstcki avatar Aug 29 '18 21:08 jstcki

@herrstucki That will be the case probably. I think the way vue-cli is implementing its webpack configuration is awkward to say the least. I tried to set it up like this:

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

// vue.config.js
module.exports = {
  chainWebpack: config => {
    config.module
      .rule('images')
      .use('responsive-loader')
      .loader('responsive-loader')
      .options({
        adapter: require('responsive-loader/sharp'),
        sizes: [600, 1200],
        placeholder: true,
        placeholderSize: 50,
        name: '/assets/img/[hash]-[width].[ext]'
      });
  },
  configureWebpack: {
    plugins: [
      new BundleAnalyzerPlugin()
    ]
  }
}

But the trouble with that setup is not immediately relevant to this repository I suppose!

bparticle avatar Aug 29 '18 21:08 bparticle

I found the issue (and it cost me many hours so I hope this may help anyone in the same situation). My images were not displayed due to the preceding slash that I put in the responsive-loader configuration (see previous code example). Also I changed the way I implement the loader in the vue-cli setup. This setup has fixed my problem:

// vue.config.js
module.exports = {
  chainWebpack: config => {
    const imgRule = config.module.rule('images');
    imgRule.uses.clear();
    imgRule
    .use('responsive-loader')
    .loader('responsive-loader')
    .options({
      adapter: require('responsive-loader/sharp'),
      sizes: [600, 1200],
      placeholder: true,
      placeholderSize: 50,
      name: 'assets/img/[hash]-[width].[ext]'
    });
  }
}

So name: 'assets/img/[hash]-[width].[ext]' instead of name: '/assets/img/[hash]-[width].[ext]'. This is not a vue-cli specific fix so I think it is useful to post back my solution.

bparticle avatar Aug 30 '18 13:08 bparticle

For other templates using html-loader this can be accomplished by using multiple source elements. Here's a pug example:

picture
    source(media='(min-width: 1024px)', srcset=`${src}?size=1280`)
    source(media='(min-width: 768px)', srcset=`${src}?size=1024`)
    source(media='(min-width: 640px)', srcset=`${src}?size=768`)
    source(media='(min-width: 481px)', srcset=`${src}?size=640`)
    img(src=`${src}?size=481`, loading='lazy', alt=alt)

Multiple source elements are required in this case since html-loader won't transform a single srcset with multiple target resolutions.

brettinternet avatar Sep 17 '20 19:09 brettinternet