react-native-eva-icons
react-native-eva-icons copied to clipboard
File size
💬 Question
Looking at my bundle size on web a large part of it is eva icons.
Another large part of it is @ui-kitten/components, specifically ui (and of course mapping).
I was wondering if there's something that can be done to reduce this. I only use 4 icons in total, so it seems a bit much to have all of it in the bundle.
React Native Eva Icons Version
"@ui-kitten/components": "^5.0.0", "@ui-kitten/eva-icons": "^5.0.0", "@eva-design/eva": "^2.0.0",
You may use this package + this guide to create an icon pack for your app without installing @ui-kitten/eva-icons
Or...
Seems you can’t. The large file size will come from the generated index.js of this package, which contains a switch clause for accessing icons by name.
I don’t see any solution for it by now
Maybe it can change to the way material icons work? They need to be imported directly which allows for smaller bundle sizes.
This could work? There's a convenience when importing everything from the same file (index) but you also lose a lot of optimizations. Same goes for UI Kitten I suppose. That's why you can import specific parts from firebase, material and even lodash. I believe it's called "tree shaking" but I'm not super familiar with that yet.
In any case, that could reduce file size by a lot, and would make for a pretty awesome update. I can help! 😄
@RWOverdijk This is slightly off topic for react-native-eva-icons
, but I hacked a solution into ui-kitten
For my use case I want individual components to register their required icons, which can then be duduped and tree-shaken per bundle.
import { SvgProps } from "react-native-svg";
import { IconProps } from "@ui-kitten/components/ui/icon/icon.component";
import { IconRegistryService } from "@ui-kitten/components/ui/icon/service/iconRegistry.service";
import { IconPack } from "@ui-kitten/components/ui/icon/service/type";
import { EvaIcon } from "@ui-kitten/eva-icons/evaIcon.component";
import { kebabCase } from "src/utilities/string";
// Override the register function to allow partial pack registers
Object.getPrototypeOf(IconRegistryService).register = function register<T>(
this: typeof IconRegistryService,
...packs: IconPack<T>[]
) {
packs.forEach((pack: IconPack<IconProps>) => {
this.registerIconPack({
name: pack.name,
icons: {
...this.getIconPack(pack.name)?.icons,
...pack.icons,
},
});
});
};
export function registerIconPacks<T>(...packs: IconPack<T>[]): void {
IconRegistryService.register(...packs);
}
export function registerIcons(
icons: Record<string, React.ComponentType<SvgProps>>,
name?: string
): void {
IconRegistryService.register({
// eslint-disable-next-line @typescript-eslint/ban-ts-comment -- Need to access protected function
// @ts-ignore
name: name || IconRegistryService.getDefaultPack().name,
icons: Object.fromEntries(
Object.entries(icons).map(([key, icon]) => [
kebabCase(key),
new EvaIcon(icon),
])
),
});
}
This then allows my React components to register their icons
import CalendarOutline from "react-native-eva-icons/icons/CalendarOutline";
import { registerIcons } from "src/IconRegistryHack";
registerIcons({
CalendarOutline,
});
I'm using NextJS as my framework, so I can simply include the hack in the _app.tsx
file and everything works out. I haven't really tested this, so there might be some issues - but hopefully this gives you some ideas.