react-icons / react-icons

svg react icons of popular icon packs
https://react-icons.github.io/react-icons/
Other
11.57k stars 750 forks source link

React Icons Imports everything even when included 2 or 3 icons #154

Closed sandeepreddy19 closed 3 years ago

sandeepreddy19 commented 6 years ago

I had imported below icons in Create React App and I see that it included the whole library in the bundle. Attached is a screenshot. How do we get around this?

import { FaBarChart, FaDatabase, FaMinus, FaPlus, FaStickyNote } from 'react-icons/lib/fa' import { IoChatboxWorking } from 'react-icons/lib/io'

screen shot 2018-07-19 at 9 58 14 am

JaccoGoris commented 6 years ago

I have the same issue image

sandeepreddy19 commented 6 years ago

@JaccoGoris Did you find any fix for this issue?

JaccoGoris commented 6 years ago

@sandeepreddy19 I found a fix by switching to 3.0.0-Beta1 and including icons like this: import { MdPublic } from 'react-icons/md/index.mjs'; which resulted in correct threeshaking. the downside is that my build time went from 3 seconds to 225 seconds.. (3.75min) so.. 75x slower when using this method with md icons. Then, when I also used some fa icons too, it went up to 279 seconds (93x). But at least my bundle size went from 1MB to 270kb 😄

JaccoGoris commented 6 years ago

@sandeepreddy19 I just figured out how to set it up correctly with 2.2.7 unfortunately you have to import them all separately from the lib files, like this:

import FaFacebookSquare from 'react-icons/lib/fa/facebook-square';
import FaLinkedin from 'react-icons/lib/fa/linkedin';
import FaTwitter from 'react-icons/lib/fa/twitter';
import FaPinterest from 'react-icons/lib/fa/pinterest-square';
import FaInstagram from 'react-icons/lib/fa/instagram';

instead of like this:

import {
    FaFacebookSquare,
    FaLinkedin,
    FaTwitter,
    FaPinterest,
    FaInstagram
} from 'react-icons/lib/fa';

which would have been a lot nicer. But I got only the icons I need now and a build time of 5 seconds! So probably we need to fix the code or fix the docs

antoinerousseau commented 6 years ago

Should be better in 3.x with #141

abramobagnara commented 6 years ago

I have the same problem with react-icons 3.0.1

wopian commented 6 years ago

141 doesn't seem to have had any effect on size. 2.2.7 with the old format was 6kb for 5 icons. Upgrading to 3.0.1 and migrating to import { <icon> } from 'react-icons/md' is now 350kb

import MdGroup from 'react-icons/lib/md/group'
import MdFavorite from 'react-icons/lib/md/favorite'
import MdStar from 'react-icons/lib/md/star'
import MdThumbsUpDown from 'react-icons/lib/md/thumbs-up-down'
import MdLocalLibrary from 'react-icons/lib/md/local-library'

vs

import { MdGroup, MdFavorite, MdStar, MdThumbsUpDown, MdLocalLibrary } from 'react-icons/md'
antoinerousseau commented 6 years ago

@kamijin-fanta any insight?

kamijin-fanta commented 6 years ago

@wopian Please tell me the version of webpack. I verified with webpack@3.8.1 / webpack@4.5.0.

If upgrade has no effect, please provide webpack.config.js.

wopian commented 6 years ago

@kamijin-fanta 4.16.3

Config: https://github.com/wopian/kitsu-season-trends/blob/master/webpack.production.config.js

sandeepreddy19 commented 6 years ago

@kamijin-fanta I am using the default webpack config provided by Create-React-App

kamijin-fanta commented 6 years ago

@wopian I saw the configuration easily.

for additional debugging please submit the minimum project configuration.

kamijin-fanta commented 6 years ago

@sandeepreddy19 I verified with react-script@1.1.4. see: https://github.com/react-icons/react-icons/tree/master/packages/demo

please upload the smallest project including bug.

wopian commented 6 years ago

Back down to 2kb (5 icons) after those changes 👍

antoinerousseau commented 6 years ago

@kamijin-fanta many people use create-react-app without ejecting (see webpack default prod config). it would be nice if the new 3.x version would work out-of-the-box with that small footprint for those users. is that the case?

kamijin-fanta commented 6 years ago

@antoinerousseau the size of the demo project is 37.84 KB in production build. use three types of icon library: FaFolder, MdAccessibility, TiArrowDown. not ejected.

demo project: https://github.com/react-icons/react-icons/tree/master/packages/demo

markusenglund commented 6 years ago

@kamijin-fanta I think the new build structure in 3.0 is pretty bad.

  1. In normal webpack setups (including creacte-react-app) it will cause a HUGE bundle size footprint, and some people won't have enough knowledge to realize what the problem is / how to fix it.
  2. The solution you propose is kind of hacky since it's based on the order of the extensions. So ['.mjs', '.js', '.jsx'] works, but ['.js', '.mjs', '.jsx'] does not.
  3. Since the solution is based on es modules, I believe it will not work at all in webpack 1.x (?)
  4. Even with the solution, the bundle size foot print is STILL bigger than before. Upgrading from 2.2 to 3.0 caused my bundle size to expand by 0.5 kb gzipped (+3.6 kb not gzipped). (The project used five different icons from fa)

All in all, a pretty big regression from 2.2. To fix it, I would start by renaming the .mjs file to index.esm.js or something like that and put a package.json file inside the fa-folder (and other such folders) and include "module": "index.esm.js" inside the file. This should cause webpack to find the right file by default.

kamijin-fanta commented 6 years ago

@markusenglund thanks for the good feedback.

about 3, 4 you are right. part 1 and 2 are also correct. project should prepare troubleshooting guide.

projects created with creacte-react-app should normally resolve .mjs first. In versions older than 1.0.15, the bundle size appears to be large. ref: https://github.com/facebook/create-react-app/blob/v1.1.4/packages/react-scripts/config/webpack.config.dev.js#L93

the default setting of the latest webpack resolves .mjs first. https://webpack.js.org/configuration/resolve/#resolve-extensions

I think that problems are occurring when using old packages or wrong config overrides. The first problem is temporary.

markusenglund commented 6 years ago

Ah ok. Number 2. was kind of a nonsensical criticism then.

Still, I think we should strive to build npm packages that work great out of the box for everyone. The setup for this package is right now pretty atypical, so it's not surprising that some projects don't have their build tools properly set up for it.

curran commented 6 years ago

I encountered this issue while using Next.js with default configuration.

Adding '.mjs' in the Webpack config (via next.config.js) solved the problem:

  webpack: config => {
    config.resolve.extensions = [ '.mjs', '.js', '.jsx', '.json' ];
curran commented 6 years ago

Suggestion: Since this will be a common issue encountered for newcomers, it may be nice to link to this issue in the README where the ES6 imports are recommended. Something like this:

Ending up with a large JS bundle? Check out this issue.

Thoughts?

SpicyPete commented 6 years ago

Getting this issue with Gatsby v2.
There's a way to modify it's webpack. If I find a solution I'll update it here

elramus commented 6 years ago

I'm having this issue using Laravel Mix's webpack config. I'm using just one icon and it's adding the entire font awesome library. I'd like to try your solution, @kamijin-fanta, but I'm not really sure how to go about it.

Mix lets you add webpack customizations like so:

mix.webpackConfig({
  plugins: [
    new BundleAnalyzerPlugin()
  ]
})

to which I added:

mix.webpackConfig({
  plugins: [
    new BundleAnalyzerPlugin()
  ],
  resolve: {
    extensions: [ '.mjs', '.js', '.jsx', '.json' ]
  }
})

but that didn't seem to fix it. I'm a bit of a webpack noob, so any pointers would be great. FWIW, I'm importing the icon like so: import { FaCamera } from 'react-icons/fa', and react-icon's index.js is coming out gzipped at 247k.

Thanks.

Stalinko commented 6 years ago

I have the same problem as @elramus Standard installation of Laravel Mix with ReactJS 16.5 Installed latest React-Icons (3.1.0) and imported 3 icons + IconContext:

import { IconContext } from 'react-icons'
import { GoCalendar } from 'react-icons/go'
import { FaRegClock } from 'react-icons/fa'
import { FaMapMarkerAlt } from 'react-icons/fa'

And my compiled JS grew up by 900kb !

Solutions mentioned here don't help :( was anybody able to make it work properly with Laravel Mix ?

elramus commented 6 years ago

@Stalinko I ended up switching over to React FontAwesome, because React Icons only carries a subset of FontAwesome's icons. Had a tree-shaking issue there too actually, but was able to resolve and it works great now.

antoinerousseau commented 6 years ago

.mjs is now being abandoned anyway: https://github.com/facebook/create-react-app/issues/5103

JaccoGoris commented 6 years ago

won't this create issues then with the current setup?

catchergeese commented 6 years ago

Are there any plans to get compatibility with create-react-app (2.x) back on track?

kamijin-fanta commented 6 years ago

What should I do to obtain compatibility?

I am considering changing the extension. Tools such as Jest do not support to ES Modules, so need to deal with both ...

jptissot commented 6 years ago

Looks like they added .mjs support back !! https://github.com/facebook/create-react-app/releases/tag/v2.0.4

jgidlow commented 6 years ago

I'm currently using TypeScript with a target version of es5 and because of this tree shaking is not working with Webpack since it relies on the es6 module syntax. With 3.x of React Icons this leads to the entire icon library to be included in my output bundle.

The only workaround I've found for this problem is to declare all the icons I'm using in my own module that I then use instead of importing the icons directly from the library. Something like this:

import { GenIcon, IconBaseProps } from 'react-icons/lib/iconBase';

export function MdPriorityHigh(props: IconBaseProps): JSX.Element {
  return GenIcon({'tag':'svg','attr':{'viewBox':'0 0 24 24'},'child':[{'tag':'circle','attr':{'cx':'12','cy':'19','r':'2'}},{'tag':'path','attr':{'d':'M10 3h4v12h-4z'}}]} as any)(props);
}

Does anyone know if there's a better way of doing this? Is there any way to just import a single icon with require like there was in 2.x?

marlonbaeten commented 5 years ago

When building with parcel (v1.10.3) instead of webpack, react-icons is included completely, resulting in a huge bundle size.

There is no option is parcel to change the extension resolve order. I think js has precedence over mjs.

Is anyone experiencing the same problem? Or could someone give any hints on how to solve this problem?

kamijin-fanta commented 5 years ago

@marlonbaeten It might be solved with the this code...

import { FaBeer } from 'react-icons/fa/index.mjs';

but, It is not good-looking.

wopian commented 5 years ago

@marlonbaeten there is an open issue tracking that problem 👌 https://github.com/parcel-bundler/parcel/issues/2238

luke-schleicher commented 5 years ago

@jgidlow

I'm a bit late to the tree shaking party here but I thought I'd leave a potential solution for others to see.

I'm also using TypeScript with a target of es5, with react-icons 3.2.2, and I have tree shaking working properly with webpack.

What worked for me was setting "module" to "es6" in my tsconfig.json. I had it set to "commonjs" before. If that's an option for you, tree shaking should work.

tsconfig.json


{
  ...
  "compilerOptions": {
    ...
    "module": "es6"
    ....
  }
}
antoinerousseau commented 5 years ago

so, shall we keep .mjs or shall we make a more universally compatible v4 of this lib?

schoenwaldnils commented 5 years ago

universally compatible sounds good 👍

Nantris commented 5 years ago
import { FaTimes } from 'react-icons/fa/index.mjs';

Results in the error: Can't import the named export 'GenIcon' from non EcmaScript module (only default export is available)

Edit: This comment helped me avoid the error: https://github.com/react-icons/react-icons/issues/193#issuecomment-428871071

mwmcode commented 5 years ago
import { FaTimes } from 'react-icons/fa/index.mjs';

doesn't seem to work :\

// webpack.config.js...
extensions: ['.mjs', '.web.js', '.js', '.json', '.web.jsx', '.jsx'],
alias: {
        shared: resolve(__dirname, 'src/shared'),
}....

Error:

Unexpected use of file extension "mjs" for "react-icons/fa/index.mjs"  import/extensions

"react-icons": "^3.3.0", "webpack": "^4.23.1",

jquense commented 5 years ago

can we please go back to being able to cherry-pick? relying on treeshaking is haphazard and inconsistent. It's an optimization not something that we should be relying on as the main strategy for including what we use. Not to mention that mjs support is very inconsistent and it's implementation and behavior is still actively changing in tools

Nantris commented 5 years ago

@mustafawm can you copy your entire Webpack config into a Gist?

Also, it looks like I used this code in the end along with the Webpack changes: import { FaTimes } from 'react-icons/fa'; - There's a pretty good chance that should work.

mwmcode commented 5 years ago

Hi @Slapbox, here it is https://gist.github.com/mustafawm/45e37b8d137fb09d10d3ccb51a609f70

Could it be the same webpack issue that fontawesome-react has? https://fontawesome.com/how-to-use/with-the-api/other/tree-shaking#issues

I switched to fontawesome which ironically had the same issue, but the workaround suggested in the link above worked.

Nantris commented 5 years ago

@mustafawm did you get it working? I'm not entirely clear since that last bit is in a blockquote. If so which workaround on that page helped you? Point 1, Using deep imports?

My Webpack config looks very similar, but I've got this line which may make a difference:

resolve: {
    extensions: ['.mjs', '.js', '.jsx', '.json'],
    modules: [cwd, 'node_modules'], // This line might be necessary, but I think this is probably unrelated
  },
mwmcode commented 5 years ago

I got fontawesome to work (by deep importing each icon)

Will try your suggestion and get back to you

mwmcode commented 5 years ago

@Slapbox no success, still importing the whole thing! (even with importing from index.mjs)

PS: in your webpack config you have cwd as a variable!? Webpack complains as it only expects strings in its resolve.modules array so I changed it to 'cwd'

Nantris commented 5 years ago

@mustafawm sorry! Instead of cwd use process.cwd() - doubt it helps, but that's what I should have said in the first place.

mwmcode commented 5 years ago

Tried that as well, still didn't work!

✖ 「wds」: Invalid configuration object. Webpack has been initialised using a configuration object that does not match the API schema.
 - configuration.resolve.modules[0] should be a string.
   -> A non-empty string

You should get the same error if you're running the same webpack v

"webpack": "^4.23.1",

Nantris commented 5 years ago

@mustafawm I'm on 4.28.3 in case that makes any difference. Still though, process.cwd() should be a non-empty string, so I'm not sure why you'd be seeing that error. If you console.log(process.cwd()) at the top of your configuration what's that spit out?

Crizzooo commented 5 years ago

This thread has many different things going on.

What is the best way to import and cherry pick specific icons on the current version without growing your bundle size by basically importing the entire libraries?

Nantris commented 5 years ago

@Crizzooo the entire thread is just trying to accomplish that. Wish it was as easy as telling you the best way. Have you tried the recommendations found above? There's at least 3 different methods to try if I recall. The one I posted works for me.