The webpack way to load svg?

Every time I use svg images, I want to provide png fallbacks. I was looking into using the file-loader, but I need to do a bit more:

  • Move svg and png fallback files into the destination folder.
  • Bundle a module for the client to check for svg support.
  • Bundle a module for the client that returns the correct url for the image based on svg support.

I hoped there would be an svg-loader but didn’t find one in the list. Maybe it’s a good idea?

Obviously we only want to check for svg support one time so the svg support test module would be memoized.

I’m using React, so my example would look like this:

my-logo.jsx

var React = require('react');
module.exports = React.createClass({
  render: function () {
    return (
      <img src="{require('my-logo.svg')}" />
    )
  }
});

I would imagine the configs would look something like this:

webpack.config.js

module.exports = {
  module.loaders = [
    { test: /\.svg$/, loader: 'svg-loader' }
  ]
}

Not a requirement in my situation, but a nice to have: the svg-loader could take it one step further and generate the png fallback automatically as well. I’m using gulp-svg2png. The svg-loader can learn something here from gulp-svg2png to generate png. I’m using the scale option to enlarge the png so it is more crisp. Query params could be passed to svg-loader:

webpack.config.js

module.exports = {
  module.loaders = [
    { test: /\.svg$/, loader: 'svg-loader?{png:{scale:2}}' }
  ]
}

What is the “webpack way” to load svgs with png fallbacks? A new loader or some other way?

Author: Fantashit

5 thoughts on “The webpack way to load svg?

  1. You’re right. That would be a task for a dedicated svg-loader. But I think the loader configuration should be a simple query-string like

    module.exports = {
      module.loaders = [
        { test: /\.svg$/, loader: 'svg-loader?pngScale=2' }
      ]
    }

    That’s how other loaders are handling this.

  2. In the meantime, while I was waiting for responses to this issue, this is what I ended up with:

    MyLogo.jsx

    var React = require('react');
    var doesBrowserSupportSVG = require('../utils/doesBrowserSupportSVG');
    
    var logo = require('my-logo/dist/logo.svg');
    var logoSmall = require('my-logo/dist/logo-small.svg');
    
    if (!doesBrowserSupportSVG()) {
      logo = require('my-logo/dist/logo.png');
      logoSmall = require('my-logo/dist/logo-small.png');
    }
    
    var MyLogo = React.createClass({
      render: function () {
        return (
          <a className="my-logo" href="http://me.com">
            <img className="my-logo__large" src={logo} />
            <img className="my-logo__small" src={logoSmall} />
          </a>
        );
      }
    });
    
    module.exports = MyLogo;

    When the code hits the browser, the svg check runs and switches out the logo
    urls if necessary.

    doesBrowserSupportSVG.js

    module.exports = function() {
      return document.implementation.hasFeature('http://www.w3.org/TR/SVG11/feature#Image', '1.1');
    }

    My logo files are output in the same directory as the compiled javascript so it
    works great. I get something like this in my example page:

      <img className="my-logo__large" src="0e02de9a5dbcb596c082639e0ce4315c.png" />

    But I just installed this component with bower into another project and realized
    it’s not so good. Because I need something like this:

      <img className="my-logo__large" src="bower_components/my-bower-component/dist/0e02de9a5dbcb596c082639e0ce4315c.png" />

    Basically, I need the path to the image to match the page to the bundled javascript
    file that referenced it since they will be sitting in the same directory.

    What do I do now?

  3. Issue is not resolved. The question was how-to convert svg to png like that
    { test: /\.svg$/, loader: 'svg-loader?{png:{scale:2}}' }

  4. @sokra perhaps I’m missing the point of webpack but so far my experience hasn’t been good. It promises all these great features but seems to take away some very basic things that in my opinion should just work out of the box. Is there a reason it’s not configured to recognize svg and fonts formats by default? instead of needing all these extra addons and loaders.

    Considering the fact that webpack is used by so many developers worldwide you should take some responsibility for ensuring it’s easy to use. It’s not always our choice to use webpack (frankly I miss gulp) but almost every project I work on now uses webpack.

    What I’d love is a webpack.config.js file with a list of presets set to true/false and lots of comments explaining how to use each loader, something like:

    css: true,
    svg: true,
    fonts: true    // supports ttf, woff, eot as standard
    etc...
    

    then for things like sass some very simple input and outputs options:

    sassInputDirectory: '/sass/*'
    sassOutputDirectory '/css'
    

    You know kinda like how nice and simple things were with gulp? if someone could build this on top of webpack I believe we’d have a new king in the web tool domain.

Comments are closed.