svgo icon indicating copy to clipboard operation
svgo copied to clipboard

Add `dereferenceUses` plugin

Open strarsis opened this issue 5 years ago • 37 comments

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).

strarsis avatar Sep 02 '20 18:09 strarsis

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>

Pomax avatar Sep 04 '20 17:09 Pomax

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 avatar Sep 04 '20 17:09 Pomax

@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 [...]

strarsis avatar Sep 04 '20 18:09 strarsis

Right, but that's what I used? I issued npx svgo 9215d05705c8e8a7ebd718ae6f690371.svg --enable=dereferenceUses

Pomax avatar Sep 04 '20 19:09 Pomax

@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!

strarsis avatar Sep 04 '20 23:09 strarsis

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 avatar Sep 05 '20 17:09 Pomax

@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.

strarsis avatar Sep 05 '20 18:09 strarsis

aha! let me give it another go =)

Pomax avatar Sep 05 '20 18:09 Pomax

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.

strarsis avatar Sep 05 '20 18:09 strarsis

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 avatar Sep 05 '20 19:09 Pomax

@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.

strarsis avatar Sep 05 '20 19:09 strarsis

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 avatar Sep 05 '20 19:09 Pomax

@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.

strarsis avatar Sep 05 '20 19:09 strarsis

fair point: once gzip is involved there is no size difference.

Pomax avatar Sep 05 '20 19:09 Pomax

@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.

strarsis avatar Sep 05 '20 19:09 strarsis

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.

Pomax avatar Sep 05 '20 19:09 Pomax

I think this PR got lost: is it still possible to land this?

Pomax avatar Jan 25 '21 19:01 Pomax

@TrySound: Ready to merge!

The collapseGroup plugin needs a fix, in another PR.

strarsis avatar Mar 19 '21 13:03 strarsis

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 avatar Mar 22 '21 01:03 zoeyfyi

@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

strarsis avatar Mar 22 '21 10:03 strarsis

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 function error (https://github.com/zoeyfyi/svgo/blob/49533cf48a3216747d6aa7d45ed266cc5fef9f6b/lib/svgo/css-style-declaration.js#L35)
  • The addAttr method 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 avatar Mar 22 '21 11:03 zoeyfyi

@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).

strarsis avatar Mar 22 '21 11:03 strarsis

@TrySound: Ready to merge! 🐱

strarsis avatar Mar 27 '21 16:03 strarsis

@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?

strarsis avatar Apr 15 '21 16:04 strarsis

See https://github.com/svg/svgo/pull/1624 You can collect all elements why traversing and finish transformations in root.exit

TrySound avatar Dec 07 '21 08:12 TrySound

@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?

Pomax avatar Mar 22 '23 17:03 Pomax

@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?

strarsis avatar Mar 23 '23 19:03 strarsis

parentNode is passed to element callback in visitor

structuredClone can copy elements

TrySound avatar Mar 24 '23 03:03 TrySound

@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.

strarsis avatar Mar 24 '23 13:03 strarsis