react-native-eva-icons icon indicating copy to clipboard operation
react-native-eva-icons copied to clipboard

File size

Open RWOverdijk opened this issue 4 years ago • 5 comments

💬 Question

Looking at my bundle size on web a large part of it is eva icons.

image

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",

RWOverdijk avatar Jul 03 '20 12:07 RWOverdijk

You may use this package + this guide to create an icon pack for your app without installing @ui-kitten/eva-icons

artyorsh avatar Jul 03 '20 12:07 artyorsh

Or...

artyorsh avatar Jul 03 '20 12:07 artyorsh

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

artyorsh avatar Jul 03 '20 12:07 artyorsh

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 avatar Jul 03 '20 13:07 RWOverdijk

@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.

marklawlor avatar Nov 26 '20 12:11 marklawlor