npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details


  • User packages



Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.


Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2021 – Pkg Stats / Ryan Hefner




This node module comes to help people who would like to develop extensions similar to [Import Cost VSCode extension]( for additional IDE's such as Atom, WebStorm, Sublime, Vim etc.




import-cost Build Status Build status

This node module comes to help people who would like to develop extensions similar to Import Cost VSCode extension for additional IDE's such as Atom, WebStorm, Sublime, Vim etc.

Use freely to implement extensions for other IDE (or contribute them to this repository)

You can see good reference for how to work with this module in the VSCode extension implementation

How to use

$ npm install --save import-cost
import {importCost, cleanup, JAVASCRIPT, TYPESCRIPT} from 'import-cost';

const emitter = importCost(fileName, fileContents, JAVASCRIPT /* or TYPESCRIPT */);
emitter.on('error', e => /* handle parse error of file, usually just log & ignore */);
emitter.on('start', packages => /* mark those packages as "calculating..." */);
emitter.on('calculated', package => /* show size of this single package */);
emitter.on('done', packages => /* show sizes of all those packages */);
emitter.removeAllListeners(); /* ask to stop getting events in case file was updated */)

// ...

cleanup(); /* do this when you shutdown your extension in order to kill our thread pool */


Usage as you can see above is pretty straight forward, importCost() gets three parameters:

  1. fileName - This is a string representing the full path to the file that is being processed. We need full file path since we need to look inside node_modules folder of the file in question
  2. fileContents - This is a string which contains the actual content of the file. We need it because in IDE extension it is usually much faster to get contents from IDE then reading it from filesystem. Also, obviously changes to the file might not have been saved yet, we want to work on the file as the user types to it.
  3. language - This effects which AST parser we will use to lookup the imports in the file. As you can see above, you pass either JAVASCRIPT or TYPESCRIPT to it. Typically IDE can tell you the language of the file, better use the correct API of your IDE then rely on extensions.

In response, importCost() returns a standard Node EventEmitter. You can read about event emitters in Node docs, but typically all you need to know is that you can register a callback for various events we emit using emitter.on(eventName, callback). We also recommend you un-register using emitter.removeAllListeners() when the file in question changes, this will help you not be confused with any results that are no longer relevant to that file.


Following are the events you can listen on for the returned emitter.

emitter.on('error', e => /* ... */);

The emitter will emit an 'error' event for any error that caused it to stop working on the task at hand. Typically, you will not get any other event from the emitter after this error happened. Usually error will be that we failed to parse the file, but that's not really something that you need to act on since it is perfectly fine that user's code is sometimes not valid while he types. e will contain the error details, feel free to log it somewhere for cases it might be useful.

emitter.on('start', packages => /* ... */);

The emitter will emit a 'start' event right after it finished parsing the file and knows which imports are going to be calculated. The callback will receive an Array of {fileName, line} objects. Typically this would be a good time for your extension to mark those lines in the file as being calculated.

emitter.on('calculated', package => /* ... */);

The emitter will emit a 'calculated' event for each of the packages as results arrive from our thread pool. The callback will receive a {fileName, line, size, gzip} object. Typically this would be where your extension displays the result in the appropriate line. The size in case we failed to calculate (mostly because of missing dependency) will be 0.

emitter.on('done', packages => /* ... */);

The emitter will emit a 'done' event once we have results for all of the packages. The callback will receive an Array of {fileName, line, size, gzip} object. This is not super helpful since by now you already received a 'calculated' event for each one of the packages in this array. However, it is a pretty good checkpoint to clear any decorations in lines that do not appear on this list and were left hanging because of some race condition edge cases.


As mentioned above, we recommend you un-register all of your event listeners using emitter.removeAllListeners() when the file in question changes, this will help you not be confused with any results that are no longer to that file.


As mentioned above, we use a thread pool for doing the calculations. When your extension terminates, your IDE will typically send you some notification of that. It is important that you handle this notification and invoke cleanup() in order to kill the thread pool.