Multiple inline SVGs on a page can clash
See original GitHub issueHave you read the Contributing Guidelines on issues?
- I have read the Contributing Guidelines on issues.
Prerequisites
- I’m using the latest version of Docusaurus.
- I have tried the
npm run clear
oryarn clear
command. - I have tried
rm -rf node_modules yarn.lock package-lock.json
and re-installing packages. - I have tried creating a repro with https://new.docusaurus.io.
- I have read the console error message carefully (if applicable).
Description
Including multiple inline SVGs on a page like so:
import FooSvg from '@site/static/img/foo.svg';
import BarSvg from '@site/static/img/bar.svg';
export default function SomePage() {
return (
<div>
<FooSvg />
<BarSvg />
</div>
);
can result in the SVGs clashing with each other if those SVGs use ids internally.
The reason the inline SVGs aren’t working is because of the way Docusaurus has configured its SVG loader internally. Docusaurus uses the Webpack loader for SVGR. SVGR in turn uses SVGO. By default, SVGO minifies SVG ids. When those ids get minified to single characters (like “a”, “b”, “c”), they can clash on the page. SVGO has an option to prefix ids, but Docusaurus has not turned that option on. I created a minimal reproduction of the bug. You can comment out one SVG at a time from the source code, and see that when only one SVG is on the page, it renders properly. But when both are on the page, one clashes with the other.
I think one possible way to fix this would be to add the SVGO option prefixIds: true
just below line 123 in webpackUtils.ts.
Reproducible demo
https://stackblitz.com/edit/github-ptytnu?file=src/pages/index.js
Steps to reproduce
All I did to create the minimal repro was to start with a fresh Docusaurus install using new.docusaurus.io, upload two SVGs that I know clash, then import and render those two SVGs into the existing index page.
Expected behavior
The SVGs should look the way they look when rendered individually.
Actual behavior
The SVGs are colored and painted incorrectly because the gradients or masks in one SVG are being applied on top of another.
Your environment
If you wish to dig in more, you can look at the history of the pull request I was working on when I ran into this bug:
Self-service
- I’d be willing to fix this bug myself.
Issue Analytics
- State:
- Created 10 months ago
- Comments:15
Top GitHub Comments
This bug is nasty and cost ~5 hours on what should have been a 10 minute task. I think the approach you are considering here is wrong. Instead of enabling
prefixIds
, why not disablecleanupIds
?cleanupIds
minifies ids without consideration of the global context. Most editing tools already include id minification and prefix additions. Disabling thecleanupIds
option delegates id management to the export tool. It also reduces confusion about how SVGs are processed by webpack (e.g. ids are left alone). Maybe it’s not a perfect long term solution, but seems simple/backward compatible enough that it could be pushed through quickly.Enabling both
cleanupIds
andprefixIds
seems insane to me. Are the prefixes random? How much entropy is there? If i add 100 svgs each with 10,000 ids am I risking an id collision?? Less magic in the processing = less stuff to debug.On a related note, enabling id minification without handling collisions seems like an insane default from
svgo
.In fact, users can’t target SVG IDs with external CSS—SVGO removes all unreferenced IDs. This can be symphasized with—all tools I know (i.e. Inkscape, Illustrator) add an ID to literally every path, so it’s mostly useless.