POC: KvIcon2 - Dynamically import and inline svgs instead of using an SVG sprite#1541
POC: KvIcon2 - Dynamically import and inline svgs instead of using an SVG sprite#1541ryan-ludwig wants to merge 2 commits into
Conversation
| }, | ||
| computed: { | ||
| iconFile() { | ||
| return () => import(`@/assets/inline-svgs/icons/${this.name}.svg`); |
There was a problem hiding this comment.
This is where the magic happens.
| @@ -5,7 +5,7 @@ | |||
| autocomplete="off" | |||
| @submit.prevent="onSubmit" | |||
| > | |||
There was a problem hiding this comment.
Implementation example. Really the only change in most cases will be adding the fill in CSS.
|
I don't think it makes sense to do this for all icons, because it results in the svg code for the icon being repeated everywhere its used and included in every page load. This article has a good breakdown of the drawbacks and advantages of various techniques of using svg sprites. https://css-tricks.com/svg-sprites-use-better-icon-fonts/ |
| /** | ||
| * Use KvIcon to display an inlined-svg from /assets/inline-svgs/icons on the page. | ||
| * SVG files should only be one color so they can be styled using CSS fill property: `.my-icon { fill: pink; }` | ||
| * Icons will fill the width of it's container. You can set the width with CSS: `.my-icon { width: 5rem; fill: pink; }` |
There was a problem hiding this comment.
not all icons use fill. Some use stroke. Others have multiple colors embed...
| @@ -0,0 +1,3 @@ | |||
| <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 22 22"> | |||
There was a problem hiding this comment.
Why are these extra files required if we already have individual files in the assets icons folder?
There was a problem hiding this comment.
The special inline-svg webpack loader only pulls from /assets/inline-svgs/**/*.
We could just dump everything from /assets/icons into /assets/inline-svgs/icons, but I'd rather just move what we're actually using by hand to remove cruft.
| } | ||
|
|
||
| .search-icon { | ||
| fill: $kiva-text-dark; |
There was a problem hiding this comment.
I think we should move the base styles for icon sets (some stroke, some fills) out of KvIcon to a global inclusion so these individual tweaks wouldn't be required unless you want a special color. It's not very much css.
There was a problem hiding this comment.
That's not necessary. The css will only be included once per page, as css is included per component definition, not per component instance. Also, as this is in src/components it's probably already being bundled into the global css.
The big performance improvement with this dynamic import method is that most of our svgs won't be included on every page load. An example scenario: In the sprite method, Page1, Page2, and Page3, all make a network request for the sprite and load a, b, c, d, x, y, z onto the DOM regardless of what they use. In the dynamic import method there are no network requests, the server sends the SVG inlined with the HTML via SSR. I've used sprites in the past, while they're really good when you repeat an icon lots times on one page, they're usually just loading a lot of stuff that isn't relevant for that page/component, and tend to bloat over time. Many component libraries in React, Vue, etc. have moved to importing just what they need either as vue/react components or as svgs: IBM's carbon design system Attlasian: React icons: There are some libraries like Vuetify that are still using sprites or even icon fonts 🤷♂️, but trend is moving away from that. Components are great at encapsulating what's needed and avoiding global stuff like sprites. |
|
@ryan-ludwig While that's a good example, we don't actually have any pages that don't load icons (because of the header). The triangle and chevron icons are used many times in every page (especially mobile/small screens). The star icon is almost always used multiple times in a page when it's used (either as the favorite button on every loan, or for showing the risk rating). Sprite sheets take advantage of browser caching, so there's only one request ever needed for an entire browsing session. We definitely shouldn't be putting everything in a sprite sheet, but we also definitely shouldn't be inlining everything. We could rename the KvIcon component to something like KvSprite and be more stringent about what is inlined and what is added to the sprite sheet. |
|
@emuvente That's a good point about the chevrons and triangles, I think making a very slim KvSprite is a good plan :) If we can ultimately reduce the number DOM nodes on the page site-wide, that'd be a good win. We get dinged on lighthouse for the excessive DOM, the current homepage has 832 nodes, of those 465 are from the sprite. I'll try making a slim sprite today and see if we can get the sprite under 50 nodes. |
This will allow us to remove the SVG sprite which currently adds over 450 DOM nodes to every page.
Instead each page will only load the SVGs (inlined) that are on that page (if any).
Keeping the KvIcon component API the same should make the transition fairly simple.
Wanted to run this past the front-enders to get your thoughts first.
To implement, my plan is to
<kv-icon>.my-icon { fill: $my-color }to many icons. Some already do this.