Stop importing whole JavaScript packages

How often have you ever imported a whole JavaScript package into a project when you only needed to use very few features of this package? You will probably be able to recall many such cases.

A vivid example of a package that is imported entirely, requiring only a few of its functions, can be called the Lodash library . If you have not heard about this library - you should take a look at its documentation. In particular, on the project’s website you can find out that Lodash simplifies JavaScript development by taking on the task of working with arrays, numbers, objects, and the like.



The Lodash library includes over 200 functions. This suggests that she, indeed, is able to help the programmer in solving a lot of problems. But it may happen that by importing the entire library, only 4-5 functions will be called. This leads us to the question of the advisability of importing the entire package in a situation where only 2-3% of its capabilities will be used. Let's think about how to handle this.

Lodash get function


One of my favorite features of the Lodash library is the feature get. It allows you to organize secure access to nested objects and supports the use of default values.

Here is an example of using this function:

const _ = require('lodash');

let employee1 = {
  name : "Jon",
  address : {
    street : "North Avenue",
    area : "DAC",
    zip : "87344",
    contact : [ 12444554, 9384847 ]
  },
  designation : "Manager"
};

let employee2 = {
  name : "Jake",
  designation : "Senior Manager"
};

function getHomeContact(employee) {
  return employee.address.contact;
}

getHomeContact(employee1); // [12444554, 9384847]
getHomeContact(employee2); // Uncaught TypeError: Cannot read property 'contact' of undefined

function getHomeContactWithLodash(employee) {
  return  _.get(employee, "address.contact", []);
}

getHomeContactWithLodash(employee1); // [12444554, 9384847]
getHomeContactWithLodash(employee2); // []

Using this function allows you to make the code much cleaner than before. This helps to avoid errors due to the fact that when an empty array is expected, the function will not return null. Thanks to this function, you cannot, by mistake, call a method mapon an empty array. It protects from other troubles.

Let’s take a look at how the inclusion of the Lodash library in the project if it is planned to use only the function will affect the size of the bundle get. The experiments will be conducted using a React project. The size of the bundle will be analyzed before importing the library and after various options for connecting it to the project.

Project size before importing the library


We analyze the size of the project files before importing the library.


File size before using Lodash

Now let's look at the consequences of several ways to import a library into a project.

Project size after using different library import methods


▍1. Traditional import


This is about importing the library in one of the following traditional ways.

The first:

import _ from ‘lodash’;

Second:

const _ = require('lodash');

Here's how it will affect the final size of the project files.


Resizing project files when importing an entire package

▍2. ES6 import


Here, again, we have two options.

The first:

import { get } from 'lodash';

Second:

const { get } = require('lodash');

Let us take a look at the effect of such imports on the size of project files.


File sizes when importing the get function using destructive assignment

As you can see, using both of the above approaches led to an increase in file sizes by about 23 Kb. And this is a very significant increase, especially considering that we are talking about using a single function from the library, which includes more than 200 functions. As a result, it turns out that the size of the bundle has increased as much as one would expect it to increase if all these 200 functions were used in the project.

Maybe 23 Kb is not such a big price for using the only necessary function? No, that's too much. 

Is there any way in which you can import only what you need into a project? Yes, there is such a way.

Let's analyze the folder where the Lodash materials are stored.

To do this, just go along the path node_modules/lodash. In this folder you can find many files in which the code of individual functions is stored. Among them, it is easy to find the file get.jsin which the code of the function we are interested in is located get. And this means that if we need only a function, it getis enough to import only this file into the project. This leads us to the third method of import.

▍3. Import get.js file from Lodash


Here, again, two methods are available.

The first:

import get from 'lodash/get';

Second:

const get = require('lodash/get');

Take a look at resizing the bundle.


File sizes when importing the get.js file

It can be seen that due to the fact that we only imported the file into the projectget.js, we were able to get rid of more than 20 KB of unnecessary code that gets into the bundle when using other methods. But we are talking about only one package. A typical JavaScript project has a lot more dependencies. Imagine how a cautious approach to importing packages and constant control of bundle sizes can affect a server or client project.

Do all packages support a selective import approach?


No, not all. It completely depends on the organization of the package files. But, fortunately, most of the fairly large popular packages are structured so that, working with them, it is easy to organize selective import of their individual capabilities.

How to do the same while working with other libraries?


The process of removing unused code is known as tree shaking. If you need, for example, to “shake the tree” of the Ant Design library - search the Internet for the words “antd tree shaking”. You may well find a discussion on this subject on StackOverflow or on GitHub. Having found such a discussion - look through it - it is quite possible that someone has already solved the task before you.

Another way to get rid of unnecessary code requires a little more effort. You need to go into the package folder located in node_modules, and do code analysis. In particular, you should be interested in the structure of the project and find out if it is divided into small modules that can be imported into the project independently of each other.

Import optimization example using antd package


Before:

import { Menu} from 'antd';

After:

import Menu from 'antd/es/menu';
import 'antd/es/menu/style/css';

Import optimization example using material-ui package


Before:

import { Button } from '@material-ui/core';

After:

import Button from '@material-ui/core/Button';

Import optimization example using moment package


Optimizing the library import moment looks a little more complicated. Therefore, if you need it, take a look at the task that I created in the task tracker of this library.

Summary


You yourself can make sure that a lot of unnecessary code gets into your projects. You can solve this problem by carefully comparing what you import with what you use. This will allow you, for example, to reduce the loading time of your sites. Therefore, it is recommended that you carefully monitor the size of project bundles and optimize dependency imports.

And how do you, in your JavaScript projects, struggle with importing unnecessary code?


All Articles