FortAwesome / Font-Awesome

The iconic SVG, font, and CSS toolkit
https://fontawesome.com
Other
73.72k stars 12.19k forks source link

Full index.es.js included in React/Webpack bundle #16101

Open riha opened 4 years ago

riha commented 4 years ago

I have a simple React, Typescript project with an import of one icon. I do however end up with the full index.es.js file in the bundle ...

Is it obvious for someone what I'm doing wrong here to get the Tree Shaking to work? 😯

component.tsx

import { faPlusSquare } from "@fortawesome/free-solid-svg-icons"; 
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import React from "react";

export class ButtonRow extends React.Component {
    render() {
        return (<FontAwesomeIcon icon={faPlusSquare} />);
    }
}

webpack.config.js

{
    "mode": "production",
    "entry": "./src/App.tsx",
    "output": { "filename": "bundle.js", "path": "C:\\mypath\\dist", "publicPath": "/" },
    "resolve": { "extensions": [".ts", ".tsx", ".js", ".json"] },
    "module": {
        "rules": [
            { "test": {}, "loader": "awesome-typescript-loader", "options": { "configFileName": "./tsconfig.json" } },
            {
                "test": {},
                "use": [{ "loader": "style-loader" }, { "loader": "css-loader" }, { "loader": "less-loader" }]
            }
        ]
    },
    "plugins": [
        {
            "options": {
                "template": "index.html",
                "filename": "index.html",
                "hash": true,
                "inject": true,
                "compile": true,
                "favicon": false,
                "minify": false,
                "cache": true,
                "showErrors": true,
                "chunks": "all",
                "excludeChunks": [],
                "chunksSortMode": "auto",
                "meta": {},
                "title": "MyApp",
                "xhtml": false
            }
        },
        {
            "opts": {
                "analyzerMode": "server",
                "analyzerHost": "127.0.0.1",
                "reportFilename": "report.html",
                "defaultSizes": "parsed",
                "openAnalyzer": true,
                "generateStatsFile": false,
                "statsFilename": "stats.json",
                "statsOptions": null,
                "excludeAssets": null,
                "logLevel": "info",
                "startAnalyzer": true,
                "analyzerPort": 8888
            },
            "server": null,
            "logger": { "activeLevels": {} }
        }
    ]
}

package.json

{
    "name": "theapp",
    "version": "1.0.0",
    "description": "",
    "main": "index.js",
    "scripts": {
        "start": "webpack-dev-server --env.dev --config ./webpack.config.js",
        "build": "webpack --env.prod --config ./webpack.config.js",
        "build:dev": "webpack --env.dev --config ./webpack.config.js",
        "build:analyze": "webpack --env.analyze --config ./webpack.config.js"
    },
    "repository": {
        "type": "git",
        "url": "git+https://theapp.git"
    },
    "author": "",
    "license": "ISC",
    "bugs": {
        "url": "https://theapp/issues"
    },
    "homepage": "https://theapp#readme",
    "dependencies": {
        "react": "^16.12.0",
        "react-dom": "^16.12.0",
        "react-router-dom": "^5.1.2"
    },
    "devDependencies": {
        "@fortawesome/fontawesome-svg-core": "^1.2.26",
        "@fortawesome/free-solid-svg-icons": "^5.12.0",
        "@fortawesome/react-fontawesome": "^0.1.8",
        "@types/memoize-one": "^5.1.2",
        "@types/react-dom": "^16.9.4",
        "@types/react-router-dom": "^5.1.3",
        "awesome-typescript-loader": "^5.2.1",
        "css-loader": "^3.4.2",
        "html-webpack-plugin": "^3.2.0",
        "less": "^3.10.3",
        "less-loader": "^5.0.0",
        "path": "^0.12.7",
        "prettier": "^1.19.1",
        "style-loader": "^1.1.3",
        "tslint": "^5.20.1",
        "tslint-config-prettier": "^1.18.0",
        "tslint-plugin-prettier": "^2.1.0",
        "tslint-react": "^4.1.0",
        "typescript": "^3.7.5",
        "webpack": "^4.41.5",
        "webpack-bundle-analyzer": "^3.6.0",
        "webpack-cli": "^3.3.10",
        "webpack-dev-server": "^3.10.1"
    }
}
tagliala commented 4 years ago

Hi!

Thanks for being part of the Font Awesome Community.

Sorry, cannot help.

Leaving this open for feedback from the community

master-elodin commented 4 years ago

I'm having the exact same issue. None of the solutions I've found online have helped, like using import {faSignInAlt} from '@fortawesome/free-solid-svg-icons/faSignInAlt'; instead of import {faSignInAlt} from '@fortawesome/free-solid-svg-icons';

wegry commented 4 years ago

It looks like https://github.com/FortAwesome/Font-Awesome/blob/master/js-packages/%40fortawesome/free-regular-svg-icons/index.es.js#L766 is a map that holds on to references from every other icon. I'm not sure webpack@5 pretty sure can't optimize this out because the map could be side effectful. Adding "sideEffects": false to the package.jsons might be enough though. https://webpack.js.org/configuration/optimization/#optimizationsideeffects

tagliala commented 4 years ago

Hi, we already have sideEffects: false in package.json

Ref: https://github.com/FortAwesome/Font-Awesome/blob/master/js-packages/%40fortawesome/free-regular-svg-icons/package.json#L59

wegry commented 4 years ago

@tagliala I can't seem to find where a mapping would force webpack@5 to hold onto all of @fortawesome/free-solid-svg-icons. I did see that @fortawesome/react-fontawesome allows strings to be used for icons (which hints at a mapping). @fortawesome/fontawesome-svg-core/index.es.js's two used exports (icon and parse) don't ever reference an external map from what I can tell, so I don't think they'd be responsible.

The following code

import ReactDOM from 'react-dom'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faCoffee } from '@fortawesome/free-solid-svg-icons'

const element = <FontAwesomeIcon icon={faCoffee} />

ReactDOM.render(element, document.body)

with Webpack 5 stats set to

module.exports = {
  module: {
    rules: [
      {
        test: /\.m?js$/,
        exclude: /(node_modules|bower_components)/,
        use: {
          loader: 'babel-loader',
        },
      },
    ],
  },
  stats: {
    logging: 'verbose',
    moduleTrace: true,
    orphanModules: true,
    usedExports: true,
  },
}

Shows the chain of...

  ./node_modules/@fortawesome/react-fontawesome/index.es.js 10.8 KiB [orphan] [built]
    [only some exports used: FontAwesomeIcon]
  ./node_modules/@fortawesome/fontawesome-svg-core/index.es.js 76.7 KiB [orphan] [built]
    [only some exports used: icon, parse]
  ./node_modules/@fortawesome/free-solid-svg-icons/index.es.js 695 KiB [orphan] [built]
    [only some exports used: faCoffee]

edit it looks like the stats output of webpack (695 KiB) for @fortawesome/free-solid-svg-icons is the parsed size of the library. Looking at the bundle output, there are no icons but the requested coffee icon in the bundle. I think this ticket can probably be closed.

tagliala commented 4 years ago

@wegry thanks for the heads-up

edit it looks like the stats output of webpack (695 KiB) for @fortawesome/free-solid-svg-icons is the parsed size of the library. Looking at the bundle output, there are no icons but the requested coffee icon in the bundle. I think this ticket can probably be closed.

I remember some comments by Rob to check the actual size of the bundle in another issue related to tree-shanking: https://github.com/FortAwesome/Font-Awesome/issues/16005#issuecomment-610412303

jsodeman commented 2 years ago

I thought I was seeing the same issue, but it turned out to be a the wrong source maps option in webpack.

AlonsoK28 commented 1 year ago

I thought I was seeing the same issue, but it turned out to be a the wrong source maps option in webpack.

Can you post the solution?

jsodeman commented 1 year ago

@AlonsoK28

It might have been specific to my app, but here's the change I made

image

Basically removing the source map from production

AlonsoK28 commented 1 year ago

It might have been specific to my app, but here's the change I made

please provide your webpack config file