-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
feat(astro): add Built-in SVG component support #12067
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
Conversation
🦋 Changeset detectedLatest commit: 7b4a3a9 The changes in this PR will be included in the next version bump. Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This PR is blocked because it contains a major changeset. A reviewer will merge this at the next release if approved.
2ff0715 to
5f8997c
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Left a few suggestions, but this looks really good!
packages/astro/client.d.ts
Outdated
| /** | ||
| * Bypasses automatic sprite optimization by directly inlinining the SVG | ||
| */ | ||
| inline?: boolean |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After sitting with this for a while, inline behavior should be the default. There are a few edge-cases that have come up with dynamic client-side behavior in astro-icon, so while I still think the optimization is very useful, we should prioritize flexibility by keeping the sprite behavior opt-in.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right. I think especially with the SVG imports that developers wouldn't necessarily assume the optimization by default.
My first thought is to offer a "mode" that allows for "sprite" or "inline" ("inline" being the default) that is configurable in the Astro Config. I assume we'll later have some other properties under and "svg" scope such as an "image service" (like svgo).
I have also seen an interesting use-case (natemoo-re/astro-icon#238) that we might be able to support later for exporting symbols instead. This would be fairly trivial with a "mode" and might enable some better DX around framework usages.
I would like to discuss and perhaps iterate a bit on the way we allow developers to opt-in/out of inline/sprite usages. Will bring this up in the Stage 3 RFC.
| // Attach file data for SVGs | ||
| if (fileMetadata.format === 'svg') { | ||
| emittedImage.contents = fileData; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would love @Princesseuh's take on this. Any expected footguns with including the file content for SVGs in the image metadata?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you have a lot of SVGs, this can be problematic for SSR since it'll get in your bundle, that's my only concerns
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right. Unfortunately that will be unavoidable for this feature.
I think the DX improvement is worth the tradeoff, though!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is definitely outside my realm of expertise. I'll defer to whatever the consensus is here :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Something we could do one day (definitely outside of this PR), though it'd make SVG icons somewhat slower in SSR is add a lazy data property or something, that's essentially async () => await fetch(this.src) in SSR and something else in SSG so that you can load the data without it being added to the bundle.
| // Attach file data for SVGs | ||
| if (fileMetadata.format === 'svg') { | ||
| emittedImage.contents = fileData; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you have a lot of SVGs, this can be problematic for SSR since it'll get in your bundle, that's my only concerns
5f8997c to
313caaa
Compare
|
I have added it behind an experiment flag called @natemoo-re would love your opinion on this approach for configuring the sprite vs inline method |
ad55d4e to
bf5e98b
Compare
|
@stramel While I was working on the PR, I noticed that you added a new configuration in Astro, which is fine, however the RFC doesn't mention anything about it. We should update the RFC and explain the options. Also, here's some feedback regarding experimental options. There aren't written rules, but in the past I was in your same situation and I went for this route: export default defineConfig({
svg: {
mode: "inline"
},
experimental: {
svg: true
}
})We still need to have the experimental flag, which stays a boolean every time. Then, you create a new section in the Astro configuration. You're still free to change it as you see fit, because it's part of the experimental feature, however I found that the maintenance of these two separate sections is easier for us maintainers. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you so much for this amazing feature @stramel ! I think people are going to really enjoy this! 🙌
I've done a quick pass on the documentation (changeset and flag docs) and you'll find some suggestions below for your consideration!
I know Nate has a docs PR going, and it seems like the mode property is newer than that, so we'll just make sure that we've got everything we need in the docs PR, too, before docs totally signs off on this! 🚀
| * - `inline`: Astro will inline the SVG content into your HTML output. | ||
| * - `sprite`: Astro will generate a sprite sheet with all imported SVG files. | ||
| * | ||
| * When using 'sprite' mode, it is important to note that the symbol definition will be included with the first instance of the SVG that is rendered. This means that if the first instance is hidden or removed from the DOM, all other references will break. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| * When using 'sprite' mode, it is important to note that the symbol definition will be included with the first instance of the SVG that is rendered. This means that if the first instance is hidden or removed from the DOM, all other references will break. | |
| * When using 'sprite' mode, it is important to note that the symbol definition will be included with the first instance of the SVG that is rendered. This means that if the first instance is hidden or removed from the DOM, all other references will break. |
Question: is this unique to Astro's implementation, or would this be something common to using a sprite sheet in general? I get that it's a caveat, but if it's not an Astro-specific caveat then it's a little bit more for the reader to have to process before they even see how to use this feature.
I might suggest we either remove this paragraph entirely (we do say full details in the RFC!), or place it after the code example if this is a super key thing and people will have a lot of trouble using the feature if they don't know this immediately up front.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is unique to the implementation that we chose to go with. Though it would probably apply to the spritesheet in general but is significantly less common if you just have a single spritesheet.
This is something I was debating about adding as an enhancement later or opt-in. Would need some help from the core team on it though.
I'll leave it up to you if we keep this caveat or remove it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, for this stage of the game, I say we omit the caveat in these docs here. We just get people up and running quickly and happily, and they can check the RFC when and if they run into trouble!
Co-authored-by: Sarah Rainsberger <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Approving for docs!
(Also noting, as I always do, that I don't see any new errors added with this feature. If that changes before the feature is released, then please loop me back in! 🙌 )
Co-authored-by: Sarah Rainsberger <[email protected]>
|
Thank you all for the help to get this in! I greatly appreciate all the reviews and feedback! |
|
Seems there is some kind of issue with the refactor of |
|
Initial fix: #12511 Going to do some testing and ensure I add a test to fail on previous case. Tested with |
Changes
This PR implements Built-in SVG Components following up on the discussions on withastro/roadmap#699
By default, SVG files will be components and can be imported by referencing their file path and then treating them like a component. Take this for example:
previously:
now:
GOALS:
<svg>element while overriding the existing props<svg>on a page can hurt browser parsing performance. We can automatically reduce the number of nodes by using<symbol>and<use>.<svg>often have xmlns and xmlns:xlink and version attributes. These are not needed in HTML5 and we can automatically drop them to save a few bytes.<Icon>component for each supported framework, we’ll make it easy for users to avoid this anti-pattern. It’s so common now because there aren’t many other good solutions.This builds a foundation for us which can be extended in the future within the core astro and even by third-parties. For instance using
astro-icon, which has been the critical plugin when it comes to icons, as a playground, I was able to extend the foundation built here to add dynamic icon import for Iconify.FUTURE:
/cc @natemoo-re
Testing
I have ensured that existing tests are functioning properly and added additional suite for SVG Components.
Manually, I have updated the blog example to include using the SVG components. I have also tested locally against
astro-iconand its demo application. Will work on some testing for this change.Docs
Docs added in withastro/docs#9911