Gatsby: [v2] Is that possible to overwrite `url-loader` ?

Created on 19 Jun 2018  路  13Comments  路  Source: gatsbyjs/gatsby

Hello guys,

First of all, I would like to thank you for the amazing work done for this v2. I'm in the middle of our website migration, and I have one question.

Summary

After checking the Gatsby's sources, it turns out that almost all media files are handled by the url-loader webpack loader. I'm trying to replace it by three other loaders:

I would like to:

  • Disable url-loader for all images / videos / audio
  • Use the following rules to achieve my goal:
      {
        test  : /\.(jpe?g|png|gif)$/i,
        use   : [{
          loader  : "file-loader",
          options : { name: `static/[name].${hash.file}.[ext]` }
        }, {
          loader  : "image-webpack-loader",
          options : {
            bypassOnDebug : true,
            mozjpeg       : { progressive: true },
            optipng       : { optimizationLevel: 7 },
            gifsicle      : { interlaced: false },
            pngquant      : { quality: "65-90", speed: 4 }
          }
        }]
      }, {
        test    : /\.(mp4|webm|ogv|wav|mp3|m4a|aac|oga)(\?.*)?$/,
        use   : [{
          loader  : "file-loader",
          options : {
            name: `static/[name].${hash.file}.[ext]`
          }
        }]
      }, {
        test : /SvgIcon\/images\/([a-zA-Z0-9-_])+\.svg?$/i,
        use  : ["svg-sprite-loader"]
      }

But I cannot figure out how to disable url-loader. Is there any way of achieving this?

What I tried

The brand new Gatsby version provides two actions in order to customize Webpack:

  • setWebpackConfig: let me create new rules, but not disable / delete existing ones
  • replaceWebpackConfig: create a configuration from scratch, but that's overkill and will be a real pain to maintain with future Gatsby's updates

Is that even possible? :)
Or at least, to edit the test and/or add an exclude parameter.

question or discussion

Most helpful comment

We're using this same solution. I'm curious if now nearly 2 years later there might be a better one. I'm porting an existing universal app over to gatsby and need a specific loader for svg files (svg-inline-loader). Changing that would require us having to change too much of our app. The reducer for editing the regex for gatsby's loader test: /\.(ico|svg|jpg|jpeg|png|gif|webp)(\?.*)?$/ to remove |svg is just absurd. Leaving that regex as is and simply adding my loader via setWebpackConfig results in the svg content being replaced with data:.

All 13 comments

There is getConfig function passed to onCreateWebpackConfig hook which will let you get your entire webpack config - possibly you could get that and manipulate just rules you need there and then use replaceWebpackConfig?

@pieh I had no knowledge about this function. I'm gonna make a try and will come back to you. Thanks!

Also I think if you use setWebpackConfig it will update a particular key you target.

Also if you think our default settings should be changed in any ways, please say something! Much rather the core settings are perfect then you and others have to maintain changes like these :-)

Can you talk about why you explicitly want to use file-loader. Url-loader _is_ file-loader except that it in lines small files, which is generally preferable, otherwise it's behavior is exactly the same as the plain file-loader. I do think maybe we should include the school loader by default perhaps. Or maybe just have a slightly easier way to edit the default loaders...webpack is annoying in that it doesn't let you name rules :/

The solution suggested by @pieh is working fine:

  1. Get the default webpack config via getConfig()
  2. Remove the wanted rules (e.g. using a reduce)
  3. Update the configuration via replaceWebpackConfig(cleanedConfig)
  4. Add custom rules via setWebpackConfig(customConfig)

It may be tricky to remove the right rules, but it gives the user a total control on webpack, and damn, thats what I was waiting for since the v1. Thanks again for this improvement guys 鉂わ笍

I wanted to add file-loader because of a shared config we're using across projects. But your messages made me think about this, and after digging more into url-loader, it definitly seems great and I kept it instead file-loader.

In this case, my custom rules were about image optimization (that could be useful for the Gatsby configuration), and a SVG sprite (specific to my project).

It should also also be noted that webpack loaders run "back to front" so often it's enough to add a new (maybe duplicate) loader using the normal setWebpackConfig instead of editing existing loaders. For instance you can add a svg optimization loader to the end which will run first and the when the URL loader is hit it will load the optimized image

to clarify my comment above, its not intuitive but:

rules: [
   { test: /\.svg/, use: 'url-loader' },
   /* maybe other loaders here */
   { test: /\.svg/, use: 'svgo-loader' },
]

is functionally the same as the more common:

rules: [
   { test: /\.svg/, use: ['url-loader', 'svgo-loader'] },
]

Question has been answered. I'm closing this.

@monsieurnebo would you mind sharing your gatsby-node.js file? I'm having trouble doing the same exact thing (needing svg-sprite-loader, image optimization, etc.).

I ended up getting mine to work using this method. I'm going to share my gatsby-node.js file here for anyone that stumbles upon this.

var path = require('path');

exports.onCreateWebpackConfig = ({
  actions,
  getConfig,
  options,
}) => {
  const prevConfig = getConfig();
  actions.replaceWebpackConfig({
    ...prevConfig,
    module: {
      ...prevConfig.module,
      rules: [
        ...prevConfig.module.rules.map(item => {
          const { test } = item;
          if(
            test &&
            test.toString() === '/\\.(ico|svg|jpg|jpeg|png|gif|webp)(\\?.*)?$/'
          ) {
            return {
              ...item,
              exclude: [
                path.resolve(__dirname, 'src/assets/icons')
              ],
            }
          }
          return { ...item };
        }),
        {
          test: /\.svg$/,
          use: [
            {
              loader: 'svg-sprite-loader',
              options,
            },
          ],
          include: [
            path.resolve(__dirname, 'src/assets/icons')
          ],
        }
      ],
    },
    resolve: {
      ...prevConfig.resolve,
      modules: [path.resolve(__dirname, 'src'), 'node_modules'],
    }
  })
};

Hi @jarodtaylor ,

Glad to see that you found a solution. If it can help, here is my onCreateWebpackConfig.js file:

module.exports = ({ stage, rules, loaders, actions, getConfig }) => {

  const defaultConfig = getConfig();
  const defaultModules = defaultConfig.module.rules;

  const cleanedModules = defaultModules.reduce((accu, module) => {
    // 1. If the rule is using `url-loader`, we remove it
    if (module.use && module.use[0].loader && !module.use[0].loader.includes("url-loader")) {
      accu.push(module);
    }

    // 2. Otherwise, rules stay unchanged
    return accu;
  }, []);

  // NOTE: cleaned config without url-loader
  defaultConfig.module.rules = cleanedModules;
  actions.replaceWebpackConfig(defaultConfig);

  const customConfig = {
    module : {
      rules : [
        // Your custom rules instead of default url-loader ones
        {
          test : /SvgIcon\/images\/([a-zA-Z0-9-_])+\.svg?$/i,
          use  : ["svg-sprite-loader"]
        },
        // etc
      ]
    }
  };

  actions.setWebpackConfig(customConfig);
};

But that's more a bad workaround than a long-term solution.

We're using this same solution. I'm curious if now nearly 2 years later there might be a better one. I'm porting an existing universal app over to gatsby and need a specific loader for svg files (svg-inline-loader). Changing that would require us having to change too much of our app. The reducer for editing the regex for gatsby's loader test: /\.(ico|svg|jpg|jpeg|png|gif|webp)(\?.*)?$/ to remove |svg is just absurd. Leaving that regex as is and simply adding my loader via setWebpackConfig results in the svg content being replaced with data:.

猬嗭笍 This.

Especially since this workaround could potentially explode at the slightest breaking update of GatsbyJS.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

dustinhorton picture dustinhorton  路  3Comments

jimfilippou picture jimfilippou  路  3Comments

magicly picture magicly  路  3Comments

ferMartz picture ferMartz  路  3Comments

theduke picture theduke  路  3Comments