Redux + React understanding size of webpack bundle - reactjs

I read various answers like this regarding reducing the bundle size. First I wanted to understand what is going on with my 13MB bundle, so I've installed the Webpack Bundle Size Analyzer. It generated this output:
There are a few things I don't understand:
Why is react appearing twice with two different sizes?
How come it doesn't add up to 13MB? (it's around 4.75MB)
Does this means my own code is only 4KB? (last line)
Is it possible to understand from this tree how to save KBs? I mean, for instance, is there a way to use only parts of lodash or is it required as a whole by React?
Update:
Found the answer for #1. React-color requires ReactCSS which requires a different version of react and lodash. Without React-color my bundle dropped from 13MB to 8MB. I will try to find a way to re-use react and lodash.

It seems that you have eval-source-map devtool option in your webpack config file, that's why you are getting such huge bundle size. This way, sourcemaps are putting inside of bundle js file.
Try to change this option to source-map to build source maps separately.
// webpack.config.js
{
devtool: 'source-map',
// ... other options
}

1) Sometimes other dependencies require again lodash and / or react, so these dependencies are pulled in multiple times by webpack (usually happens when the version differs), here the DedupePlugin should help. The final bundle size also depends on your devtool entry in webpack, so in development it is usually much bigger as you probably have sourcemaps enabled and a your build is not optimized. Hard to tell without your actual webpack config.
2) Maybe webpack is already deduping?
3) last line says 400KB
4) You can definitely save a few kbs. A good way to start is using lodash-webpack-plugin with babel-plugin-lodash, this will import only the lodash methods you are actually using instead of the complete library. You can also just require the bits you need from material-ui as outlined in this answer.
I recently added the webpack-dashboard to my webpack config, so I instantly see the output and percentages that make up my bundle size, so maybe you think twice about adding huge dependencies if you don't really need them.

Related

How can I debug a React JS App into Cordova?

I was trying to integrate a React.js app in Cordova. Everything goes well, but I was not able to debug the app in the simulator. With chrome://inspect it seems like there's no way to do it, because I can only see the "compiled code". Any solution? Thanks
Maybe there is another better way, but what do the trick for me is to build react with some custom files that i took from node_modules/react-scripts/
(i do that, to avoid react eject)
You need all the sources map on your app.
React by default, use a certain webpack config, but that config doesn't work in your phone.
By default, react use this
You can check it on the file node_modules/react-scripts/config/webpack.config.js
What i do, is to build react with the next webpack config
devtool: "eval-source-map",
So you must
Copy these files on your source code and adapt some imports (there are some import with relative path) You only need these two files
node_modules/react-scripts/scripts/build.js
node_modules/react-scripts/config/webpack.config.js
On the first one, modify it to use the second one,
On the second one, add this devtool: "eval-source-map"
Create new task on package.json , new custom build to use the script your custom build.js
Build with this script, and copy all the source maps with your code, and thats it.
The debug could crash sometimes, (i try it also with iphone + safari, sometimes works, sometimes don't so you must keep trying)
On android tend to work in a better way.
The debug is a little bit slow in compare to the web debug.
I hope this works for you too.
(Sorry for my bad English)

Getting Parcel Bundler Code Splitting working with React + TypeScript + MobX + ReactRouter

I've been trying to get Parcel Bundler to code split a ReactJS project for a while with no success, this project also used TypeScript, ReactRouter and MobX for its state management.
I've been meaning to put a boilerplate sample together and ask for help here for a while but not got round to it.
After a quick google earlier today, I came across a ready made boilerplate on Github which uses the same setup and also does not code split...
https://github.com/wenpengfei/parcel-typescript-react-boilerplate
Once compiled and ran, it just ends up with one big .js file in the dist folder, the idea behind code splitting is to create several smaller .js files per 'area' of the web application right?
Is this even possible with this combination of libraries/frameworks? If not, is my only option to go down the webpack route instead (if that will work?)?
For client side code splitting just use import + React.lazy. Should work out of the box.
To support server-side code splitting (or client-side code splitting with server-side rendering) - https://github.com/theKashey/react-imported-component is the only choice for today.

React root.js weights about 9MB

Ok, so... I have this project where we are using a lot of components (as usual in every React project) but when we compile the project to see it in the browser (ie. foreman start) it takes a lot of time to load and also when it loads it creates a file that is very very large.
We don't know why this is happening, probably something that we messed up and we don't know yet.
I don't know which part of code you need to see to help me understand why this is happening. Let me know and I will give it to you.
Also, I wanna know if there is a way to prevent that file to be that large, as long as I know it should weight no more than 2Mb or something...
Thanks in advance!
The typical reason for such issues is not the amount of components you have made but rather the libraries you use. You can check what is the cause for a large bundle by first running
webpack --json > stats.json
and then installing and running webpack bundle analyzer
webpack-bundle-analyzer stats.json
After this you need to start working on fixing the cause of the large size.
Normally that would depend on what the reason for large bundle size is..but the following methods will definitely help.
code splitting for react
code splitting for webpack
Using webpack's optimizations
And, since sometimes tree-shaking doesn't work as well as it is expected to..you could change your imports from the style of
import {x, y} from 'library';
to
import x from 'library/x';
import y from 'library/y';
Which would ensure that if there are 10 exports from the library, then all of them dont get loaded... Only those that are needed do. For example, if you are using lodash,
import {debounce} from 'lodash';
will import the entire lodash library while
import debounce from 'lodash/debounce';
will only import that particular file.
There are other ways to optimize your output (like webpack externals) but that is dependent on what is actually causing the issue.
NOTE A lot of this answer assumes you are using webpack to bundle code. However if that is not the case you will need to search out optimization and bundle analyzed for the specific bundling tool you are using

how to confirm if tree shaking is working with Webpack 2?

I just finished updating my react app from webpack 1 to webpack 2. However, My bundle size increased by ~30Kb. I was hoping the bundle size would decrease , How can i confirm that tree shaking worked. And why the increase?
TL;DR: As of version 2.3, webpack doesn't have any tree shaking. It merely uses UglifyJS to remove unused code.
First we must define what is tree shaking.
Stackoverflow defines it as "dead code elimination algorithm for modern javascript".
Webpack clarifies that it relies on ES2015 module import/export for the static structure of its module system.
Rollup (which originally popularized the term) also has a similar explanation.
So we can deduce a specific definition: static exclusion of unused ES module exports.
Now, let's see which stages of transformation each module usually has:
babel-loader is fed an entry point which is a javascript file in some module format. Babel can either transform it to another module format of leave it as is (module: false)
webpack will statically parse the file and find imported modules (using some sort of regexp)
webpack will either transform the module format (if babel doesn't tranform it already) or add some wrappers (for commonjs modules)
imported module becomes an entry point and goes to babel-loader
after all modules are loaded and transformed, uglify will process the result bunle and remove unused code (unused: true)
Now, we can see that while uglify can remove unused exports it doesn't actually rely on ES module syntax. It's just a general purpose dead code elimination so it can't be defined as "Tree shaking".
So how can we confirm whether webpack has tree shaking?
First of all, all the code must be in ES module format.
As it was already mentioned in another answer we must disable Uglify.
We also must disable babel's module transformation as we can't know whether a module is used at that phase.
And now if webpack actually implements a tree shaking algorithm we can confirm it by looking at the bundle size of this entry point:
import { keyBy } from 'lodash-es'; // lodash is in ES module format
console.log(keyBy([{ key: 'value' }], 'key'));
If webpack does have tree shaking the result should be tens of kilobytes. If it doesn't it would be half a megabyte or more.
There's a few steps you can take:
turn off minification/uglify
insert comments into some of the functions you know are unused
check the output to see if those comments are there or not
Webpack can also show you the size of each import module/package. For example, at work we have a bundle that includes both lodash and underscore because one of the libraries we're using requires each of them; webpack clearly shows how many kilobytes each package adds:
You should be able to see from this where the increase in size is coming from.

React components large size

Is it normal to have over 700kB in file size for a react component?
This is the file size after compilation.
GridComponent.js 732 kB 0 [emitted] GridComponent
main.js 7.97 kB 1 [emitted] main
GridComponent is the react component. main is normal js for comparison.
Is that normal?
I plan to only include react components in pages that requires them.
I can see that you're using webpack in your app, and your GridComponent.js should have something like require('react'); (or import React from 'react';, if using ES6 modules with babel).
When you require things, webpack will "join" all your dependencies in the specified "output" settings (provided in webpack.config.js). So, if you check the contents of GridComponent.js you'll see that React is inside. In your case, this GridComponent.js is your "bundled file" (it will contain all the dependencies that you've imported). That's why it seems to be "large", because this file contains your component and React itself (and other dependencies as well).
When you say "I plan to only include react components in pages that requires them.", I think you may want to split your code, so your page will only load the things you need. You can check more info about code splitting here:
https://webpack.github.io/docs/code-splitting.html
A basic "splitting" strategy would be to split your "vendor" code from your "app" code (https://webpack.github.io/docs/code-splitting.html#split-app-and-vendor-code). In your case, React, React DOM and other "common" dependencies would go to "vendor", and your app is the code you've written.
But just as tip, code splitting is only really needed when you have lots of code. Because sometimes an extra network request may introduce more "latency" than downloading a few more bytes. Or if you have some "special" caching strategy, since your app may change more times than your vendor code (your vendor code will only be downloaded again when some dependency version is changed), and you avoid downloading lots of bytes when a simple thing is changed in your app.
I think this solves your question, but to add more information here, if you want to distribute your code to more people (i.e. an open source project), you may distribute your code and say "ok, to run that, you must install that other dependency", and you can achieve that with peer dependencies.
If peer dependencies is not your case, you can save some bytes by minifying your file (you can do that by modifying your webpack configuration). A good blog post talking about that can be found here:
http://moduscreate.com/optimizing-react-es6-webpack-production-build/

Resources