Search code examples
svgoptimizationbundling-and-minificationimage-optimizationsvgo

How can I safely minify and optimise SVG files?


SVGO is currently the only actively-developed optimiser/minifier for SVG files, which - although being the most common filetype for vector images on the web - are rarely optimised for bandwidth and space like HTML, CSS, JS and raster-based images are. From its README:

SVG files, especially those exported from various editors, usually contain a lot of redundant and useless information. This can include editor metadata, comments, hidden elements, default or non-optimal values and other stuff that can be safely removed or converted without affecting the SVG rendering result.

The problem is that out of the box SVGO suffers from quite a few bugs that do affect the rendering result and make it non-safe, thanks to a small and historically stubborn maintainer list that rarely merges outside PRs, even when some of them are known to be destructive.

This situation is starting to change with a newly-appointed maintainer who's doing great work and is also in the process of developing some much-needed documentation for the project, but until these serious bugs are fixed, how can I run SVGO safely (i.e. without changing how my SVGs look or render) while still benefitting from its optimisation gains?


Solution

  • It's first important to note that the nature of the optimisations that SVGO applies to SVG files make it impractical for optimised SVGs to remain editable in editors like Adobe Illustrator. If you need to guarantee that your SVGs are editable after optimising them, I'd highly recommended creating backups of them that you can edit while serving your users the optimised versions.

    This can be very easily done by running the following command in Bash (Cygwin or WSL2 on Windows), which will make a copy of each SVG in its current location and append _editable to the end of it:

    find public/images/ -iname "*.svg" -exec cp "{}" "{}_editable" \;
    

    Once you have your backups, install SVGO using your package manager:

    npm -g install svgo
    

    Create a file called svgo.config.js in your directory root (where the package.json folder is stored) with the following configuration of my own that tries to make the defaults a bit more sane:

    module.exports = {
      multipass: true,
      plugins: [
        {
          // Include and override the built-in plugins
          name: "preset-default",
          params: {
            overrides: {
              removeViewBox: false,
              // prevent breaking scaling for SVGs that are scaled with HTML, CSS or JS
              // see: https://github.com/svg/svgo/issues/1128
              removeTitle: false,
              removeDesc: false,
              // not necessary for safety, but better for accessibility
            },
          },
        },
        {
          // Better for accessibility
          name: "removeUnknownsAndDefaults",
          params: {
            keepRoleAttr: true,
          },
        },
    
        "prefixIds",
        // prevents conflicts with inline SVGs on the same page by prefixing with the name of the file
        // see: https://github.com/svg/svgo/issues/674
      ],
    };
    

    Since I'm using SVGO to optimise my web app I need to run it on my application's current directory structure without moving the SVGs to a separate output folder. Although the documentation doesn't explicitly mention it, this is possible by simply omitting the output folder and using the -f option on its own.

    From the directory root, run the following to optimise all SVGs in public/images:

    svgo -rf public/images
    

    The output shows a list of all optimised SVGs along with the percentage of their filesize that was reduced. As can be seen, even with a configuration like the above that prioritises safety over optimisation, the optimisation gains from running SVGO are still significant:

    enter image description here

    Much credit goes to SethFalco for confirming a few things about how SVGO works for this answer, and for all the recent work he's been doing on the project - he definitely has his work cut out for him, so if anyone can contribute the time, code, or funds needed to help him bring the package up to standard and shake off its previous reputation, please do.