DEV Community

Andrei Cacio
Andrei Cacio

Posted on

How to analyse browser NPM packages before installing them, a beginners guide.

There's a popular quote on the internet about your daily javascript needs:

There is a NPM package for that

Maybe it's a bit exaggerated, or is it? Even so, installing NPM dependencies is part of any project and they should be handled with care and thought.

I'm not sure if this is the best approach. But I would like to share my train of thought before hitting npm install ... in my console.

The dependency

You've been hitting that NPM search engine and that perfect result just popped up, it's everything you've been waiting for and more. But we're not out of the woods yet, here are a few steps to follow before installing that new fancy dependency.

Size matters

A great tool to use is https://bundlephobia.com.
For the sake of argument let's say you are in a search for a quick modal library for a Vue app. First search tot pop up is vue-js-modal. A quick search in bundlephobia and we have the following result:
bundlephobia analysis results
Those are some interesting numbers for a modal. Is 11 kb of bandwidth worth for just a modal component?

In your bundlephobia investigation you should keep an eye out for:

  • download speed
  • bundle size (raw and gzipped)
  • composition (on how many dependencies does it depend)

Check the README

First red flag if there is no README. In this case maybe it's time to go back to the NPM search engine. Empty README's are ok if you just want to explore or experiment. But if you are looking for a production dependency I would turn back.

Check for an example section. Examples will confirm if that dependency does what you want it to do. If it does way too much maybe it's not worth all those extra bytes just for a plain happy flow. This is not a big problem if the package supports tree shacking (jump to Tree shakeability for mode details).

The README should also have a more broad documentation or a link to one.

The repository

If everything looks fine until now we can head over to the repository.

Contribution frequency

One way to get the pulse of a repository is to check the time to the last contribution. This can be easily spotted on the left side of the file row in Github.
Source code file contribution frequency

The src or source folder is the most important one because it tells us when was the last time the source was changed. A red flag would be if we see more than 7-8 months (a number with no research behind it). There are very rare cases where packages don't require maintenance or are simply done. But most of the case you would like to see activity on that repo.

Why is contribution frequency important? It gives the developer an idea if the project is abandoned or if the community simply lost interest.

Another way to spot a legacy/abandoned repository is to look in the README file for Project status or similar headers. An example of such a section we can find on the momentjs repository.

Image description

Version

Check the version. If the library is in an alpha or beta version it will mean it's not production ready. However, they might have an older stable version available. If this information is not clear from the README you could still check the Github tags section and look for the next stable version. But, if the README is not clear on it it usually means you're out of luck.

Security

When installing a dependency via npm install, NPM does an audit check via npm audit and you will get a report if any vulnerabilities pop up. If there are issues with the dependencies of the package you are trying to install, you can try to fix them with npm audit fix.

For more info check out the official NPM documentation

Source code

Reading source code is a very good practice to master. It has loads of advantages.

Reading the source code is important because it will give the developer an idea if the dependency does way more than it needs to or if it falls in the other extreme and does too little.

Even if the dependency seems to fix the problem at hand it may not be necessary to install it. Some dependencies might be simple wrappers (or facades) over an existing library. These types of dependencies can be spotted easily with UI libraries like react or vue. Some examples are: vue-click-outside, vue-markdown and others.

If we were to analyze vue-markdown's README we can see that it comes out of the box with some extensions pre configured. And if we dig inside the code a bit we can see that there is no way of disabling or adding new extensions if we need to:

render(createElement) {
    this.md = new markdownIt()
      .use(subscript)
      .use(superscript)
      .use(footnote)
      .use(deflist)
      .use(abbreviation)
      .use(insert)
      .use(mark)
      .use(katex, { "throwOnError": false, "errorColor": " #cc0000" })
      .use(tasklists, { enabled: this.taskLists })
}
Enter fullscreen mode Exit fullscreen mode

the markdown instance lives on the component instance. To change its configuration it needs to be accessed directly and reinstantiated. This beats the purpose of the package altogether.

Another drawback of depending on a library that is tied to a UI package like Vue will become more obvious when you will want to upgrade Vue. Having a lot of Vue based packages will make the upgrade process unnecessarily complex.

If you reach the conclusion that vue-markdown does too little or too much you can always just use the code library the component is based on. In this case markdown-it and create your own component with just the right configuration.

Tree shakeability

This feature is built in in most popular bundler tools like webpack and rollup. This is important because it offers the possibility to import strictly the functionality you intend to use. The rest of the library that is not imported will not end up in the final bundle. This is a very important trait for a package to have.

An easy way to spot if a library is not tree shakable is to look in the docs and see how that library is imported. For example momentjs is not tree shakeable because you can only import it like so:

import moment from 'moment'
Enter fullscreen mode Exit fullscreen mode

vs date-fns which is tree shakeable

import { format } from 'date-fns`
Enter fullscreen mode Exit fullscreen mode

For more info on this checkout the webpack docs.

Check the dependencies

You can easily check these by reading the pacakge.json file in the repository. Some of the stuff to look out for

  • double dependency: duplicating a dependency because the version differs from the one in your project (e.g. ending up with two Vue versions or two React versions). You can check this by reading package-lock.json or yarn.lock after installing the dependency and look for dependencies with more than one version.

  • having too many dependencies: this can drastically boost final bundle size, however this can be also spotted using bundlephobia, I mentioned above.

Github stars

Intentionally last because it's the most known criteria for filtering packages. There isn't much to say here, so I will leave it as is. Just keep in mind that left-pad had a generous number of stars and we all know where that road went.

Reasons to ignore some or all of the items on this list

In one word: speed: If you want to hack together a proof of concept or a small project. But, for longterm projects that will require maintenance, it could help to check some of these steps off before installing your next dependency.

Conclusion

I'm sure this list can be improved and it's far from finished but it's a good place to start. Developers are usually busy with other tasks and projects are always on a deadline. But, because of all this rush it's very tempting to cut corners and go with what works until it doesn't anymore.

Having fewer dependencies in your project will benefit on the long term. You will have more control over the project and we all now how painful it is to deal with:

  • dependency versions issues
  • dependency upgrade/updates
  • core library upgrades like Vue, React etc. which impacts other dependencies

Thank you for reading.

Discussion (0)