react-fontawesome icon indicating copy to clipboard operation
react-fontawesome copied to clipboard

How does explicit import work with tree shacking?

Open Vadorequest opened this issue 4 years ago • 10 comments

Per your doc:

import ReactDOM from 'react-dom'
import { library } from '@fortawesome/fontawesome-svg-core'
import { fab } from '@fortawesome/free-brands-svg-icons'
import { faCheckSquare, faCoffee } from '@fortawesome/free-solid-svg-icons'

library.add(fab, faCheckSquare, faCoffee)

fab contains all the font-awesome brand icons. Does that mean they'll be loaded by the browser even if they're not actually used?

I'm working with Next.js and I'm currently naming all icons one by one and it's cumbersome, and I wish to import all icons and kinda hope tree shacking will remove those that aren't actually used.

Vadorequest avatar Sep 22 '20 13:09 Vadorequest

Tree-shaking isn't quite this smart. It doesn't know if you are dynamically using an icon.

Right now we don't have anything better than just importing the icons individually. It's a pain, but that's the cost of keeping the bundle size small at the moment. We've got plans for helping with this in the future.

robmadole avatar Oct 26 '20 14:10 robmadole

Thanks for confirming, that's what I assumed and I'll keep on importing them one by one until a better alternative comes to light!

Vadorequest avatar Oct 26 '20 14:10 Vadorequest

Hmm I'm noticing my bundle is huge due to font awesome. It seems the entire lib is importing even though I'm only importing a few dozen icons using the explicit method. Any guidance on how to troubleshoot why the tree shaking might now be working? This is in a CRA boilerplate app using react-scripts for the build process.

jimjeffers avatar Nov 02 '20 02:11 jimjeffers

Are you talking about the production or development build? Because it seems optimizations happens only for the production build.

Vadorequest avatar Nov 02 '20 08:11 Vadorequest

@jimjeffers also, please look at the actual file size (not the web pack analyzer) for the production build. We've seen instances where the analyzer reports larger file sizes than what is really there.

robmadole avatar Nov 02 '20 16:11 robmadole

Thanks for getting back to me. I could adjust the project to use deep imports if I have to that just seems like a big hassle so hopefully I can figure out the cause of this. Also for reference this is a mono-repo that has two packages that CRA SPAs.

Right here is the output after running:

NODE_ENV=production yarn build

yarn workspace v1.22.5 yarn run v1.22.5 $ react-scripts build Creating an optimized production build...

File sizes after gzip:

1.69 MB build/static/js/2.8f24654d.chunk.js 55.47 KB build/static/js/main.9f461445.chunk.js 41.39 KB build/static/js/3.39ba6be8.chunk.js 21.57 KB build/static/js/4.e2b6951c.chunk.js 4.35 KB build/static/css/main.5aa5159a.chunk.css 2.81 KB build/static/css/2.19b7558e.chunk.css 1.2 KB build/static/js/runtime-main.97381a6e.js 195 B build/static/js/5.3a6c9a11.chunk.js 195 B build/static/js/6.e5073874.chunk.js

I'm using Node 12.18.4 and here's my package.json:

{
  "name": "web-client",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@apollo/client": "^3.2.1",
    "@babel/runtime": "^7.7.2",
    "@fortawesome/fontawesome-svg-core": "^1.2.20",
    "@fortawesome/pro-light-svg-icons": "^5.10.0",
    "@fortawesome/pro-regular-svg-icons": "^5.10.0",
    "@fortawesome/pro-solid-svg-icons": "^5.10.0",
    "@fortawesome/react-fontawesome": "^0.1.4",
    "@hookform/resolvers": "^1.0.0",
    "@sentry/browser": "^5.10.2",
    "@sentry/react": "^5.25.0",
    "@sentry/tracing": "^5.25.0",
    "graphql": "^15.3.0",
    "graphql-tag": "^2.10.1",
    "hsportal-schema": "1.0.0",
    "luxon": "^1.17.2",
    "react": "^16.13.1",
    "react-dnd": "^11.1.3",
    "react-dnd-html5-backend": "^11.1.3",
    "react-dom": "^16.13.1",
    "react-ga": "^2.7.0",
    "react-google-recaptcha": "^1.1.0",
    "react-helmet": "^5.2.1",
    "react-hook-form": "^6.9.6",
    "react-redux": "^7.1.0",
    "react-router": "5.1.2",
    "react-router-dom": "5.1.2",
    "react-scripts": "3.4.3",
    "session": "1.0.0",
    "typescript": "~3.7.2",
    "ui": "1.0.0",
    "utils": "1.0.0",
    "uuid": "^3.3.2",
    "validations": "1.0.0",
    "validator": "^11.1.0",
    "yup": "^0.27.0"
  },
  "devDependencies": {
    "@graphql-codegen/cli": "^1.13.2",
    "@graphql-codegen/fragment-matcher": "^1.13.2",
    "@graphql-codegen/introspection": "^1.13.2",
    "@graphql-codegen/typescript": "^1.13.2",
    "@graphql-codegen/typescript-operations": "^1.13.2",
    "@graphql-codegen/typescript-react-apollo": "^1.13.2",
    "@testing-library/jest-dom": "^4.2.4",
    "@testing-library/react": "^9.3.2",
    "@testing-library/user-event": "^7.1.2",
    "@types/draft-js": "^0.10.38",
    "@types/draftjs-to-html": "^0.8.0",
    "@types/graphql": "^14.2.3",
    "@types/humps": "^1.1.2",
    "@types/jest": "^24.0.0",
    "@types/jwt-decode": "^2.2.1",
    "@types/luxon": "^1.15.2",
    "@types/node": "^12.0.0",
    "@types/react": "^16.9.0",
    "@types/react-dom": "^16.9.0",
    "@types/react-helmet": "^5.0.8",
    "@types/react-redux": "^7.1.1",
    "@types/react-router": "^5.1.2",
    "@types/react-router-dom": "^5.1.0",
    "@types/react-text-mask": "^5.4.6",
    "@types/redux": "^3.6.0",
    "@types/uuid": "^3.4.5",
    "@types/yup": "^0.26.22",
    "prettier": "^2.1.2"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject",
    "deploy": "yarn build && sls deploy client",
    "prettier": "prettier --config ../../.prettierrc 'src/**/*.{ts,tsx}' --write"
  },
  "eslintConfig": {
    "extends": "react-app"
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}

But running ls -lh returns the following:

jimjeffers@Jims-iMac mcss % ls -lh packages/web-client/build/static/js
total 34736
-rw-r--r--  1 jimjeffers  staff   5.5M Nov  4 10:14 2.8f24654d.chunk.js
-rw-r--r--  1 jimjeffers  staff   2.2K Nov  4 10:14 2.8f24654d.chunk.js.LICENSE.txt
-rw-r--r--  1 jimjeffers  staff   8.9M Nov  4 10:14 2.8f24654d.chunk.js.map
-rw-r--r--  1 jimjeffers  staff   142K Nov  4 10:14 3.39ba6be8.chunk.js
-rw-r--r--  1 jimjeffers  staff   808B Nov  4 10:14 3.39ba6be8.chunk.js.LICENSE.txt
-rw-r--r--  1 jimjeffers  staff   620K Nov  4 10:14 3.39ba6be8.chunk.js.map
-rw-r--r--  1 jimjeffers  staff   106K Nov  4 10:14 4.e2b6951c.chunk.js
-rw-r--r--  1 jimjeffers  staff   275K Nov  4 10:14 4.e2b6951c.chunk.js.map
-rw-r--r--  1 jimjeffers  staff   233B Nov  4 10:14 5.3a6c9a11.chunk.js
-rw-r--r--  1 jimjeffers  staff   203B Nov  4 10:14 5.3a6c9a11.chunk.js.map
-rw-r--r--  1 jimjeffers  staff   233B Nov  4 10:14 6.e5073874.chunk.js
-rw-r--r--  1 jimjeffers  staff   209B Nov  4 10:14 6.e5073874.chunk.js.map
-rw-r--r--  1 jimjeffers  staff   391K Nov  4 10:14 main.9f461445.chunk.js
-rw-r--r--  1 jimjeffers  staff   1.0M Nov  4 10:14 main.9f461445.chunk.js.map
-rw-r--r--  1 jimjeffers  staff   2.4K Nov  4 10:14 runtime-main.97381a6e.js
-rw-r--r--  1 jimjeffers  staff    12K Nov  4 10:14 runtime-main.97381a6e.js.map

And here's a screenshot of that large bundle after running:

source-map-explorer 'build/static/js/*.js'

Screen Shot 2020-11-04 at 10 24 01 AM

jimjeffers avatar Nov 04 '20 18:11 jimjeffers

Also worth noting is that the CRA projects are importing a ui package which as a library of shared components and this package also uses font-awesome/react-fonteawsome. Perhaps that is why the tree shaking might not be working as usual?

Just to be sure I found the other chunk where our UI package exists in the build. Doesn't seem that font awesome was duped because of the monorepo but maybe it's still possible:

Screen Shot 2020-11-04 at 10 33 19 AM

jimjeffers avatar Nov 04 '20 18:11 jimjeffers

Just following up on this one guys. It turns out the other packages in my monorepo were compiling with "CommonJS" which doesn't support tree shaking. I changed the "module" setting to "es6" and my issue went away! I recommend pointing people to webpack's docs on tree shaking -- specifically scroll down to the conclusion section which provides a good checklist:

https://webpack.js.org/guides/tree-shaking/

Screen Shot 2020-12-19 at 10 07 23 AM

jimjeffers avatar Dec 19 '20 18:12 jimjeffers

@jimjeffers what did you change exactly to make sure only the FA icons are included that you are using in CRA?

thijssmudde avatar Jul 29 '22 09:07 thijssmudde

@fullhdpixel I just set the "module" attribute in my tsconfig.json to compile my sibling packages as ES6 instead of commonJS. It's been a few years so your mileage may vary with modern projects and FA6. But in my case I was compiling the packages in my monorepo as commonJS so that my jest tests wouldn't complain about transpiling dependencies. Webpack can't perform tree shaking on anything compiled in CommonJS.

jimjeffers avatar Jul 29 '22 16:07 jimjeffers