nuxt / icon

The <Icon> component, supporting Iconify, Emojis and custom components.

Home Page:https://stackblitz.com/edit/nuxt-icon-playground?file=app.vue

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[Feature Request] Include Icons in build instead of doing network requests

madebyfabian opened this issue · comments

Hey there, thanks so much for this module! It's absolutely great and easy to use.
I noticed something though, where I couldn't find a config for. In Production, the icons are loaded over the network via https://api.iconify.design/ri.json?icons=icon-name. This can cause several issues, such as:

  • When API is potentially offline, users would not see icons?
  • In the EU it's actually a law issue with GDPR since the HTTP endpoint could receive & process some personal data in the headers (I'm sure you don't, but of course I don't have any control), like the IP, User-Agent, Refrerrer, etc. See the google fonts GDPR issue https://complianz.io/google-fonts-and-gdpr-does-it-work/)
  • The loading times for slow connections could be high, leading in slower web loading times
  • Building offline apps (PWAs) might be more difficult (I see that it gets cached in localStorage)
  • Other general issues I may not have listed above

Maybe I'm understanding wrong and the Module perfectly works without connecting to this API, but I think it would be great to have an option to store all used icons locally on build and request them from a local server endpoint.

Hey guys! I was thinking of implementing this feature but I was wondering which approach should I take. Maybe adding a module option like offline and then downloading icons at build-time and referencing them conditionally in the Icon component.

I think it's also important for online mode, bc for instance if I have a theme switcher and click on it (switching color theme and icon) the icon disappears for a few hundred ms until the new one is downloaded. Would be nice if in online mode it would download and cache all icons right away in the background after page load is finished.

You can see the effect here: https://webapicheck.com

Hey guys! I was thinking of implementing this feature but I was wondering which approach should I take. Maybe adding a module option like offline and then downloading icons at build-time and referencing them conditionally in the Icon component.

Any news about that? Thanks

I found this in the Doc for building an offline bundle https://docs.iconify.design/icon-components/bundles/

I found this in the Doc for building an offline bundle https://docs.iconify.design/icon-components/bundles/

Hi, thanks for the help. I took a look.

I'm using this https://github.com/nuxt-modules/icon and figured out that this module puts the svg directly on html, so it loads offline.

I saw that using capacitor and generating an apk the icon wasn't showing. So I think the problem is with capacitor and not from offline.

I think it's also important for online mode, bc for instance if I have a theme switcher and click on it (switching color theme and icon) the icon disappears for a few hundred ms until the new one is downloaded. Would be nice if in online mode it would download and cache all icons right away in the background after page load is finished.

You can see the effect here: https://webapicheck.com

@toniengelhardt I guess you could do that with plain CSS

I think it's also important for online mode, bc for instance if I have a theme switcher and click on it (switching color theme and icon) the icon disappears for a few hundred ms until the new one is downloaded. Would be nice if in online mode it would download and cache all icons right away in the background after page load is finished.
You can see the effect here: https://webapicheck.com

@toniengelhardt I guess you could do that with plain CSS

It says "the icons won't be loaded on initial load and an HTTP request will be made to Iconify CDN to load them" in the README though?

I need this. It only shows mdi:access-point-network-off text, instead of the icon when the PWA is offline.

In the end, I downloaded icons from icones.js.org and integrated them using nuxt-icons. 😅

In the end, I downloaded icons from icones.js.org and integrated them using nuxt-icons. sweat_smile

@mkdirnow how is that possible?

commented

In the end, I downloaded icons from icones.js.org and integrated them using nuxt-icons. 😅

Seems inconvenient though...

@mkdirnow how is that possible?

Seems inconvenient though...

In fact, most of the icons in my project are individual SVG files, and only a few places use icons from icones.js.org.
However, this plugin is really convenient, and I'm looking forward to the offline feature.

I agree with everything @madebyfabian mentioned but want to add another point.
The icon svg's are embedded into the rendered html nuxt renders meaning the nuxt server had to actually fetch them on request time - which can't be beneficial for performance/ time to first byte.

Tbh I was assuming things were bundled at build time as nowhere in the readme individual http requests are mentioned.
Hoping this is something that can be resolved, going down the rabbit hole of individually creating components for each icon sort of defeats the purpose of the module unfortunately

I was using unplugin-icons (which bundled the icons at build time) before migrating to Nuxt.

Do you foresee this to be a difficult issue to solve?

With Unplugin icons you need to import manually the icons you use, with Nuxt icons its a string that could be any unicons icon.
Maybe we could have a whitelist feature that bundles the whitelisted icons ?

With Unplugin icons you need to import manually the icons you use, with Nuxt icons its a string that could be any unicons icon. Maybe we could have a whitelist feature that bundles the whitelisted icons ?

Not if you set up auto-importing

As a user od the module I would also love to see the option to support bundled icons without having to do the request to get them. Only missing part for it to be perfect for us.

We can create a nitro event handler to serve the icons data from either @iconify/json or @iconify-json/[collection-id] if installed, with a fallback to iconify api?

What do you think @atinux ?

In what case would it be more performant than Iconify API @stafyniaksacha ?

I'm currently developing a Vue application designed for offline use. I've been contemplating migrating to Nuxt due to its appealing features, such as automatic component imports and integrated UI libraries. However, I'm concerned that Nuxt may predominantly cater to applications with an online-first approach.

I'm eager to hear from anyone who has experience in building offline applications using Nuxt. Specifically, I'm interested in understanding any potential drawbacks or limitations encountered during development. Does Nuxt accommodate the needs of offline applications effectively, or are there significant challenges I should be aware of?

commented

Currently very unfriendly for offline applications.

We are planning to rewrite this module to avoid making network requests.

As workaround, if you are using UnoCSS, you can use https://unocss.dev/presets/icons

If you are using TailwindCSS, you take take a look at https://github.com/egoist/tailwindcss-icons

If you are using Nuxt UI, we already support offline with UIcon component (based on TailwindCSS-Icons)

I still believe there would be some of us who would benefit from bundling the icons into the build. Maybe there could be an option to opt-in?

Mainly because right now (v1.2.0) if I create a SPA with ssr: false, every time I navigate to a page with new icons they aren't rendered until they load from Iconify's API. I just see them suddenly appear, which doesn't look good.

It would be nice to be able to bundle the icons natively without relying on the UnoCSS or TailwindCSS workarounds.

The main selling point of using Nuxt Icons is the dynamic bits, which support rendering icons that you retrieved at runtime (dynamic content, user content, etc.). Other solutions like unplugin-icons and UnoCSS Icons only support bundling the icons that are known at build time. Supposedly, they should work as a complement; Nuxt Icon v1 also dedupe the icon fetching if it's already been provided by UnoCSS.

Because the focus is fully dynamic, meaning it would be hard for Nuxt Icon to pre-bundle the icons at build time.

For example, to know the usage of your icons, the module would need to scan every file in your project to detect usage statically like this:

<template>
  <Icon name="carbon:sun" />
</template>

Where the cases like:

<script setup>
const props = defineProps({
  icon: String
})
</script>

<template>
  <Icon :name="icon" />
</template>

It won't be possible to know what's the value of the props passed in at build time. (any many more edge cases like this).

That said, I would still love to improve the DX with this, but in order to perform good static analysis result, we would need to:

  1. Define a strict syntax convention that can be statically extracted (we are kind of re-implementing UnoCSS in this case)
  2. Only usages following that convention would be able to be bundled, the others will still fallback to runtime fetching
  3. Opt-in this behavior as it would perform a project-wide filesystem scan. It can be inefficient for projects with a lot of files.

I would need to have some examples of your project usage to know what would be the best way to support that.

Please share your project or a minified version below and tell your usage/expectation.

So we could come up with a better design that works for the majority of the users. Thanks

@antfu it might not be ideal, but if the scanning is too complex, maybe there could be a preload list in the config, similar to the safelist in unocss, and we can then prefetch all icons in the preload list and alias list if the preload setting is enabled.

Defining aliases for all icons is anyway good practice IMO, it makes the project more maintainable.

You are right @antfu. I see your point in how this introduces complexity beyond what I would know how to do.

I won't say this is a deal breaker, it's just a UX/DX improvement. It is definitely so nice to only write the icon name and magically have it appear. Unfortunately, as soon as the client is hydrated and SPA takes control, rendering icons that weren't at the initial page load last a tiny bit to appear, which feels weird but it's not critical.

If this feature is at all possible, but requires defining a fixed pattern to write the names of icons (such as TailwindCSS Icons with i-{collection}-{icon}) I believe that anyone who really needs it won't mind the extra step. That's how Nuxt UI v2 does it and I think it is both nice UX/DX. Of course, @nuxt/icon will use dynamic icons as the default and bundled would be opt-in.

I tried unplugin-icons and it works just fine. If this is not possible for @nuxt/icon, I will certainly use it. But of course, only writing <Icon name="i-ph-x" /> is way nicer than having to import every icon and use them as a separate component. That's why it's not a deal breaker, just a quality-of-life improvement.

Most of the projects I build are SPA's on the client side, since they are admin dashboards or management platforms. I don't use SSR as much. But even with SSR, once hydration happens, I have the same issue. Here's a video on what I mean (uses 3G network throttling to make the icon loading time more visible)

Arc.mp4

#208 and #223 should give the capability of doing so. We will still need to figure out a better way to do auto-discovery in the future