# Tree-Shaking

Guide to optimizing Font Awesome usage with tree shaking in JavaScript projects.

> Use tree-shaking to automatically subset and include only the icons you're using.

Make sure you already:

- [Set up access](/apis/javascript.md) to the Javascript API in your project.

Beginning with the excellent tool [Rollup.js](https://rollupjs.org) by Rich Harris, the concept of tree-shaking attempts to eliminate any unused code. Webpack 2 now includes this as well.

## Using Font Awesome with Tree-shaking

The Font Awesome icon packages support tree-shaking out of the box but **only if your tool
is tree-shaking compatible**.

In this example, only `faCoffee` is imported from `free-solid-svg-icons`, so
only that icon will be included in the production optimized bundle:

```js
// Tree-shaking Example
import { faCoffee } from '@fortawesome/free-solid-svg-icons'
```

## Alternative to Tree-shaking: Deep Imports

If your tool does not yet support tree-shaking you can still
benefit from only importing the icons you use by following this example:

```js
// Bullet-proof deep import example
import { faCoffee } from '@fortawesome/free-solid-svg-icons/faCoffee' // <-- note the extra faCoffee there
```

## Known Issues with Tree-shaking

#### Production Mode

Webpack only performs tree-shaking when the [`--mode=production`](https://webpack.js.org/concepts/mode/#mode-production) flag is used. This enables the `UglifyJsPlugin` which performs the
optimization. To nerd out for a second; this plugin is actually doing "dead
code elimination" which is a slower process than the canonical tree-shaking but
the results are similar.

Rollup enables tree-shaking by default but it does so [only with ES modules](https://rollupjs.org/guide/en#tree-shaking). Font Awesome provides ES modules in all of its NPM packages so you should be good-to-go.

#### Slow Build Times with Webpack 4, uglify-es@3 and uglify-js@3

You may experience surprisingly slow build times with Webpack 4, uglify-es@3 and uglify-js@3. For instance, when running a production build with Webpack 4, it might seem to hang for a long time with a status of: `92% chunk asset optimization`. `angular-cli` 6.0 uses Webpack 4 under the hood, as does `vue-cli` 3.0, and perhaps other similar zero-configuration development framework tools.

**Here's more background**: `uglify-es` is a minifier based on `uglify-js`. A minifier can eliminate unused code, and this is how Webpack achieves tree-shaking. It delegates dead code elimination to the minifier used for production bundles. Unfortunately, as of `uglify-es@3.3.x` and `uglify-js@3.3.x`, there's a [significant performance problem](https://github.com/fabiosantoscode/terser/issues/50) in this minifier code base that happens to effect modules that are formatted like our icon packages. Also, the `uglify-es` project has transitioned ownership and been renamed `terser`.

We expect that future releases of Webpack will depend upon `terser` instead of `uglify-es`,
and will include the [performance fix](https://github.com/fabiosantoscode/terser/issues/50) that will make tree-shaking fast again in Webpack 4. In the meantime, if you're facing this problem, there are a few workarounds that you might consider.

**Workaround 1: Use deep imports** - Each icon is available as a submodule in CommonJS format and can be imported like the example below. This avoids tree-shaking entirely.

```js
// Bullet-proof deep import example
import { faCoffee } from '@fortawesome/free-solid-svg-icons/faCoffee' // <-- note the extra faCoffee there
```

**Workaround 2: Switch to Babel Minify** - Configure webpack to use [`babel-minify`](https://github.com/babel/minify) instead of `uglify-es` or `uglifyjs`, like this:

```js
// webpack.config.js

const BabelMinifyPlugin = require('babel-minify-webpack-plugin')
module.exports = {
  // ...
  optimization: {
    minimizer: [new BabelMinifyPlugin()]
  }
}
```

**Workaround 3: Disable collapse_vars** - Stick with `uglify-es` or `uglify-js` 3.x, but configure webpack to disable the [`collapse_vars` compression option](https://github.com/mishoo/UglifyJS2#compress-options). This would impact your whole build, of course, not just the Font Awesome modules.

```js
// Disable collpase_vars
// webpack.config.js

const UglifyWebpackPlugin = require('uglifyjs-webpack-plugin')
module.exports = {
  // ...
  optimization: {
    minimizer: [
      new UglifyWebpackPlugin({
        uglifyOptions: {
          compress: {
            collapse_vars: false
          }
        }
      })
    ]
  }
}
```

#### Zero-configuration tools

If you're using a tool like `angular-cli` that uses Webpack 4 under the hood, it may be necessary to **eject from the tool's configuration management** if you want to make any of the Webpack configuration modifications suggested above.

If ejecting is too undesirable, then your best options are probably to either downgrade
to a version of that tool set that uses Webpack 3 until the fix for this performance regression is available, or switch to using deep imports as described above until the fix is available.
