Skip to content
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

Tree Shaking #3

Open
ksweetie opened this issue Jun 4, 2023 · 2 comments
Open

Tree Shaking #3

ksweetie opened this issue Jun 4, 2023 · 2 comments

Comments

@ksweetie
Copy link

ksweetie commented Jun 4, 2023

Hello! I was wondering if you had any thoughts on reducing bundle size when using this library. We're using a relatively small number (50~) of icons, so I'd like to leverage tree shaking to only include the icons we're using. As is, the icons load in noticeably after the rest of the page, causing a flicker when they render in. I think this could be fixed if we weren't making the browser download and parse JS for thousands of icons.

I would expect this to only load a single icon when used with, for example, Vite tree shaking:

import { PhArrowBendUpRight } from '@phosphor-icons/webcomponents'

But it looks like every icon gets bundled.

Curious if you have any thoughts, ideas, workarounds, etc. Thank you!

@rektdeckard
Copy link
Member

rektdeckard commented Apr 2, 2024

Hey @ksweetie, sorry for taking so long to respond 😅.

I recommend importing each icon separately from their fully-qualified path, rather than using the barrel file. Since the import side-effect is what registers the custom elements, you don't need to use the values and can just stick all of these in a file somewhere, then source that file:

icons.ts

import "@phosphor-icons/webcomponents/PhAvocado";
import "@phosphor-icons/webcomponents/PhCheese";
import "@phosphor-icons/webcomponents/PhChefHat";

main.tsx

import "./icons";

export default function App() {
  return (
    <main>
      <ph-avocado size={32} weight="duotone" color="darkolivegreen" />
      <ph-cheese size={32} weight="duotone" color="goldenrod" />
      <ph-chef-hat size={32} weight="duotone" color="white" />
    </main>
  );
}

This is sorta pseudo-code, because I don't know what framework (if any) you're working in, but as long as the icons are imported for effect, you'll be able to use them. Some JSX implementations will need to be taught about the custom elements to have correct type inference in your editor — for example in SolidJS I would include the following in my icons file:

icons.ts

import type { IconAttrs } from "@phosphor-icons/webcomponents";
import "@phosphor-icons/webcomponents/PhAvocado";
import "@phosphor-icons/webcomponents/PhCheese";
import "@phosphor-icons/webcomponents/PhChefHat";

declare module "solid-js" {
  namespace JSX {
    interface IntrinsicElements {
      "ph-avocado": IconAttrs;
      "ph-cheese": IconAttrs;
      "ph-chef-hat": IconAttrs;
    }
  }
}

I believe Typescript should pick up the JSX extension automatically when using them in HTML or React files.

@rektdeckard
Copy link
Member

Just to put a finer point on it, as far as I know, most bundlers will not attempt to tree-shake if modules are marked as having side-effects. When importing something directly from the barrel file as you showed in your example, the bundler has no way of knowing that it is OK not to load the other imports in that file besides PhArrowBendUpRight, because important things might happen when a module is loaded.

We rely on those side-effects to register the custom element type on the window, so we can't really do the barrel-file package structure. We could, but we'd have to then force you to call some method manually to register the custom elements you use:

import { register, PhArrowBendUpRight } from "@phosphor-icons/webcomponents";

register(PhArrowBendUpRight);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants