formidable-playbook
Version:
The Formidable Playbook
201 lines (144 loc) • 6.66 kB
Markdown
### Start with good base plugins
Webpack has a rich plugin ecosystem, including both
[core](https://webpack.github.io/docs/list-of-plugins.html) and
[open source](http://nipstr.com/#webpack plugin)
[modules](https://www.npmjs.com/browse/keyword/webpack-plugin) modules.
Webpack also has a straight forward interface to
[write your own plugins](https://webpack.github.io/docs/plugins.html).
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
- [`UglifyJsPlugin`](#uglifyjsplugin)
- [`DedupePlugin`](#dedupeplugin)
- [`OccurrenceOrderPlugin`](#occurrenceorderplugin)
- [`DefinePlugin`](#defineplugin)
- [`lodash-webpack-plugin`](#lodash-webpack-plugin)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
##### [`UglifyJsPlugin`](https://webpack.github.io/docs/list-of-plugins.html#uglifyjsplugin)
* Recommended?: **Yes**
The `UglifyJsPlugin` minimizes code using
[Uglifyjs](https://github.com/mishoo/UglifyJS2) and with most options proxied
through to the plugin.
Typical configuration:
```js
new webpack.optimize.UglifyJsPlugin()
```
##### [`DedupePlugin`](https://webpack.github.io/docs/list-of-plugins.html#dedupeplugin)
* Recommended?: **Yes for `webpack@1`**
Collapse identical code chunks to a single reference. The plugin looks for
identical occurrences of the same code and replaces real code chunks in the
bundle with integer references (think pointers in C/C++) to find an earlier
instance of the same code.
Typical configuration:
```js
new webpack.optimize.DedupePlugin()
```
**Note - npm Deduplication**: This "deduplication" is separate from the
deduplication that `npm` performs while flattening the dependency tree in
`node_modules`. It is just a scan by webpack to coalesce identical code chunks
to a single reference.
<!-- **TODO: inspectpack duplicates reference + note - https://github.com/FormidableLabs/formidable-playbook/issues/2* -->
**Webpack 2+ Note**: This plugin has been removed as of `webpack@2` with a note
that it "isn't needed anymore" because of npm deduplication. Unfortunately, npm
deduplication can often fail where the plugin would yield a smaller bundle.
Hopefully, this plugin will be resurrected by core or the community as a new OSS
project.
##### [`OccurrenceOrderPlugin`](https://webpack.github.io/docs/list-of-plugins.html#occurrenceorderplugin)
* Recommended?: **Maybe for `webpack@1`**
Reorder module / chunk ids by order of most-to-least occurring. This reduces
raw code size since smaller integer indexes are `require`-ed more. Also makes
the order of modules deterministic.
Typical configuration:
```js
new webpack.optimize.OccurrenceOrderPlugin()
```
**Assessment**: The size gains are often not significant, and can make the
ultimate minified + gzipped bundle size actually _larger_. And this calculus
can change over time, so generally speaking size should not be a motivating
factor for enabling this plugin. However, if you need a deterministic ordering
of chunks and modules, this plugin is appropriate.
**Webpack 2+ Note**: Enabled by default now.
##### [`DefinePlugin`](https://webpack.github.io/docs/list-of-plugins.html#defineplugin)
* Recommended?: **Maybe**
Add raw replacement strings for free variables in code. This literally rewrites
your source code with replacements. With a bit of strategy and a project
convention you can opportunistically have code paths removed / variables
replaced for a bespoke optimized production build.
Additionally, many frameworks / tools such as React, expect a definition of
`"process.env.NODE_ENV": JSON.stringify("production")` for the most optimized
build of included code.
Example configuration:
```js
new webpack.optimize.DefinePlugin({
"process.env.NODE_ENV": JSON.stringify("production"), // or "\"production\""
"DEBUG": false // or "false"
})
```
**Note**: to expand a variable to a quoted string, you must use
`JSON.stringify`.
If we had this source:
```js
if (process.env.NODE_ENV === "production") {
console.log("I'm in prod!");
}
if (DEBUG) {
console.log("Explicit debug switch");
}
```
with the above configuration, the output would be:
```js
if ("production" === "production") {
console.log("I'm in prod!");
}
if (false) {
console.log("Explicit debug switch");
}
```
which with minification would become:
```js
console.log("I'm in prod!");
```
##### [`lodash-webpack-plugin`](https://github.com/lodash/lodash-webpack-plugin)
* Recommended?: **Maybe**
If your project uses [lodash](https://lodash.com/) and can handle some limiting
constraints and complexities, this plugin provides some useful optimizations for
reducing code size.
Typically you'll want to already use the
[`babel-plugin-lodash`](https://github.com/lodash/babel-plugin-lodash) which
optimizes some things in a webpack / babel build. This plugin then goes further
by removing lots of internal code, grouped in logical
["feature sets"](https://github.com/lodash/lodash-webpack-plugin#feature-sets)
**Big Warning**: The plugin's only real value is removing internal stuff that
your code **may still depend on**. And it's not always obvious what is getting
removed.
For example, looking to a simple example provided at:
https://github.com/exogen/test-lodash-webpack-plugin we have this starting code:
```js
import get from "lodash/get";
import assert from "assert";
const x = { a: { b: { c: 1 } } };
assert.strictEqual(get(x, "a.b.c"), 1);
```
Using the plugin with no configuration:
```js
new LodashModuleReplacementPlugin()
```
will fail the assertion because the result of `get(x, "a.b.c")` is `undefined`.
The reason is that all deep path traversal code is removed under the hood by
default. Thus to support deep path traversal for the `get()` call, we would
need to configure the plugin like:
```js
new LodashModuleReplacementPlugin({
paths: true
})
```
Thus, this plugin is not really a "fire and forget" thing, but rather a power
tool with very few safeties. You must be familiar with all the of the feature
sets removed, probably need to coordinate re-enabling key ones for your specific
project, and ensure that all lodash usage is tested / complies with the internal
rewriting of the plugin.
For example, after enabling it without configuration in the Victory project,
we later found that we needed several configurations enabled. See:
https://github.com/FormidableLabs/builder-victory-component/pull/64
In short, it's easier to just not add the plugin. But if you need that extra
bit of super-optimized lodash tuning, you can enable the plugin and accept the
complexity cost of it.