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

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.

Related

can't find less loader and rules in webpack.conf

I want to add Less support to a React project. According to these links:
Adding SASS or LESS support to create-react-app
React + CSS Modules + LESS + Webpack 4
I ejected project and installed less and less-loader, but I can't find rules section in webpack.config.js.
Why my config file is not like the config file in these two pages? (webpack version is 4.1.0)
How can I add Less support to my project?
If I add
{
loader: require.resolve('less-loader'),
},
to file config, I'll get "Failed to compile" error
Cannot read property 'denominator' of undefined
in ...\node_modules\bootstrap\dist\css\bootstrap.css (line 2100, column 2)
Those tutorials are based on the old CRA, in the latest one they merged dev and prod files and did some additional mumbo jumbo to make it more "concise". One of those things was extracting CSS loaders into a standalone helper function - getStyleLoaders(). The rules section is below and the output of getStyleLoaders is merged onto it at an appropriate point.
In general what you are doing by appending your loader at the end of loaders array, is correct. And the error is not on the webpack side. It's rather thrown by less-loader not being able to interpret the file, because of invalid syntax inside.

How to remove dead code in Create React App

I have a create-react-app project, and I am working on reducing my bundled JS file size. About half of my bundle size is coming from a dependency called MDBReact (a react component library), and majority of it is not being used. I am trying to find out how/if I can remove dead code with tree shaking from the bundled build. I have been looking into this for a while and the closest article I found was this. This article leaves me confused and it does not give any explanation into how or if it can be done. I also found this guide on webpack tree shaking explaining how it can be done, but this does not seem to solve the problem.
CRA is using webpack to bundle code. Webpack can only treeshake es modules by default and commonjs modules when using plugins.
To help you on the way, how are you currently importing from MDBReact?
It looks like MDBReact is not written in es modules and webpack is therefore going to have a hard time tree shaking if you use the following import statement:
import { module } from 'MDBReact';
Instead you could try to import using the following
import modules from 'MDBReact/module';
You might have to change the path to the module depending on how MDBReact is structured. Take a look in the node_modules folder to find out.

Using webpack with angular.1.5 , php and bower

my index.php is like the following :
<script src="app/bower_components/jquery/dist/jquery.min.js"></script>
<script src="app/bower_components/angular/angular.min.js"></script>
<script src="app/bower_components/angular-ui-router/release/angular-ui-router.min.js"></script>
<script src="app/bower_components/angular-sanitize/angular-sanitize.min.js"></script>
I would like to add webpack to bundle all these files and minify them
I did not find the way to do that.
I have installed npm , node and webpack
I manged to us webpack to simple files like: webpack entry.js bundle.js . but not for my angular app
Let me answer it in general and then specific to your use case.
IN GENERAL:
Webpack
is a module bundler
needs entry and output as minimum
configuration
Where do i configure/list-out all my application code?
You dont configure it but code it. Please read on...
How webpack knows what code/modules to pick up to bundle?
Webpack will look at the code configured for entry and then internally builds its module dependencies (as dependency graph).
How do you declare module dependencies?
In short: by using require("module-or-path-here") or import "module-or-path-here". Do note that the javascript (ES6 a.k.a ES2015) itself has native module support now. Here is a good article on JS modules.
What is dependency graph?
Webpack will start with the code configured for entry and then pick up its immediate dependencies. It then goes to find out the dependencies of those immediate dependencies and so on...
Once the dependency graph is complete, webpack will start processing them and bundle them into output.filename located at output.path
Fine, but i want to perform some resource (JS / CSS / SCSS / images, etc..) specific work for ex. minify js code. How to do that?
Webpack is flexible (and powerful) and allows to configure resource specific work via loaders and plugins.
IN SPECIFIC:
The modules in AngularJS (i.e. 1.x) are not same as the modules that webpack works with. As you can see, while declaring the modules in angularJS, you are defining modules with angular by calling angular.module.
One option is to make sure to bundle all your angular module definition files (i.e that consists of angular.module("module-name-here", ["depenndencies"])) first followed by the angular components that needs those modules. There are several way to do that. For ex. name all your angular modules declaration files with a common pattern and then configure webpack to pick them up first.
Minification is pretty simple to achieve with webpack. You can try one of the options pointed out in the webpack documentation.

Redux + React understanding size of webpack bundle

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.

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