- Notifications
You must be signed in to change notification settings - Fork112
Using a library in your webpack project? Here’s how to optimize it
License
GoogleChromeLabs/webpack-libs-optimizations
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
Using a library in your webpack project? Use these tips to make your bundle smaller!
Want to add a tip? Seethe contribution guide and make a pull request!
Contents:
async
async-es
babel-polyfill
core-js
date-fns
handlebars
lodash
lodash-es
moment
moment-timezone
react
ractive
reactstrap
react-bootstrap
react-router
styled-components
whatwg-fetch
- Solutions that work with multiple libraries
async
is a collection of utilities for working with async functions.npm package
Generally, you should usetheasync-es
package ⤵ instead. It ships with ES modules and is more optimized for bundling with webpack.
Still, even if prefer to useasync
, for the list of optimizations, seetheasync-es
section ⤵.
async-es
is a collection of utilities for working with async functions. It’s the same package asasync
⤴, but it’s more optimized for bundling with webpack.npm package
✅ Safe to use by default / How to enable is ↓ / Added by@iamakulov
If you useasync-es
as a single import, you’re bundling the whole library into the application – even if you only use a couple of its methods:
// You only use `async.map`, but the whole library gets bundledimportasyncfrom'async-es';async.map(['file1','file2','file3'],fs.stat,function(err,results){console.log(results);});
Usebabel-plugin-lodash
to pick only thoseasync-es
methods you need:
// Before Babel is appliedimportasyncfrom'async-es';async.map(['file1','file2','file3'],fs.stat,function(err,results){console.log(results);});↓// After Babel is appliedimport_mapfrom'async-es/map';_map(['file1','file2','file3'],fs.stat,function(err,results){console.log(results);});
Enable this plugin as follows:
// .babelrc{"plugins": [["lodash", {"id": ["async-es"] }]],}
babel-polyfill
is a Babel’s package that loadscore-js
and a custom regenerator runtime.Babel docs ·npm package
For the list of optimizations, seethecore-js
section ⤵.
core-js
is a set of polyfills for ES5 and ES2015+.npm package
✅ Safe to use by default /How to enable / Added by@iamakulov
If you compile your code with Babel andbabel-preset-env
, addtheuseBuiltIns: true
option. This option configures Babel to only include polyfills that are necessary for target browsers. I.e., if you target your app to support Internet Explorer 11:
// .babelrc{"presets": [ ["env", {"targets": {"browsers": ["last 2 versions","ie >= 11"] } } ] ]}
enablinguseBuiltIns: true
will remove polyfills for all features that Internet Explorer 11 already supports (such asObject.create
,Object.keys
and so on).
✅ Safe to use by default /How to enable / Added by@iamakulov
All browsers that support<script type="module">
also support modern JS features likeasync
/await
, arrow functions and classes. Use this feature to build two versions of the bundle and make modern browsers load only the modern code. For the guide, seethe Philip Walton’s article.
date-fns is a date utility library.npm package
✅ Safe to use by default /How to enable / Added by@chentsulin
babel-plugin-date-fns
replaces full imports of date-fns with imports of specific date-fns functions:
import{format}from'date-fns';format(newDate(2014,1,11),'MM/DD/YYYY');
↓
import_formatfrom'date-fns/format';_format(newDate(2014,1,11),'MM/DD/YYYY');
Handlebars is a templating library.npm package
⚠ Use with caution / How to enable is ↓ / Added by@danburzo
If you useHandlebars.compile()
to compile templates in your app, switch tohandlebars-loader
. This way, you’ll compile templates during a webpack build – and won’t need to bundle the template-parsing part of the library.
Here’s how to avoid bundling the template-parsing part of Handlebars:
- Switch to
handlebars-loader
, if you haven’t yet - And either:
replace all
import Handlebars from 'handlebars'
withimport Handlebars from 'handlebars/runtime'
or alias the module using
resolve.alias
:// webpack.config.js{// ...resolve:{alias:{// Tip: `$` in the end of `handlebars$` means “exact match”: https://webpack.js.org/configuration/resolve/#resolvealias// This’d disable aliasing – and prevent breaking the code – for imports like `handlebars/something.js`handlebars$:path.resolve(__dirname,'node_modules/handlebars/runtime.js')}}// ...}
Use this optimization with caution. Make sure your code does not useHandlebars.compile()
anywhere, or your app will break.
Lodash is an utility library.npm package
✅ Safe to use by default /How to enable / Added by@iamakulov
babel-plugin-lodash
replaces full imports of Lodash with imports of specific Lodash functions:
import_from'lodash';_.map([1,2,3],i=>i+1);
↓
import_mapfrom'lodash/map';_map([1,2,3],i=>i+1);
Note: the plugin doesn’t work with chain sequences – i.e. code like
_([1,2,3]).map(i=>i+1).value();
won’t be optimized.
✅ Safe to use by default / How to enable is ↓ / Added by@7rulnik
Some of your dependencies might usethelodash-es
package instead oflodash
. If that’s the case, Lodash will be bundled twice.
To avoid this, alias thelodash-es
package tolodash
:
// webpack.config.jsmodule.exports={resolve:{alias:{'lodash-es':'lodash',},},};
⚠ Use with caution /How to enable / Added by@iamakulov
lodash-webpack-plugin
strips parts of Lodash functionality that you don’t need. For example, if you use_.get()
but don’t need deep path support, this plugin can remove it. Add it to your webpack config to make the bundle smaller.
Use the plugin with caution. The default settings remove a lot of features, and your app might use some of them.
lodash-es
is Lodash with ES imports and exports.npm package
For the list of optimizations, seethelodash
section ⤴.
Moment.js is a library for working with dates.npm package
⚠ Use with caution /How to enable / Added by@iamakulov
By default, Moment.js ships with 160+ minified KBs of localization files. If your app is only available in a few languages, you won’t need all these files. Usemoment-locales-webpack-plugin
to remove the unused ones.
Use the plugin with caution. The default settings remove all locales; this might break your app if you use some of them.
Moment Timezone is a plugin for Moment.js with full support for time zone calculations.npm package
⚠ Use with caution /How to enable / Added by@iamnotyourbroom
By default, Moment Timezone includes as much time zone data as possible via a 900+ KB JSON file. In some cases this data includes dates in the 19th century. If your app can work with a smaller range of dates, or only needs specific time zones, most of that data is redundant. Usemoment-timezone-data-webpack-plugin
to remove the unused data.
Use the plugin with caution. Removing too much time zone data can cause subtle date calculation bugs. Make sure your app still has all the data it needs to function correctly.
Ractive is a UI templating library.npm package
⚠ Use with caution / How to enable is ↓ / Added by@danburzo
If you’re compiling your Ractive templates on the go (e.g., by passing strings toRactive({ template })
, switch toractive-loader
. This way, you’ll compile templates during a webpack build – and won’t need to bundle the template-parsing part of the library.
Here’s how to avoid bundling the template-parsing part of Ractive:
Switch to
ractive-loader
, if you haven’t yetAnd alias the
ractive
module to the Ractive runtime usingresolve.alias
:// webpack.config.js{// ...resolve:{alias:{// Tip: `$` in the end of `ractive$` means “exact match”: https://webpack.js.org/configuration/resolve/#resolvealias// This’d disable aliasing – and prevent breaking the code – for imports like `ractive/something.js`ractive$:path.resolve(__dirname,'node_modules/ractive/runtime.min.js')}}// ...}
Use this optimization with caution. Make sure your code does not compile any templates on the fly, or your app will break. Compiling templates on the fly happens whenever you pass a string toRactive({ template: ... })
orRactive.parse()
.
React is a library for building user interfaces.npm package
✅ Safe to use by default /How to enable / Added by@iamakulov
React doesn’t performpropTypes
checks in production, but thepropTypes
declarations still occupy a part of the bundle. Usebabel-plugin-transform-react-remove-prop-types
to remove them from during building.
⚠ Use with caution / Added by@iamakulov &@kurtextrem
There are alternatives to React with a similar API that have a smaller size or a higher performance, but lack some features (e.g., fragments, portals, or synthetic events).
Preact | The smallest React alternative (
preact@8.3.1
+preact-compat@3.18.3
is 7.6 kB gzipped;react@16.4.0
+react-dom@16.4.0
is 31.4 kB gzipped) | No synthetic events | IE8 supported with polyfillsNerv | Smaller than React, larger than Preact (
nervjs@1.3.3
is 9.8 kB gzipped, compat is not needed;react@16.4.0
+react-dom@16.4.0
is 31.4 kB gzipped) | The goal of Nerv is to have 100% the same API (without Fiber and Suspense), seeNervJS/nerv#10 for details | IE8 supportedInferno | Smaller than React, larger than Preact and Nerv (
inferno@5.4.2
+inferno-compat@5.4.2
is 11.3 kB gzipped;react@16.4.0
+react-dom@16.4.0
is 31.4 kB gzipped) | Higher runtime performance than React, the highest performance among all React alternatives,manual optimization possibilities offered | Partial synthetic events | IE8 unsupported natively
Migrate to alternatives with caution. Some of the alternatives don’t have synthetic events or are lacking some React 16 features (Preact issue,Inferno issue,Nerv issue). However, many projects still can be migrated without any codebase changes. See the migration guides:Preact,Inferno,Nerv.
Reactstrap is a Bootstrap 4 library for React.npm package
✅ Safe to use by default / How to enable is ↓ / Added by@kurtextrem
When you import a module from Reactstrap:
import{Alert}from'reactstrap';
other Reactstrap modules also get bundled into the app and make it larger.
Usebabel-plugin-transform-imports
to strip unused modules:
// .babelrc{"plugins": [ ["transform-imports", {"reactstrap": {"transform":"reactstrap/lib/${member}","preventFullImport":true } }] ]}
To see how it works, checkthebabel-plugin-transform-imports
section
react-bootstrap
is a Bootstrap 3 library for React.npm package
✅ Safe to use by default / How to enable is ↓ / Added by@kurtextrem
When you import a module fromreact-bootstrap
:
import{Alert}from'react-bootstrap';
otherreact-bootstrap
modules also get bundled into the app and make it larger.
Usebabel-plugin-transform-imports
to strip unused modules:
// .babelrc{"plugins": [ ["transform-imports", {"react-bootstrap": {"transform":"react-bootstrap/es/${member}","preventFullImport":true } }] ]}
To see how it works, checkthebabel-plugin-transform-imports
section
React Router is a popular router solution for React.npm package
✅ Safe to use by default / How to enable is ↓ / Added by@kurtextrem
When you import a module from React Router:
import{withRouter}from'react-router';
other React Router modules also get bundled into the app and make it larger.
Usebabel-plugin-transform-imports
to strip unused modules:
// .babelrc{"plugins": [ ["transform-imports", {"react-router": {"transform":"react-router/${member}","preventFullImport":true } }] ]}
(This was tested with React Router v4.)
To see how it works, checkthebabel-plugin-transform-imports
section
styled-components
is a CSS-in-JS library.npm package
✅ Safe to use by default /How to enable / Added by@iamakulov
There’sbabel-plugin-styled-components
that minifies the CSS code you write withstyled-components
. Seethe minification docs.
whatwg-fetch
is a completewindow.fetch()
polyfill.npm package
⚠ Use with caution / How to migrate is ↓ / Added by@iamakulov
unfetch
is a 500 bytes polyfill forwindow.fetch()
. Unlikewhatwg-fetch
, it doesn’t support the fullwindow.fetch()
API, but instead focuses on polyfilling the most used parts.
Migrate tounfetch
with caution. While it supports the most popular API parts, your app might break if it relies on something less common.
Of course, there are also optimization tips for other libraries too. You can use them with common sense to get smaller or more performant bundles.
✅ Safe to use by default /How to enable / Added by@kurtextrem / More Insight about this onTwitter
This handy babel plugin will transform your imports to only import specific components, which ensures not the whole library gets included (if tree-shaking is ineffective for the specific library).
// Beforeimport{Grid,Row,Col}from'react-bootstrap';// AfterimportGridfrom'react-bootstrap/lib/Grid';importRowfrom'react-bootstrap/lib/Row';importColfrom'react-bootstrap/lib/Col';
Copyright 2018 Google Inc. All Rights Reserved. Licensed underthe Apache License, Version 2.0.
About
Using a library in your webpack project? Here’s how to optimize it
Topics
Resources
License
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Releases
Packages0
Uh oh!
There was an error while loading.Please reload this page.
Contributors9
Uh oh!
There was an error while loading.Please reload this page.