svgo
svgo copied to clipboard
Add `dereferenceUses` plugin
This PR adds the dereferenceUses plugin, which de-references <use/> elements, replacing it with the targeted node.
It also takes the special attribute inheritance rules into account.
You can already try this feature branch by installing it using this npm command:
npm install github:strarsis/svgo#dereferenceUses-plugin
Note that this plugin currently doesn't run by default and has to be explicitly enabled:
svgo --enable=dereferenceUses [...]
The original/source elements are kept by this plugin as those may still be needed, but can (and will by default) be removed using the existing removeUselessDefs plugin (that runs afterwards by default).
I'm trying to run this using "svgo": "git://github.com/strarsis/svgo#dereferenceUses-plugin" as dependency, and then running the following command:
>npx svgo 9215d05705c8e8a7ebd718ae6f690371.svg --enable=dereferenceUses
9215d05705c8e8a7ebd718ae6f690371.svg:
Done in 42 ms!
15.119 KiB - 0% = 15.119 KiB
however, the resultant SVG still has all its <use...> in place:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="423" height="75" viewBox="0 0 317 56"><defs>...snip...</defs><use xlink:href="#a" x="-.475" y="30.513"/><use xlink:href="#b" x="8.946" y="30.513"/><use xlink:href="#c" x="15.27" y="30.513"/><use xlink:href="#d" x="19.586" y="30.513"/><use xlink:href="#e" x="30.082" y="30.513"/><use xlink:href="#f" x="36.921" y="30.513"/><use xlink:href="#f" x="40.484" y="30.513"/><use xlink:href="#g" x="44.046" y="30.513"/><use xlink:href="#h" x="53.407" y="30.513"/><use xlink:href="#d" x="59.349" y="30.513"/><use xlink:href="#i" x="69.845" y="30.513"/><use xlink:href="#c" x="74.496" y="30.513"/><use xlink:href="#j" x="78.812" y="30.513"/><use xlink:href="#k" x="86.774" y="30.513"/><use xlink:href="#l" x="99.399" y="30.513"/><use xlink:href="#m" x="103.471" y="30.413"/><use xlink:href="#c" x="119.407" y="30.413"/><use xlink:href="#c" x="133.682" y="30.413"/><use xlink:href="#n" x="138.005" y="26.073"/><use xlink:href="#c" x="153.228" y="30.413"/><use xlink:href="#o" x="157.544" y="26.073"/><use xlink:href="#p" x="162.804" y="30.513"/><use xlink:href="#q" x="169.523" y="30.513"/><use xlink:href="#r" x="175.506" y="19.056"/><use xlink:href="#s" x="175.506" y="29.224"/><use xlink:href="#s" x="175.506" y="37.779"/><use xlink:href="#t" x="175.506" y="53.925"/><use xlink:href="#m" x="188.13" y="8.745"/><use xlink:href="#u" x="213.367" y="8.745"/><use xlink:href="#u" x="238.605" y="8.745"/><use xlink:href="#u" x="263.854" y="8.745"/><use xlink:href="#u" x="188.13" y="23.19"/><use xlink:href="#u" x="213.367" y="23.19"/><use xlink:href="#m" x="238.605" y="23.19"/><use xlink:href="#u" x="263.854" y="23.19"/><use xlink:href="#v" x="183.48" y="37.636"/><use xlink:href="#w" x="192.781" y="37.636"/><use xlink:href="#w" x="213.368" y="37.636"/><use xlink:href="#v" x="233.955" y="37.636"/><use xlink:href="#x" x="243.256" y="37.636"/><use xlink:href="#v" x="259.192" y="37.636"/><use xlink:href="#m" x="268.493" y="37.636"/><use xlink:href="#x" x="188.13" y="52.082"/><use xlink:href="#v" x="208.717" y="52.082"/><use xlink:href="#x" x="218.018" y="52.082"/><use xlink:href="#m" x="238.605" y="52.082"/><use xlink:href="#m" x="263.854" y="52.082"/><use xlink:href="#y" x="274.483" y="19.056"/><use xlink:href="#z" x="274.483" y="29.224"/><use xlink:href="#z" x="274.483" y="37.779"/><use xlink:href="#A" x="274.483" y="53.925"/><use xlink:href="#q" x="285.114" y="30.513"/><use xlink:href="#r" x="291.094" y="19.056"/><use xlink:href="#s" x="291.094" y="29.224"/><use xlink:href="#s" x="291.094" y="37.779"/><use xlink:href="#t" x="291.094" y="53.925"/><use xlink:href="#B" x="299.67" y="8.745"/><use xlink:href="#C" x="306.639" y="11.698"/><use xlink:href="#B" x="299.67" y="23.19"/><use xlink:href="#n" x="306.639" y="26.144"/><use xlink:href="#B" x="299.068" y="37.636"/><use xlink:href="#D" x="308.597" y="33.296"/><use xlink:href="#C" x="306.038" y="40.766"/><use xlink:href="#B" x="299.068" y="52.082"/><use xlink:href="#D" x="308.597" y="47.742"/><use xlink:href="#n" x="306.038" y="55.211"/><use xlink:href="#y" x="312.501" y="19.056"/><use xlink:href="#z" x="312.501" y="29.224"/><use xlink:href="#z" x="312.501" y="37.78"/><use xlink:href="#A" x="312.501" y="53.925"/></svg>
Github won't let me attach the SVG file itself, so here's the full content as code block:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="423" height="75" viewBox="0 0 317 56"><defs><symbol overflow="visible" id="a"><path d="M9.281-8.438c0-.03-.219-.25-.328-.25a.701.701 0 00-.328.172l-.672.75c0 .016-.672-.921-2-.921-2.672 0-5.562 2.765-5.562 5.546C.39-1.17 2.016.266 3.844.266c1.031 0 2.078-.516 2.703-1.063C7.657-1.78 7.922-2.969 7.922-3c0-.125-.203-.031-.203-.031l-.125-.219c-.078 0-.344.156-.36.25-.109.344-.328 1.094-1.156 1.797-.812.672-1.422.828-2.047.828-1.078 0-2.156-.484-2.156-2.344 0-.687.188-2.531 1.39-3.922C4-7.5 4.986-8.062 6.048-8.062c1.219 0 1.719.796 1.719 2.187 0 .469-.032.484-.032.61 0 .109.329.25.375.25.157 0 .36-.157.407-.376zm0 0"/></symbol><symbol overflow="visible" id="b"><path d="M6.14-1.844c0-.11-.296-.25-.327-.25-.125 0-.344.188-.375.344-.204.781-.22 1.36-.704 1.36-.328 0-.171-.188-.171-.422 0-.266.03-.36.156-.891l.265-1.063.438-1.687c.078-.328.078-.36.078-.406 0-.204-.344-.454-.547-.454-.281 0-.656.407-.703.657h.406c-.218-.438-.765-.89-1.297-.89-1.406 0-3.078 1.89-3.078 3.64 0 1.125.86 2.031 1.781 2.031.25 0 .97-.078 1.422-.61.032.094.657.61 1.22.61.421 0 .827-.297 1.015-.688l.062-.093c.203-.438.297-1.094.297-1.094zm-2.03-2.25c0 .063-.016.14-.032.203l-.594 2.344c-.062.203 0 .14-.187.344-.531.656-.875.812-1.203.812-.594 0-.578-.53-.578-1 0-.593.328-1.968.593-2.515.375-.703.782-1.11 1.266-1.11.766 0 .734.844.734.922zm0 0"/></symbol><symbol overflow="visible" id="c"><path d="M4.14-5.156c0-.125-.312-.266-.53-.266h-.83c.39-1.562.453-1.797.453-1.875 0-.203-.328-.453-.53-.453-.032 0-.579.14-.688.563l-.422 1.765H.64c-.25 0-.563.14-.563.36 0 .156.297.28.531.28h.813C.594-1.515.547-1.311.547-1.093c0 .64.656 1.219 1.312 1.219 1.22 0 2.079-1.875 2.079-1.969 0-.11-.282-.25-.329-.25-.109 0-.328.172-.375.297C2.72-.547 2.281-.39 1.875-.39c-.25 0-.172-.03-.172-.421 0-.282.016-.375.063-.579l.859-3.39h.953c.25 0 .563-.125.563-.375zm0 0"/></symbol><symbol overflow="visible" id="d"><path d="M10.328-1.844c0-.11-.297-.25-.328-.25-.125 0-.328.172-.39.344-.172.64-.36 1.36-1.016 1.36-.203 0-.094.015-.094-.266 0-.297.11-.594.219-.844.219-.625.719-1.953.719-2.64 0-.766-.657-1.407-1.563-1.407-.89 0-1.64.563-2.094 1.203l.344.094c-.016-.156-.11-.656-.453-.953-.297-.25-.813-.344-1.11-.344-1.078 0-1.796.797-2 1.078l.329.094c-.063-.688-.75-1.172-1.282-1.172-.562 0-.921.5-1.03.719C.358-4.406.14-3.61.14-3.578c0 .125.484.219.484.219l-.14.03c.124 0 .328-.14.406-.405.203-.844.25-1.282.671-1.282.188 0 .172-.046.172.407 0 .265-.03.39-.187 1.015L.844-.844c-.031.188-.11.469-.11.516 0 .219.375.453.563.453.14 0 .547-.219.656-.547-.078.156.125-.5.203-.797l.266-1.078c.062-.265.14-.531.203-.797l.14-.594c.188-.374.626-1.328 1.766-1.328.532 0 .438.313.438.704 0 .296-.078.625-.172.984l-.344 1.39c-.11.438-.125.516-.234.907-.047.25-.157.656-.157.703 0 .219.375.453.547.453.375 0 .641-.422.735-.813l.718-2.875c.032-.156.47-1.453 1.782-1.453.515 0 .437.266.437.704 0 .671-.5 2.046-.734 2.671-.11.297-.156.422-.156.657 0 .562.625 1.109 1.187 1.109 1.11 0 1.75-1.875 1.75-1.969zm0 0"/></symbol><symbol overflow="visible" id="e"><path d="M6.688-1.844c0-.11-.297-.25-.344-.25-.11 0-.328.188-.375.344-.157.672-.188 1.36-.688 1.36-.25 0-.172-.032-.172-.422 0-.266.141-.829.235-1.25l.328-1.282c.047-.187.156-.64.203-.812.063-.282.188-.735.188-.797 0-.219-.36-.469-.547-.469-.047 0-.563.156-.657.563l-.906 3.593c-.015.047-.281.875-1.156.875-.625 0-.547-.406-.547-.859 0-.656.328-1.61.64-2.438.141-.359.204-.515.204-.75 0-.53-.578-1.109-1.172-1.109C.782-5.547.14-3.687.14-3.578c0 .125.484.219.484.219l-.14.03c.124 0 .328-.155.39-.343.297-1.031.563-1.344 1.016-1.344.109 0 .093-.125.093.266 0 .281-.125.625-.203.813-.437 1.171-.687 1.921-.687 2.5 0 1.14 1.015 1.562 1.672 1.562.78 0 1.343-.563 1.328-.531.015.094.64.531 1.156.531.422 0 .828-.297 1.016-.688l.062-.093c.203-.438.297-1.094.297-1.094zm0 0"/></symbol><symbol overflow="visible" id="f"><path d="M3.219-8.203s-.14-.36-.297-.36c-.266 0-1.14.094-1.453.126-.094.015-.422.156-.422.374 0 .141.312.266.5.266.562 0 .375-.016.375.078l-.031.235L.375-1.5a1.376 1.376 0 00-.047.406c0 .672.719 1.219 1.281 1.219.407 0 .891-.36 1.094-.797C2.922-1.125 3-1.75 3-1.75l.063-.094c0-.11-.297-.25-.344-.25-.11 0-.328.188-.36.344-.203.781-.234 1.36-.703 1.36-.36 0-.172-.25-.172-.422 0-.282.016-.344.063-.579L3.28-8.297zm0 0"/></symbol><symbol overflow="visible" id="g"><path d="M7.516-6.734c0 .406-.125 1.125-.594 1.593-.313.313-.797.657-1.875.657h-1.11l.735-2.985c.078-.281-.078-.281.14-.312.11-.016.5-.016.735-.016.844 0 1.969-.125 1.969 1.063zM9.219-1.25c0-.14-.203-.047-.203-.047l-.141-.219c-.094 0-.328.22-.36.297-.296.89-.609.953-.874.953-.391 0-.297-.125-.297-.593 0-.375.078-.985.125-1.36a3.59 3.59 0 00.047-.562c0-.922-.985-1.422-1.313-1.547v.266C7.406-4.329 9.031-5.298 9.031-6.5c0-1.031-1.281-1.922-2.844-1.922H2.781c-.234 0-.547.125-.547.36 0 .14.313.265.532.265l.14-.031s.125.031.328.062c.204.016.11-.093.11.063 0 .047-.016.078-.047.219L1.703-1.063c-.125.47.047.422-.89.422C.593-.64.28-.5.28-.266c0 .141.5.235.5.235L.656 0l1.5-.031L3.687 0c.094 0 .422-.125.422-.375 0-.125-.296-.266-.53-.266C3.14-.64 3-.5 3-.719c0-.062.031-.125.031-.203l.766-3.031h1.265c1.079 0 1.094.531 1.094.953 0 .172-.093.547-.172.828-.078.328-.187.766-.187 1.016C5.797.125 7.437.266 7.594.266c1.015 0 1.625-1.344 1.625-1.516zm0 0"/></symbol><symbol overflow="visible" id="h"><path d="M5.797-3.39c0-1.25-1.031-2.157-2.11-2.157-1.593 0-3.406 1.828-3.406 3.531C.281-.844 1.297.125 2.406.125c1.594 0 3.39-1.781 3.39-3.516zM4.53-3.86c0 .47-.187 1.626-.64 2.407-.407.687-.922 1.062-1.47 1.062-.515 0-.858-.25-.858-1.171 0-.594.25-1.782.64-2.391.594-.922 1.14-1.063 1.485-1.063.687 0 .843.438.843 1.157zm0 0"/></symbol><symbol overflow="visible" id="i"><path d="M4.156 2.719a.504.504 0 00-.11-.203c-1.234-.922-2-3.22-2-5.141v-1c0-1.906.767-4.203 2-5.14a.457.457 0 00.11-.188c0-.063-.25-.25-.312-.25a1.01 1.01 0 00-.203.062C2.312-8.156 1-5.67 1-3.625v1C1-.578 2.313 1.906 3.64 2.906a.997.997 0 00.204.063c.062 0 .312-.203.312-.25zm0 0"/></symbol><symbol overflow="visible" id="j"><path d="M3.64-2.625v-1c0-2.047-1.328-4.531-2.64-5.516a.774.774 0 00-.203-.062c-.063 0-.313.187-.313.25 0 .031.079.172.094.187 1.25.938 2.016 3.235 2.016 5.141v1c0 1.922-.766 4.219-2.016 5.14-.015.032-.094.157-.094.204 0 .047.25.25.313.25A.774.774 0 001 2.906c1.313-1 2.64-3.484 2.64-5.531zm0 0"/></symbol><symbol overflow="visible" id="k"><path d="M8.828-4.281c0-.125-.312-.375-.437-.375H.906c-.125 0-.437.25-.437.375 0 .14.312.375.437.375h7.485c.125 0 .437-.235.437-.375zm0 2.328c0-.14-.312-.375-.437-.375H.906c-.125 0-.437.234-.437.375 0 .125.312.36.437.36h7.485c.125 0 .437-.235.437-.36zm0 0"/></symbol><symbol overflow="visible" id="l"><path d="M3.938 3.203c0-.14-.297-.375-.454-.375h-.859v-11.89h.86c.156 0 .453-.235.453-.376 0-.156-.297-.39-.454-.39H1.72V3.578h1.765c.157 0 .454-.234.454-.375zm0 0"/></symbol><symbol overflow="visible" id="m"><path d="M5.203-.125v-.516h-.578c-1.078 0-.922 0-.922-.437v-6.703c0-.282-.187-.438-.578-.438-.766.797-1.672.766-2.266.766v.625c.438 0 1.282-.031 1.563-.172v5.922c0 .437.172.437-.906.437H.937v.672C1.547-.03 2.595-.03 3.079-.03c.469 0 1.516 0 2.125.062zm0 0"/></symbol><symbol overflow="visible" id="p"><path d="M2.14-9.828H.579c-.14 0-.453.234-.453.39 0 .141.313.376.453.376h.86v11.89h-.86c-.14 0-.453.235-.453.375s.313.375.453.375h1.75V-9.828zm0 0"/></symbol><symbol overflow="visible" id="q"><path d="M2.484-3.125c0-.344-.468-.766-.828-.766-.343 0-.828.422-.828.766 0 .36.485.766.828.766.36 0 .828-.407.828-.766zm0 0"/></symbol><symbol overflow="visible" id="r"><path d="M7.922-17.703c0-.203-.344-.485-.547-.485H3.641V0H4.75v-17.219h2.625c.203 0 .547-.281.547-.484zm0 0"/></symbol><symbol overflow="visible" id="s"><path d="M4.75-.125v-12.094H3.64V0h1.11zm0 0"/></symbol><symbol overflow="visible" id="t"><path d="M7.922-.484c0-.204-.344-.5-.547-.5H4.75v-17.203H3.64V0h3.735c.203 0 .547-.281.547-.484zm0 0"/></symbol><symbol overflow="visible" id="u"><path d="M5.688-3.953c0-.953-.063-1.922-.47-2.797-.562-1.156-1.734-1.469-2.234-1.469-.718 0-1.796.438-2.28 1.547-.376.828-.438 1.766-.438 2.719 0 .89.109 2.062.593 2.969.516.968 1.532 1.25 2.11 1.25.656 0 1.75-.391 2.281-1.516.375-.828.438-1.766.438-2.703zm-1.391-.14c0 .89 0 1.702-.125 2.468C4-.485 3.516-.265 2.969-.265 2.516-.266 2-.438 1.78-1.579c-.125-.719-.125-1.813-.125-2.516 0-.765 0-1.562.094-2.203.219-1.422.922-1.406 1.219-1.406.406 0 .984.094 1.219 1.266.109.671.109 1.578.109 2.343zm0 0"/></symbol><symbol overflow="visible" id="v"><path d="M8.828-3.125c0-.125-.312-.36-.437-.36H.906c-.125 0-.437.235-.437.36 0 .14.312.375.437.375h7.485c.125 0 .437-.234.437-.375zm0 0"/></symbol><symbol overflow="visible" id="w"><path d="M5.656-2.172c0-.984-.953-2.047-2.187-2.297v.266c.984-.328 1.86-1.297 1.86-2.234 0-.985-1.235-1.782-2.391-1.782-1.204 0-2.313.844-2.313 1.75 0 .39.469.75.813.75.375 0 .796-.39.796-.734 0-.594-.75-.734-.656-.734.234-.36.89-.47 1.313-.47.484 0 .953.126.953 1.204 0 .14.031.734-.281 1.266-.36.578-.626.578-.922.578a4.76 4.76 0 01-.47.046c-.093.016-.374.157-.374.266 0 .14.281.266.484.266h.531c.985 0 1.22.687 1.22 1.86 0 1.624-.626 1.843-1.157 1.843-.516 0-1.266-.172-1.531-.61.125.016.687-.375.687-.828 0-.437-.515-.796-.86-.796-.28 0-.874.296-.874.812C.297-.656 1.609.266 2.922.266c1.453 0 2.734-1.22 2.734-2.438zm0 0"/></symbol><symbol overflow="visible" id="x"><path d="M5.36-2.344h-.47c-.077.485-.109.922-.234 1.094-.078.11-.718.063-.984.063H1.89l1.03-1c1.86-1.657 2.642-2.391 2.642-3.579 0-1.375-1.266-2.453-2.735-2.453C1.484-8.219.391-7 .391-5.922c0 .656.796.797.843.797.204 0 .813-.281.813-.766 0-.312-.406-.75-.828-.75-.094 0-.125 0 .125-.093.187-.547.64-.86 1.328-.86 1.094 0 1.406.844 1.406 1.828 0 .954-.547 1.797-1.203 2.532L.578-.672C.453-.532.391-.422.391 0h4.812l.375-2.344zm0 0"/></symbol><symbol overflow="visible" id="y"><path d="M4.328-.125v-18.063H.594c-.203 0-.563.282-.563.485s.36.484.563.484h2.625V0h1.11zm0 0"/></symbol><symbol overflow="visible" id="z"><path d="M4.14-12.219h-.92V0h1.11v-12.219zm0 0"/></symbol><symbol overflow="visible" id="A"><path d="M4.328-.125v-18.063h-1.11V-.983H.595c-.203 0-.563.296-.563.5 0 .203.36.484.563.484h3.734zm0 0"/></symbol><symbol overflow="visible" id="B"><path d="M9.39-8.156c0-.094-.265-.266-.359-.266-.312 0-.656.031-.969.031-.406 0-.812-.03-1.187-.03-.078 0-.438.124-.438.358 0 .126.313.266.407.266.312.031.343.016.343.266 0 .187.157.547.157.547l-.282-.188-3.671 5.828.343.094-.812-6.313c0-.203.078-.234.625-.234.172 0 .5-.125.5-.36 0-.109-.297-.265-.36-.265-.484 0-1 .031-1.484.031-.219 0-.453-.015-.656-.015-.219 0-.453-.016-.656-.016-.079 0-.422.125-.422.36 0 .14.312.265.5.265.672 0 .484-.016.515.281L2.422-.14c.047.235.297.407.453.407.188 0 .36-.094.453-.25l4.313-6.86c.578-.922.953-.922 1.39-.953.156-.016.297-.266.297-.266zm0 0"/></symbol><symbol overflow="visible" id="n"><path d="M4.234-1.844H3.75c-.047.344-.063.735-.172.813-.062.047-.562 0-.687 0H1.812c.563-.5.86-.735 1.36-1.125.625-.5 1.265-1.14 1.265-1.938 0-1-1.093-1.781-2.171-1.781-1.032 0-1.954.89-1.954 1.656 0 .422.579.625.657.625.203 0 .656-.297.656-.61 0-.14-.266-.593-.422-.593.188-.437.547-.469.938-.469.843 0 1.062.5 1.062 1.172 0 .735-.453 1.203-.719 1.5l-2.03 2C.374-.516.311-.39.311 0h3.844l.313-1.844zm0 0"/></symbol><symbol overflow="visible" id="o"><path d="M4.516-1.61c0-.656-.75-1.468-1.672-1.656v.313c.89-.313 1.406-1.094 1.406-1.61 0-.656-.969-1.312-1.89-1.312-.938 0-1.86.61-1.86 1.281 0 .282.39.594.64.594.266 0 .641-.344.641-.578 0-.25-.375-.578-.297-.578.094-.11.532-.157.844-.157.375 0 .688.016.688.75 0 .344-.047.625-.266.891-.281.313-.36.281-.781.313-.203.015-.235.015-.266.015l.14.281s-.437-.109-.437-.015c0 .125.282.281.422.281h.453c.656 0 .922.297.922 1.188 0 1.046-.39 1.187-.89 1.187-.329 0-.922-.031-1.094-.266.078-.015.375-.453.375-.625 0-.265-.407-.625-.672-.625-.235 0-.672.297-.672.641C.25-.5 1.328.172 2.344.172 3.5.172 4.516-.766 4.516-1.61zm0 0"/></symbol><symbol overflow="visible" id="C"><path d="M4.172-.156v-.469H3.64c-.829 0-.625.063-.625-.219v-4.64c0-.235-.235-.391-.563-.391-.578.578-1.203.531-1.75.531v.625c.406 0 1.11-.047 1.219-.11v3.985c0 .281.203.219-.625.219h-.53v.64L2.469-.03l1.703.047zm0 0"/></symbol><symbol overflow="visible" id="D"><path d="M3.063-4.313c0-.25-.422-.609-.672-.609-.172 0-.563.281-.61.406l-1.5 3.72H1L2.922-3.97c.047-.062.14-.265.14-.344zm0 0"/></symbol></defs><use xlink:href="#a" x="-.475" y="30.513"/><use xlink:href="#b" x="8.946" y="30.513"/><use xlink:href="#c" x="15.27" y="30.513"/><use xlink:href="#d" x="19.586" y="30.513"/><use xlink:href="#e" x="30.082" y="30.513"/><use xlink:href="#f" x="36.921" y="30.513"/><use xlink:href="#f" x="40.484" y="30.513"/><use xlink:href="#g" x="44.046" y="30.513"/><use xlink:href="#h" x="53.407" y="30.513"/><use xlink:href="#d" x="59.349" y="30.513"/><use xlink:href="#i" x="69.845" y="30.513"/><use xlink:href="#c" x="74.496" y="30.513"/><use xlink:href="#j" x="78.812" y="30.513"/><use xlink:href="#k" x="86.774" y="30.513"/><use xlink:href="#l" x="99.399" y="30.513"/><use xlink:href="#m" x="103.471" y="30.413"/><use xlink:href="#c" x="119.407" y="30.413"/><use xlink:href="#c" x="133.682" y="30.413"/><use xlink:href="#n" x="138.005" y="26.073"/><use xlink:href="#c" x="153.228" y="30.413"/><use xlink:href="#o" x="157.544" y="26.073"/><use xlink:href="#p" x="162.804" y="30.513"/><use xlink:href="#q" x="169.523" y="30.513"/><use xlink:href="#r" x="175.506" y="19.056"/><use xlink:href="#s" x="175.506" y="29.224"/><use xlink:href="#s" x="175.506" y="37.779"/><use xlink:href="#t" x="175.506" y="53.925"/><use xlink:href="#m" x="188.13" y="8.745"/><use xlink:href="#u" x="213.367" y="8.745"/><use xlink:href="#u" x="238.605" y="8.745"/><use xlink:href="#u" x="263.854" y="8.745"/><use xlink:href="#u" x="188.13" y="23.19"/><use xlink:href="#u" x="213.367" y="23.19"/><use xlink:href="#m" x="238.605" y="23.19"/><use xlink:href="#u" x="263.854" y="23.19"/><use xlink:href="#v" x="183.48" y="37.636"/><use xlink:href="#w" x="192.781" y="37.636"/><use xlink:href="#w" x="213.368" y="37.636"/><use xlink:href="#v" x="233.955" y="37.636"/><use xlink:href="#x" x="243.256" y="37.636"/><use xlink:href="#v" x="259.192" y="37.636"/><use xlink:href="#m" x="268.493" y="37.636"/><use xlink:href="#x" x="188.13" y="52.082"/><use xlink:href="#v" x="208.717" y="52.082"/><use xlink:href="#x" x="218.018" y="52.082"/><use xlink:href="#m" x="238.605" y="52.082"/><use xlink:href="#m" x="263.854" y="52.082"/><use xlink:href="#y" x="274.483" y="19.056"/><use xlink:href="#z" x="274.483" y="29.224"/><use xlink:href="#z" x="274.483" y="37.779"/><use xlink:href="#A" x="274.483" y="53.925"/><use xlink:href="#q" x="285.114" y="30.513"/><use xlink:href="#r" x="291.094" y="19.056"/><use xlink:href="#s" x="291.094" y="29.224"/><use xlink:href="#s" x="291.094" y="37.779"/><use xlink:href="#t" x="291.094" y="53.925"/><use xlink:href="#B" x="299.67" y="8.745"/><use xlink:href="#C" x="306.639" y="11.698"/><use xlink:href="#B" x="299.67" y="23.19"/><use xlink:href="#n" x="306.639" y="26.144"/><use xlink:href="#B" x="299.068" y="37.636"/><use xlink:href="#D" x="308.597" y="33.296"/><use xlink:href="#C" x="306.038" y="40.766"/><use xlink:href="#B" x="299.068" y="52.082"/><use xlink:href="#D" x="308.597" y="47.742"/><use xlink:href="#n" x="306.038" y="55.211"/><use xlink:href="#y" x="312.501" y="19.056"/><use xlink:href="#z" x="312.501" y="29.224"/><use xlink:href="#z" x="312.501" y="37.78"/><use xlink:href="#A" x="312.501" y="53.925"/></svg>
@Pomax: Oh right, sorry, that I hadn't explicitly mentioned this, but the plugin is not enabled by default (as this may not always be wished for default optimization) and has to be explicitly enabled when using svgo (CLI or config):
svgo --enable=dereferenceUses [...]
Right, but that's what I used? I issued npx svgo 9215d05705c8e8a7ebd718ae6f690371.svg --enable=dereferenceUses
@Pomax: Right, so <use> can target all kinds of elements, but also <symbol/> elements which are template elements,
hence they are not displayed and require special treatment when being dereferenced.
Browsers would replace <symbol/> elements by <svg/> elements when being placed via <use/> (at least Chrome),
code has been added to the plugin to do this, too. The resulting SVG show now display correctly (identical to input SVG).
I took your sample SVG (some mathematical formula) and made two plugin tests out of it.
Reinstall from this plugin branch to try the fix yourself!
Maybe I'm doing something wrong here, but I'm not seeing it replace the the <use> elements yet... I reinstalled installed your branch by first uninstalling svgo and confirming it was gone, then setting "svgo": "git://github.com/strarsis/svgo#dereferenceUses-plugin" in package.json and running npm install. I verified that it indeed puts your branch in node_modules by checking the file tree: the svgo/plugins/dereferenceUses.js exists.
I then tried both npx svgo 9215d05705c8e8a7ebd718ae6f690371.svg --enable=dereferenceUses and npx svgo --enable=dereferenceUses 9215d05705c8e8a7ebd718ae6f690371.svg but in both cases the resultant file still ends with that huge block of <use xlink:href="#..." x="..." y="..."/> instructions.
@Pomax: Alright, the reason was that the dereferenceUses plugin had not been listed in the .svgo.yml, this is always necessary.
I pushed a fix to the feature branch. Please reinstall and then invoke svgo:
./bin/svgo --enable=derferenceUses 9215d05705c8e8a7ebd718ae6f690371.svg -o 9215d05705c8e8a7ebd718ae6f690371.min.svg
The output SVG looks identical, but it doesn't contain any <use> elements anymore.
aha! let me give it another go =)
Side note: All <use/>d <symbol/> elements are placed inside a <svg> element (as browsers would do).
When those elements should stand alone, the symbolContainer plugin option can be set to g for placing <g/> (group) elements instead. Then the collapseGroups plugin, that runs afterwards, would unwrap all the singular, wrapped SVG elements.
Note that the current version of the collapseGroups plugin seems to have issues with some elements, notably <path>, as such does not support the x/y attributes, and transform has to be used instead. This is outside of the scope of the dereferenceUses plugin and this PR. The collapseGroups plugin requires a fix that makes it able to apply the x/y attributes of the wrapping element <g/> onto the the <path/> elements as transform or some other supported mechanism of positional translation for such elements.
Sweet, that's working quite well now. It grows the file, of course, but the improvement in inspectability and (with --pretty) readability is night and day. Awesome work!
@Pomax: Please also notice the side note above! It is possible to further unwrap these elements (from their <svg/> wrappers) using the existing, built-in collapseGroups plugin. However, that collapseGroups plugin has some issues with <path/> elements as these don't support the x and y attribute. A new PR has to be made with a fix for the collapseGroups plugin if this should also work with <path/> elements.
I tried this on your input SVG and indeed, the <path/> elements stand alone afterwards, but are incorrectly positioned because the collapseGroups plugin doesn't handle the x/y for <path/>s.
I do notice that all the nested <svg> have overflow="visible" which a single <style>:root > svg { overflow: visible }</style> would take of, would it make sense to add that in to shave off some more bytes? For files like these, that's 1~2kb saved because of the crazy number of <use...> =)
(specifically, this files -and about 250 files like it- is the result of running a latex -> pdfcrop -> pdf2svg -> svgo chain, with pdf2svg basically mirroring the PDF spec in SVG instructions, so you get a tremendous amount of <use> and <symbol> because that's how PDF files do typesetting)
@Pomax: It may be negligible for the effective SVG file size when dereferencing the <use/>s using this plugin, always check the gzipped file size of the SVG. Either by uploading + getting the SVG and checking the actual size in Network tab of Web Developer Tools (for the actual server gzip settings) or by compressing the SVG file yourself using the gzip command: gzip input.svg.
GZIP is similar to <use/> but on text level. So it may well be that it takes care well of the <svg/> wrapper elements.
fair point: once gzip is involved there is no size difference.
@Pomax: There is the inlineStyles plugin, and as kind of opposite to that, another "externalizeStyles" plugin was planned, that could try to move all inline styles to external styles and simplify, but with GZIP it may be too much of a hassle.
yeah definitely. Plus, for what I need, externalizing styles is not really an option, the files need to stay self-contained. If gzip/brotli makes it a non-optimization over the wire, then no reason to try to micro-optimize there.
I think this PR got lost: is it still possible to land this?
It appear that a style attribute on a <use> element causes a problem. Here is a minified example:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 1 1" height="64" width="64">
<defs>
<symbol id="a" overflow="visible">
<path/>
</symbol>
</defs>
<use xlink:href="#a" style="fill:#000"/>
</svg>
@@@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 1 1" height="64" width="64">
<defs>
<symbol id="a" overflow="visible">
<path/>
</symbol>
</defs>
<svg style="fill:#000">
<path/>
</svg>
</svg>
@@@
{"keepHref":true}
And the resulting error:
TypeError: properties.forEach is not a function
at CSSStyleDeclaration.getCssText (lib/svgo/css-style-declaration.js:121:14)
at CSSStyleDeclaration.getStyleValue (lib/svgo/css-style-declaration.js:56:15)
at Function.entries (<anonymous>)
at JS2SVG.createAttrs (lib/svgo/js2svg.js:292:38)
at JS2SVG.createElem (lib/svgo/js2svg.js:271:12)
at JS2SVG.convert (lib/svgo/js2svg.js:100:19)
at JS2SVG.createElem (lib/svgo/js2svg.js:261:27)
at JS2SVG.convert (lib/svgo/js2svg.js:100:19)
at module.exports (lib/svgo/js2svg.js:50:29)
at optimize (lib/svgo.js:49:13)
at /home/zoey/repos/svgo/test/plugins/_index.js:34:26
@zoeyfyi: I added your plugin test and indeed the test run fails now.
Edit: Alright, this uncovered a bug in the CSSStyleDeclaration implementation of svgo. This separate PR addresses the underlying issue: https://github.com/svg/svgo/pull/1449
I have a fix here. From my limited understanding, here is what I discovered:
- Map's become objects with the JSON seralize/deseralize deep clone trick, hence the
properties.forEach is not a functionerror (https://github.com/zoeyfyi/svgo/blob/49533cf48a3216747d6aa7d45ed266cc5fef9f6b/lib/svgo/css-style-declaration.js#L35) - The
addAttrmethod does not handle adding style attributes correctly (https://github.com/zoeyfyi/svgo/blob/49533cf48a3216747d6aa7d45ed266cc5fef9f6b/plugins/dereferenceUses.js#L68)
Ah, looks like you have already figured this out :sweat_smile:
@zoeyfyi: Fix for the underlying issue: https://github.com/svg/svgo/pull/1449 The CI tests for this plugin will pass when this other PR has been merged.
Concerning this plugin: I fixed the expected result in your test (the href is kept and the overflow attribute was missing).
Also the plugin now applies the styles of the <use/> element on top of the referenced styles.
Edit: A fix has been merged (not this one, but it works now).
@TrySound: Ready to merge! 🐱
@TrySound: So I looked further into the visitor pattern for plugins.
Should the plugin traverse all the <use> and target nodes on its own and map them to each other -
or just use the root node and use querySelectorAll/querySelector to query for these elements?
See https://github.com/svg/svgo/pull/1624 You can collect all elements why traversing and finish transformations in root.exit
@strarsis just noticed this is still taking up space in my "mentioned PRs" list, given how long it's taken for it not to get merged in, it's probably worth closing?
@TrySound: How can the parent node/element be retrieved from an XastElement? The parentNode attribute is deprecated and not really accessible with TypeScript checking. The parent element is needed for each <use> element.
And how can a XastElement be cloned / copied / duplicated?
parentNode is passed to element callback in visitor
structuredClone can copy elements
@TrySound: The tests all pass except for the regressions test, but not because of the plugin but of a failing test setup. An additional, separate PR fixes that issue: https://github.com/svg/svgo/pull/1759
A polyfill for structuredClone is added for support of the older node versions that are tested against.