pinterest / bonsai

Understand the tree of dependencies inside your webpack bundles, and trim away the excess.

Home Page:https://pinterest.github.io/bonsai

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Are dependency sizes post-minification?

gaearon opened this issue · comments

commented

Apologies since it's not a real issue but a question.

I've noticed many similar tools include misleading JavaScript dependency size information because Webpack stats only give you module sizes before Uglify plugin is applied. As a result, for example, React is reported to be much larger than it really is.

I was wondering if this tool also suffers from this issue, or if you have a workaround for this. From what I know, sourcemaps offer a much more reliable way to measure real sizes than stats produced by Webpack.

Cheers!

The short answer is, strictly speaking, Bonsai takes that Webpack data and all the problems that come with it, un-minified file size, __DEV__ conditions & debugging statements, etc. It's a tradeoff, but I got a win when I punted on building a cli command!

Whats worse, the 'weighted size' column is full of completely made up numbers that never appear anywhere else. If people want to report actual bytes saved they've got to measure in prod. Bonsai needs to be clear in it's intention to highlight potential hotspots so people can decide where to take action.

For me the size of a single module is too game-able, we can split big files into many small ones all day long but it doesn't save bytes. The problem is that it's easy for a single import statement to pull in 100's of modules and explode the bundle size.

For vendor libs like React I think the file size is a cost that's paid back by all the utility that you get. The trick is to call out places where a big dependency isn't being used frequently enough, or a project only uses a small slice of it. For example it's worthwhile to build a blog platform with React, but I would not suggest someone add react and react-tag-cloud to their Wordpress site, that's a big dependency for a small utility. There are probably more efficient ways to get that feature.

That's my philosophy on it, I hope the tool can bear that out.

The blog was a toy example, I've been looking at https://github.com/getsentry/sentry because I think they've got some smart folks, clean code and it's a real world example.

git clone https://github.com/getsentry/sentry.git
cd sentry
yarn install
./node_modules/.bin/webpack --json --config webpack.config.js > sentry-stats.json

Putting the stats through th0r/webpack-bundle-analyzer we get a cool visual:

screenshot 2017-06-04 11 30 25

Some things jump out.

  • Sure React is big-ish in yellow, but I assume all those blue boxes inside app/views/ and app/components/ use react, which is great utility and code reuse.
  • jquery.js and select2.js stand out and are surprising inside a react site. If that's the only place that uses jQuery then maybe we should consider using react-based dropdown instead?
    • Turns out if we wanted to remove select2 we'd have to touch 5 files, so it's got some utility.
    • jQuery is imported into 60 files, so whatever they're using it for there's clearly many plugins and reasons for it being there.
  • lodash isn't in the vendor bundle, but it is inside node_modules... interesting. It looks much bigger than underscore.js at 219kb compared to 51kb in the vendor file, but those numbers have all the problems you were asking about. And we don't know what depends on lodash, so we're kinda left to wading through yarn.lock or node_modules and maybe learn something.

Lets switch into Bonsai. Looking at the 'app' bundle for Sentry we can see these 10 modules as the heaviest:

screenshot 2017-06-04 13 56 44

./app/index.js
./app/routes.jsx
multi
/Users/ryan/Code/sentry/~/react/lib/ReactDefaultInjection.js
./app/views/groupActivity/index.jsx
./app/views/groupEventDetails.jsx
./app/components/activity/noteInput.jsx
/Users/ryan/Code/sentry/~/react-mentions/lib/index.js
/Users/ryan/Code/sentry/~/react-mentions/lib/MentionsInput.js
./app/views/groupDetails.jsx

We can just past the first few:

  • index.js and routes.jsx are the main modules for the app. The entry point is always at the top.
  • The third record represents the vendor bundle, which should be depended on by everything. We know React and jQuery are well used, I assume the others are too.
  • Maybe ReactDefaultInjection should be vendored too?
  • Sentry doesn't do route-splitting, so both groupActivity/index.jsx and groupEventDetails.jsx are depended on by the router. If we split them we'd have two new chunks to talk about.
  • noteInput.jsx. Here we go, 7th on the list.
    This looks like something we could have a placeholder for and then load on focus. If we click 'Ignore' we see that this module brings in 367 more things!

screenshot 2017-06-04 13 44 57

Expanding that list there's lots of lodash, some babel-runtime stuff, and react-mentions. These are all modules without any other references in the app. The files sizes still have all those same problems, but it's probably worth it to strip out 10% of the uncompressed bytes.

Marking this as resolved. Happy to keep talking with people about it though