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:
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.
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.
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 })
}
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'
vs date-fns
which is tree shakeable
import { format } from 'date-fns`
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
oryarn.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.
Top comments (0)