tabler / tabler-icons

A set of over 5400 free MIT-licensed high-quality SVG icons for you to use in your web projects.
https://tabler.io/icons
MIT License
17.84k stars 886 forks source link

icons-svelte builds ALL icons, even ones not used #669

Open silveltman opened 1 year ago

silveltman commented 1 year ago

I'm using @tabler/icons-svelte in my sveltekit project and astro project. When building, it logs the following:

building client 
transforming (8344) ../../sveltekit/fulldev-ui/node_modules/@tabler/icons-svelte/dist/svelte/icons/IconWand.svelte

The above is 1 moment in the build. It takes about 30-60 seconds and goed over every icon

Is this supposed to happen?

PudottaPommin commented 1 year ago

Hey, this relates to #518 and it's at unknown state 😿

kwhitley commented 1 year ago

You'll also notice in dev mode it loads the full 24-25MB (unless you specifically call each icon by it's full @tabler/icons/svelte/dist/svelte/icons/IconName.svelte path. This causes a pretty big delay in even just refreshing a page in dev mode.

alpap commented 11 months ago

same issue here it just bundles everything

danawoodman commented 8 months ago

any word on this? i'm going to stop using Tabler because I can't bear waiting many seconds for each file change with HMR

ttmx commented 8 months ago

any word on this? i'm going to stop using Tabler because I can't bear waiting many seconds for each file change with HMR

As a workaround you can import them like " import IconBattery from '@tabler/icons-svelte/dist/svelte/icons/IconBattery.svelte';" But typescript complains a lot.

danawoodman commented 8 months ago

the combo of no import auto complete and broken typescript types makes this untenable, ended up moving to use Lucide which ironically has the same issue but only loads 7mb instead of the 40mb

is the root export a barrel file like it is with lucide? if so, afaik tree shaking won't work

danawoodman commented 8 months ago

yeah everything is exported via a barrel file so assuming the issue is lack of proper tree shaking

https://github.com/tabler/tabler-icons/blob/master/packages/icons-svelte/src/tabler-icons-svelte.js

perhaps an export file can be auto generated?

ttmx commented 8 months ago

It is definitely hacky, it was just the way I had to make it work, I like tabler icons a lot. I feel this change is much more needed than any new icon, but I don't speak for everyone.

BahaaZidan commented 7 months ago

No news here ?

codecalm commented 7 months ago

I'm working on it here: https://github.com/tabler/tabler-icons/pull/969 πŸ™‚

sapkra commented 6 months ago

@codecalm Any update on this? I have seen that you closed your PR and remove the branch. πŸ‘€

codecalm commented 6 months ago

@sapkra I've moved it to #993 as a part of biggest improvements

TheEisbaer commented 6 months ago

@codecalm is this fix availalbe in the version 3.0.0-alpha.1 already?

Plorenzo commented 6 months ago

I tested 3.0.0-alpha.1 and the issue is still there, all icons are built regardless of how many you are using.

MarArMar commented 6 months ago

Temporary fix :

Set to this version in package.json :

"@tabler/icons-svelte": "2.30.0",
mcmxcdev commented 5 months ago

Temporary fix :

Set to this version in package.json :

"@tabler/icons-svelte": "2.30.0",

I tried it out and it's actually not true. When you run a Vite build it still transforms all icons if you use the named imports from @tabler/icons-svelte directly.

MarArMar commented 5 months ago

@mcmxcdev It fixes my problem and my problem (https://github.com/tabler/tabler-icons/issues/1003) was marked as a duplicate to this one by @BG-Software-BG

So maybe my problem was wrongly marked as a duplicate then

Plorenzo commented 5 months ago

@sapkra I've moved it to #993 as a part of biggest improvements

Hey @codecalm, 3.0 is out and the issue is still happening.

It would be great if you can share if there is any plans to address this soon or not, so people can decide if they can wait or they need to find other solutions.

It's clear there is quite a bit of us waiting for some clarity on this :)

mcmxcdev commented 5 months ago

You can just define your icons like import IconBolt from '@tabler/icons-svelte/icons/bolt' for the time being until this issue is resolved.

codecalm commented 5 months ago

@Plorenzo I dont have to much experience with Svelte and build process with it, so if you have any ideas create PR with solution, please

codecalm commented 5 months ago

I've fixed it in #1039

import IconAd from "@tabler/icons-svelte/IconAd.svelte";
import IconAdOff from "@tabler/icons-svelte/IconAdOff.svelte";
import IconAdFilled from "@tabler/icons-svelte/IconAdFilled.svelte";

Results:

> vite build

vite v5.1.4 building for production...
βœ“ 32 modules transformed.
dist/index.html                  0.40 kB β”‚ gzip: 0.28 kB
dist/assets/index-DzadqsTt.css   1.04 kB β”‚ gzip: 0.56 kB
dist/assets/index-Cg3TY0qG.js   13.24 kB β”‚ gzip: 4.80 kB
βœ“ built in 293ms
TheEisbaer commented 5 months ago

Version 3.0.0:

Importing icons like this

import IconEdit from '@tabler/icons-svelte/icons/edit';
import IconTrash from '@tabler/icons-svelte/icons/trash';

Results in:

vite v5.1.6 building SSR bundle for production...
βœ“ 225 modules transformed.
vite v5.1.6 building for production...
βœ“ 208 modules transformed.

Importing icons like this

import { IconEdit, IconTrash } from '@tabler/icons-svelte';

Results in:

vite v5.1.6 building SSR bundle for production...
βœ“ 5412 modules transformed.
vite v5.1.6 building for production...
βœ“ 5395 modules transformed.

Named imports results in all icons in the icon pack being transformed during build

TheEisbaer commented 5 months ago

I've found a "solution" to this issue over at lucide-icons lucide-icons/lucide#1944 :

function tablerSvelteImportOptimizer(): import('vite').Plugin {
    return {
        name: 'tabler-svelte optimizer',
        transform(code, id) {
            const ms = new MagicString(code, { filename: id });
            ms.replace(
                /([ \t]*)import\s+\{([^;]*?)\}\s+from\s+['"]@tabler\/icons-svelte['"];/g,
                (match, whitespace: string, importNames: string) => {
                    const hasSemi = match.endsWith(';');
                    const imports = importNames
                        .split(',')
                        .map((v) => v.trim())
                        .map((name) => {
                            const path = name;
                            return `${whitespace}import ${name} from '@tabler/icons-svelte/${path}.svelte'${hasSemi ? ';' : ''}`;
                        });
                    return imports.join('\n');
                }
            );

            if (ms.hasChanged()) {
                return {
                    code: ms.toString(),
                    map: ms.generateMap()
                };
            }
        }
    };
}

This converts named imports to direct imports during transforming.

mcmxcdev commented 4 months ago

Did anyone try out https://github.com/tabler/tabler-icons/releases/tag/v3.0.1 which supposedly fixes this issue?

UPDATE: I tried out 3.1.0 and if you use named imports e.g. import { IconEdit } from '@tabler/icons-svelte', the issue is still present. I would like to use named imports though eventually, and I am sure others do as well since that is what this issue is about.

Before 3.0.1, import IconEdit from '@tabler/icons-svelte/icons/edit' used to work which changed to import IconEdit from '@tabler/icons-svelte/IconEdit.svelte' now which is the workaround.

TheEisbaer commented 3 months ago

Any update on this? @codecalm

TheEisbaer commented 3 months ago

@codecalm I have found a possible fix, but don’t know how to implement it:

you are exporting each icon separately in the package.json, that causes a huge slowdown for everything.

I have tried manually renaming every icon to Icon.svelte and doing a single export in the package.json and that improved the performance.

again, I don’t know how to implement it, but it’s worth taking a look at i guesss

rudiv commented 1 month ago

I don't know why this keeps going around in circles, but now the whole import Home from "@tabler/icons-svelte/IconHome.svelte"; has changed back, again, to import Home from "@tabler/icons-svelte/icons/home"; for anyone wondering why things are broken after updating.

BG-Software-BG commented 1 month ago

The change was implemented in response to https://github.com/tabler/tabler-icons/issues/1133

rudiv commented 1 month ago

Yeah I understand the change, it's making zero difference in editor performance at my side but the biggest pain is having to update every single import across the entire project. Because it's JS/TS, this is rather tedious and as far as I can see not documented anywhere other than that issue (and the link to it from the changelog). To me, this is a breaking change and should be documented as such.

That's why I've posted it here in case someone like myself comes frantically stumbling to this GitHub wondering why everything has suddenly broken after updating the package.

mcmxcdev commented 1 month ago

I was also surprised about a breaking change as part of a minor release. It took me 30min to update all icon paths in our codebase and it would be nice if there was a codemod for such things to save everyone some time.

levinit commented 1 month ago

Another alternative is to use the web-font, It depends on whether you can accept the size of the packaged font files

levinit commented 3 weeks ago

I've found a "solution" to this issue over at lucide-icons lucide-icons/lucide#1944 :

thx @TheEisbaer, it solves the issue, but I made a little modification, now pnpm build runs fast, I think only the imported icons are being transformed.

update

pnpm i -D magic-string

create a ts file sush as vite-plugin-optimizer-tabler.ts:

import MagicString from 'magic-string'

// see https://github.com/tabler/tabler-icons/issues/669#issuecomment-1993756128
export default function tablerSvelteImportOptimizer(): import('vite').Plugin {
  return {
    name: 'tabler-svelte-optimizer',
    transform(code, id) {
      const ms = new MagicString(code, { filename: id })
      ms.replace(
        /([ \t]*)import\s+\{([^;]*?)}\s+from\s+['"]@tabler\/icons-svelte['"];?/g,
        (match, whitespace: string, importNames: string) => {
          const hasSemi = match.endsWith(';')
          const imports = importNames
            .split(',')
            .map((v) => v.trim())
            .map((name) => {
              // example: IconArrowRightBar
              //old: import {IconArrowRightBar} from '@tabler/icons-svelte';
              //new: import IconArrowRightBar from '@tabler/icons-svelte/icons/arrow-right-bar';

              //IconArrowRightBar ---> arrow-right-bar
              //IconAlignLeft2 ---> align-left-2
              //IconBadge3dFill ---> badge-3d-fill
              //IconNumber123 ---> number-123
              const newName = name.replace(/([A-Z]|[0-9]+)/g, '-$1').toLowerCase().slice(6)
              // console.log(`${name} ---> ${newName}`);
              return `${whitespace}import ${name} from '@tabler/icons-svelte/icons/${newName}'${hasSemi ? ';' : ''}`
            })
          return imports.join('\n')
        }
      )

      if (ms.hasChanged()) {
        return {
          code: ms.toString(),
          map: ms.generateMap()
        }
      }
    }
  }
}

use this pluin in the vite.config.js

import {tablerSvelteImportOptimizer} from './vite-plugin-optimizer-tabler'
//...other codes

export default defineConfig({
//...other codes
  //Make sure the new component is in front of the web framework (mine is sveltekit)
  plugins: [tablerSvelteImportOptimizer(), sveltekit()],
//...other codes
})
anatoliy-t7 commented 3 weeks ago

@levinit add to regex: 0-9, so icons with numbers can work too IconReceipt2

 const newName = name.replace(/([A-Z0-9])/g, '-$1').toLowerCase().slice(6);
levinit commented 3 weeks ago

@levinit add to regex: 0-9, so icons with numbers can work too IconReceipt2

 const newName = name.replace(/([A-Z0-9])/g, '-$1').toLowerCase().slice(6);

thx, I looked through the list of icons and found that some of the names had two consecutive numbers, e.g., IconNumber123 (convert to number-123) so the new code is:

const newName = name.replace(/([A-Z]|[0-9]+)/g, '-$1').toLowerCase().slice(6)

'IconAlignLeft2'.replace(/([A-Z]|[0-9]+)/g, '-$1').toLowerCase().slice(6) 'align-left-2' 'IconNumber123'.replace(/([A-Z]|[0-9]+)/g, '-$1').toLowerCase().slice(6) 'number-123'