svg/svgo

bug: svg "sprites" are broken when using svgo

tomcru opened this issue · 6 comments

Describe the bug

We used to format our svg sprites with npx svgo --pretty -f ./public/sprites. This was working previously, but now returns empty svgs. I couldn't make out the version when this started happening. Issue seems to be coming from <defs>?

To Reproduce

  1. create file: /regions.svg
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" aria-hidden="true" overflow="hidden" style="position:absolute;width:0;height:0">
    <defs>
        <symbol id="Europe" viewBox="0 0 24 24">
            <g clip-path="url(#clip0_1273_38264)">
                <path fill="#0052B4" d="M12 22c5.523 0 10-4.477 10-10S17.523 2 12 2 2 6.477 2 12s4.477 10 10 10"/>
                <path fill="#FFDA44" d="m12 5.913.324.997h1.048l-.848.615.324.997L12 7.906l-.847.616.323-.997-.847-.615h1.048zM7.696 7.696l.934.475.74-.74-.163 1.034.933.476-1.034.164-.164 1.035-.476-.934-1.035.164.741-.74zM5.913 12l.997-.324V10.63l.615.847.997-.324-.616.848.616.848-.997-.324-.615.848v-1.048zm1.783 4.304.476-.933-.74-.741 1.034.164.476-.934.164 1.035 1.034.164-.933.476.164 1.034-.741-.74zM12 18.087l-.323-.997h-1.048l.848-.615-.324-.997.847.616.848-.616-.324.997.848.615h-1.048zm4.304-1.783-.933-.475-.741.74.164-1.035-.934-.475 1.035-.164.164-1.035.476.934 1.034-.164-.74.74zM18.087 12l-.996.324v1.048l-.616-.848-.997.324.616-.848-.616-.848.997.324.616-.847v1.047zm-1.783-4.304-.476.933.741.741-1.035-.164-.475.934-.164-1.035-1.035-.164.934-.476-.164-1.034.74.74z"/>
            </g>
            <defs>
                <clipPath id="clip0_1273_38264">
                    <path fill="#fff" d="M2 2h20v20H2z"/>
                </clipPath>
            </defs>
        </symbol>
        <symbol id="NorthAmerica" viewBox="0 0 24 24">
            <g clip-path="url(#clip0_1273_38302)">
                <path fill="#F0F0F0" d="M12 22c5.523 0 10-4.477 10-10S17.523 2 12 2 2 6.477 2 12s4.477 10 10 10"/>
                <path fill="#D80027" d="M11.566 12H22c0-.902-.12-1.777-.344-2.608h-10.09zm0-5.217h8.967a10.054 10.054 0 0 0-2.308-2.609h-6.66zM12 22a9.957 9.957 0 0 0 6.225-2.174H5.775A9.957 9.957 0 0 0 12 22m-8.532-4.782h17.064a9.94 9.94 0 0 0 1.124-2.61H2.345a9.94 9.94 0 0 0 1.123 2.61"/>
                <path fill="#0052B4" d="M6.632 3.562h.911l-.847.615.324.997-.848-.616-.848.616.28-.86c-.746.62-1.4 1.35-1.94 2.16h.293l-.54.393c-.084.14-.165.282-.242.427l.258.793-.481-.35a9.81 9.81 0 0 0-.327.777l.284.874h1.048l-.848.616.324.996-.848-.616-.508.37C2.027 11.161 2 11.577 2 12h10V2a9.953 9.953 0 0 0-5.368 1.562M7.02 11l-.848-.616-.848.616.324-.996-.847-.616h1.047l.324-.997.324.997h1.047l-.847.616zm-.324-3.91.324.997-.848-.616-.848.616.324-.996-.847-.616h1.047l.324-.997.324.997h1.047zm3.91 3.91-.847-.616L8.91 11l.324-.996-.848-.616h1.048l.324-.997.324.997h1.047l-.847.616zm-.323-3.91.324.997-.848-.616-.848.616.324-.996-.848-.616h1.048l.324-.997.324.997h1.047zm0-2.913.324.997-.848-.616-.848.616.324-.997-.848-.615h1.048l.324-.997.324.997h1.047z"/>
            </g>
            <defs>
                <clipPath id="clip0_1273_38302">
                    <path fill="#fff" d="M2 2h20v20H2z"/>
                </clipPath>
            </defs>
        </symbol>
        <symbol id="World" viewBox="0 0 24 24">
            <path fill="#006CA2" d="M21.944 12.001c0 5.492-4.453 9.944-9.946 9.944-5.49 0-9.943-4.452-9.943-9.944 0-5.493 4.452-9.944 9.943-9.944 5.493 0 9.946 4.45 9.946 9.944"/>
            <path fill="#BDCF46" d="M18.41 14.378a1.882 1.882 0 0 0-.658-.29c-.304-.046-.47.06-.612-.262-.119-.269-.207-.437-.419-.659-.408-.426-.777-.615-1.33-.828h-.943c-.396-.108-.794-.25-1.146.066-.038.033-.07.075-.104.113-.039.042-.215.057-.272.072-.08.02-.163.043-.247.045-.13.003-.306-.032-.395-.134a.509.509 0 0 1-.088-.25c-.01-.102.034-.191.036-.289.003-.087.007-.187-.017-.27-.05-.172-.245-.222-.396-.255-.09-.02-.179-.033-.27-.063-.23-.078-.111-.392-.014-.531.1-.143.242-.242.003-.372a.561.561 0 0 0-.597.039c-.162.123-.269.361-.465.423-.225.072-.47-.093-.683-.123.021-.284-.121-.806-.114-.935.021-.34.272-.71.6-.8.329-.09.69-.159 1.031-.123.527.056.505.338.78.705.09.12.262.262.418.179.331-.174.23-.621.24-.923.016-.47.318-.753.606-1.1.107-.127.215-.253.32-.382.094-.117.205-.227.364-.257.111-.02.248.001.36.001.184 0 .533.062.64-.126.099-.177-.047-.298-.194-.355-.06-.024-.162-.036-.18-.111-.061-.263.22-.272.396-.3.16-.026.365-.078.486.069.055.066.027.145.089.213.113.121.402.052.524-.018.14-.083.18-.314.18-.464a.386.386 0 0 0-.057-.224c-.12-.17-.473-.249-.65-.35a6.794 6.794 0 0 1-.734-.499 6.376 6.376 0 0 0-.882-.537c-.263-.137-.588-.363-.896-.31-.12.02-.186.107-.212.223-.016.087-.057.175-.057.265.002.11.053.21.084.313.04.127.07.258-.03.364-.096.1-.309.098-.42.015-.135-.102-.19-.265-.339-.343a.714.714 0 0 0-.473-.089c-.172.021-.38.042-.552-.001a.483.483 0 0 1-.328-.41c-.003-.122.024-.291.14-.359.136-.078.362-.058.515-.07a1.57 1.57 0 0 0 .09-.008l.014-.001c.004-.002.01-.002.015-.002.043-.006.084-.01.112-.018-.001-.003-.006-.006-.007-.009.024.045.16-.153.165-.175.024-.1-.05-.215-.014-.308.027-.069.125-.113.19-.134.1-.031.204-.013.306-.003.082.01.17.01.252.026.187.039.193.186.31.3.168.158.27.089.49.119.235.031.853.436 1.063.12.235-.353-.396-.613-.59-.677a1.793 1.793 0 0 1-.816-.566c-.06-.077-.18-.109-.177-.274.005-.134-.081-.205.03-.277.03-.02.15.001.185 0 .062-.006.114-.03.164 0 .076.046.231.24.27.316 0 0 .104.07.223.235.118.16.155.111.299.246.373.348.786.658 1.265.84.258.1.53.176.774.311.278.156.38.357.564.596.518.665 1.978.585 1.622-.464-.394-.302-.74-.542-1.437-.968a6.44 6.44 0 0 0-1.203-.565c-.469-.169-1.22-.412-1.691-.49a13.005 13.005 0 0 0-1.597-.18c-.41-.017-.646 0-.975.017a13.76 13.76 0 0 0-.5.045c-.011.201.28.26.322.444.017.08.023.15-.039.21-.067.066-.16.087-.175.192-.012.092.022.153.058.231.029.06.09.176.038.243-.14.176-.328-.14-.34-.26-.018-.196.044-.365-.154-.488-.134-.083-.497-.119-.552.076-.027.093.078.183.066.291-.026.22-.171.164-.338.192-.291.05-.351.268-.663.123-.03-.156.06-.408-.092-.513-.121-.082-.26.16-.397.105-.342-.138-.302-.144-.666-.036-.386.115-.4.204-.771.389-.17.084-.69.425-.965.617l-.329.248c-.121.097-.21.144-.347.287-.166.146-.308.277-.473.425-.09.101-.171.183-.236.251a10.169 10.169 0 0 0-.405.453c.322.042.383.23.641.398.22.14.488.283.527.552.048.324-.012.686-.003 1.014.018.653.693 1.15 1.095 1.601.179.201.194.452.37.641.097.107.393.636.609.44.172-.156-.28-.634-.243-.853.02-.133.322.134.34.153.126.15.192.367.258.548.143.392.27.566.598.719-.02.188.172.314.343.411.188.107.392.11.592.198.189.086.396.084.571.17.261.126.086.25.233.438.163.21.474.081.695.116.472.073.393.525.687.796.16.152.435.135.638.158.08.009.183.01.246.067.157.14-.027.332-.087.469-.083.183-.14.38-.176.577-.1.553-.08 1.17.323 1.597.438.467.974.678 1.14 1.344.143.557.01 1.102-.091 1.651-.063.33-.515.904-.066 1.147.39.211 1.053-.371 1.308-.593.602-.525 1.397-.845 1.793-1.582.188-.35.355-.719.683-.96.173-.128.372-.212.557-.318.392-.224.626-.7.801-1.094.207-.479.017-.749-.358-1.03m-7.067-8.445a.84.84 0 0 1 .296-.009c.173.042.3.177.432.285.096.077.177.158.263.243.055.056.108.105.096.197-.01.08-.054.118-.126.126-.13.013-.19-.072-.306-.092-.278-.046-.394.422-.671.294-.07-.033-.05-.091-.05-.166a.366.366 0 0 1 .021-.158.461.461 0 0 1 .123-.162c.033-.028.087-.05.113-.088.061-.096-.026-.198-.113-.234-.054-.023-.133-.024-.168-.072-.064-.092-.001-.14.09-.164m10.563 5.2c-.003-.45-.142-1.021-.223-1.403-.183-.23-.349-.113-.635.175-.556.56-.78 1.616-.318 2.296.17.252.388.462.673.528.28.065.39 0 .514 0 .01-.165.026-.632.026-.811-.001-.305-.034-.483-.037-.784Z"/>
            <path fill="#BDCF46" d="M13.782 10.556c-.138-.069-.19-.186-.282-.279a.413.413 0 0 0-.177-.108c-.148-.042-.334-.025-.485-.016-.224.013-.794.05-.822.364-.038.4.513.356.786.351.187-.003.369-.072.557-.025.274.067.213.312.426.405.076.033.313.078.387.084.273.024.929-.134.755-.524-.158-.358-.865-.112-1.145-.252"/>
        </symbol>
        <symbol id="LatinAmerica" viewBox="0 0 24 24"><path d="M21.944 12.001c0 5.492-4.453 9.944-9.946 9.944-5.49 0-9.943-4.452-9.943-9.944 0-5.493 4.452-9.944 9.943-9.944 5.493 0 9.946 4.45 9.946 9.944Z" fill="#006CA2"/><path d="M10.69 3.814c-.226-.11-.311-.299-.462-.449a.679.679 0 0 0-.29-.173c-.24-.068-.546-.041-.794-.027-.366.022-1.3.082-1.347.586-.062.645.84.572 1.288.565.307-.005.605-.116.912-.04.45.108.35.5.699.65.125.054.514.126.634.136.447.038 1.522-.215 1.237-.842-.258-.577-1.417-.181-1.876-.406Z" fill="#BDCF46"/><path d="M17.196 9.494c.293.044.819.275 1.077.466.615.451.927.886.588 1.655-.288.635-.672 1.4-1.313 1.76-.303.17-.63.306-.912.511-.539.389-.812.982-1.12 1.544-.648 1.185-1.951 1.699-2.937 2.544l-.01.009c-.426.363-1.5 1.281-2.134.944-.735-.391.005-1.313.108-1.844.167-.883.384-1.759.15-2.654-.273-1.071-1.15-1.412-1.868-2.162-.66-.688-.694-1.68-.529-2.567.059-.319.152-.635.288-.93.098-.22.4-.528.142-.752-.103-.092-.273-.094-.403-.109-.332-.036-.782-.01-1.045-.253-.482-.437-.351-1.163-1.126-1.282-.361-.055-.87.152-1.138-.185-.241-.302-.312-.481-.514-.72 1-1.019 1.094-1.124 2.247-1.914.391.21.425.49.263.72-.16.225-.354.729.022.854.15.049.295.07.443.102.248.053.568.132.649.41.04.133.032.294.027.434-.003.157-.074.3-.06.463.013.124.062.31.146.403.145.165.435.22.647.215.137-.002.275-.04.405-.072.094-.024.381-.048.445-.116.057-.06.108-.128.17-.18.578-.508 1.23-.28 1.878-.107h1.544c.907.342 1.512.647 2.181 1.332.347.357.492.627.686 1.06.233.518.504.347 1.003.421Z" fill="#BDCF46"/></symbol>
    </defs>
</svg>
  1. run: npx svgo --pretty regions.svg

results in:
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" aria-hidden="true" overflow="hidden" style="position:absolute;width:0;height:0"/>

Running without --pretty has the same results

Desktop (please complete the following information):

  • SVGO Version 3.1.0
  • NodeJs Version 20.5.0
  • OS: macOS 14.0

Additional context
There's multiple svgs just like this in /public/sprites

This issue is caused by either cleanupIds or removeHiddenElems

What is the original SVG's purpose? It seems to be to define things, as it renders nothing. How is it being used?

It is used as a Sprite sheet (instead of requesting a lot of icons on a page, we can just request this file once and pick the item out of it with <use>).

It is for all icons here:
https://main.gamegator.net/games/starfield
These, for example:
Screenshot 2023-12-21 at 16 12 48

Example on how it is used in a React component:

import { VariantProps, cva, cx } from 'class-variance-authority';
import { ComponentPropsWithoutRef } from 'react';
import { Sprite } from '../../../common/types/Sprite';

const styles = cva('', {
  variants: {
    color: {
      primary: 'text-icon-primary',
      secondary: 'text-icon-secondary',
      tertiary: 'text-icon-tertiary',
      success: 'text-icon-success',
      'on-color': 'text-icon-on-color',
      'on-color-inverse': 'text-icon-on-color-inverse',
      error: 'text-icon-error',
      none: '',
    },
  },
  defaultVariants: {
    color: 'none',
  },
});

type Props = {
  path: Sprite;
  className?: string;
  width?: number;
  height?: number;
  style?: Omit<ComponentPropsWithoutRef<'svg'>['style'], 'width' | 'height'>;
} & VariantProps<typeof styles>;

export function Icon({
  path,
  className,
  width,
  height,
  style,
  ...props
}: Props): JSX.Element {
  /** helper to find broken icons */
  if (!path) {
    return <div className="block h-24 w-24 bg-button-danger"></div>;
  }
  const [type, name] = path.split('/');

  return (
    <svg
      className={cx(styles(props), className)}
      style={{
        width: `${width}px`,
        height: `${height}px`,
        ...style,
      }}
    >
      <use href={`/sprites/${type}.svg#${name}`} />
    </svg>
  );
}

You can basically render the elements inside defs with a # and the id of it, like /sprites/regions.svg#LatinAmerica

As SVGO caters to standalone SVGs, this isn't a bug, but SVGO working as intended - removing unused definitions. However you can customize SVGO to disable that behavior, by turning off removeHiddenElems and cleanupIds, as these both have the sole purpose to optimize defs within the SVG.

Thank you, this was indeed the case - had to disable both removeHiddenElems & cleanupIds.

module.exports = {
  plugins: [
    {
      name: 'preset-default',
      params: {
        overrides: {
          removeHiddenElems: false,
          cleanupIds: false,
        },
      },
    },
  ],
};