Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add dereferenceUses plugin #1279

Open
wants to merge 37 commits into
base: main
Choose a base branch
from
Open

Conversation

strarsis
Copy link
Contributor

@strarsis strarsis commented Sep 2, 2020

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

@Pomax
Copy link

Pomax commented Sep 4, 2020

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
Copy link

Pomax commented Sep 4, 2020

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>

@strarsis
Copy link
Contributor Author

strarsis commented Sep 4, 2020

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

@Pomax
Copy link

Pomax commented Sep 4, 2020

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

@strarsis
Copy link
Contributor Author

strarsis commented Sep 4, 2020

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

@Pomax
Copy link

Pomax commented Sep 5, 2020

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.

@strarsis
Copy link
Contributor Author

strarsis commented Sep 5, 2020

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

@Pomax
Copy link

Pomax commented Sep 5, 2020

aha! let me give it another go =)

@strarsis
Copy link
Contributor Author

strarsis commented Sep 5, 2020

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.

@Pomax
Copy link

Pomax commented Sep 5, 2020

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!

@strarsis
Copy link
Contributor Author

strarsis commented Sep 5, 2020

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

@Pomax
Copy link

Pomax commented Sep 5, 2020

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)

@strarsis
Copy link
Contributor Author

strarsis commented Sep 5, 2020

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

@Pomax
Copy link

Pomax commented Sep 5, 2020

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

@strarsis
Copy link
Contributor Author

strarsis commented Sep 5, 2020

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

@Pomax
Copy link

Pomax commented Sep 5, 2020

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
Copy link

Pomax commented Jan 25, 2021

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

@strarsis
Copy link
Contributor Author

strarsis commented Mar 19, 2021

@TrySound: Ready to merge!

The collapseGroup plugin needs a fix, in another PR.

@zoeyfyi
Copy link

zoeyfyi commented Mar 22, 2021

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

…element (`svg` is the default).

Add tests for `<symbol>` elements as target.
Add comments.
@strarsis
Copy link
Contributor Author

strarsis commented Mar 23, 2023

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

@TrySound
Copy link
Member

parentNode is passed to element callback in visitor

structuredClone can copy elements

@strarsis
Copy link
Contributor Author

strarsis commented Mar 24, 2023

@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: #1759

A polyfill for structuredClone is added for support of the older node versions that are tested against.

@kuhler-Stratege
Copy link

Any updates on this?

@Pomax
Copy link

Pomax commented Aug 29, 2024

Also note that structuredClone does not need a polyfill. Due to how long this PR's been taking, all versions of Node that are still in support, support structuredClone.

@strarsis
Copy link
Contributor Author

strarsis commented Aug 29, 2024

@kuhler-Stratege; @Pomax; @SethFalco: I merged all the changes and updated the plugin code and documentation.

@SethFalco: How can I run the tests for non-preset default plugins as this one, or run tests only for a specific (this one) plugin?
For testing I temporarily added the plugin to default preset.

@strarsis
Copy link
Contributor Author

strarsis commented Aug 29, 2024

@Pomax:

Due to how long this PR's been taking, all versions of Node that are still in support, support structuredClone.

The CI tests still include Node 16 which does not natively support structuredClone and requires a polyfill:
https://github.com/svg/svgo/actions/runs/10619846377/job/29438306446?pr=1279

@SethFalco: Is Node 16 still supported by svgo, as there are still CI tests for that version?

@strarsis strarsis changed the title Add dereferenceUses plugin Add dereferenceUses plugin Aug 29, 2024
@Pomax
Copy link

Pomax commented Aug 29, 2024

Note that Node 16 is no longer supported by Node itself, the current maintenance LTS is v18 and active LTS is v20 - it should definitely be removed from any CI tasks with svgo itself bumped up a major version. The benefit of semver: no one is inconvenienced =)

@strarsis
Copy link
Contributor Author

All checks are passing except the node version 16 one (that may have to be removed).
Except for two lines (that are only used for type-correctness) the plugin has full test coverage.
So from my perspective the plugin is ready to be merged in.

One thing though: How can I force this plugin to run before/after specific other plugins,
even with this plugin being not one in the default preset?

@Pomax
Copy link

Pomax commented Oct 25, 2024

@TrySound is there anyone else who can be marked as reviewer? Sure, it's been years, but if the plugin still works, no reason to not still land it =)

@GreLI
Copy link
Member

GreLI commented Oct 27, 2024

@SethFalco ☝🏻

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants