DEV Community

Cover image for Testing npm packages before publishing
Carl Vitullo
Carl Vitullo

Posted on • Updated on

Testing npm packages before publishing

Photo by Erol Ahmed on Unsplash

When developing an npm package, you have to confirm that it can actually be used. It's great if tests pass, examples build, and demos run, but it's broken if consumers can't install it. npm provides a tool to help test packages before publishing, npm link. The docs explain it very well, but a small example is below. You run it once in your package directory, and again in your app directory.

~/workspace/package-name $ npm link
~/workspace/some-application $ npm link package-name
Enter fullscreen mode Exit fullscreen mode

This is an excellent option–when it works. npm link has been around all the way back to npm@1.0, long before build steps were the norm and browser JS was a part of npm, and the adoption of these tools has introduced some problems. There are 3 main problems I've run into.

Some build tools don't understand symlinks.

Mature build tools typically don't have this problem or have issues with symlinks discovered and fixed quickly. However, it's a common problem with newly released tools and one of the more common regressions. webpack has special configuration for how to resolve symlinks because of these issues. The documentation specifically mentions potential problems with npm link.

Symlinking doesn't verify that you've packaged it correctly.

Even if you've gotten your symlinked package to run correctly, it doesn't tell you if it will work once you publish it. You only know that all of the files on your disk will run. A package that has been published to npm is packaged as a tar archive, and there is some configuration about how it should be packed. Symlinking doesn't go through that process, leaving you with untested configuration.

Module resolution doesn't work with 2 file trees.

Because the package is a symlink, it exists in a different file tree. This creates a corner case in module resolution–one that breaks React packages. When a component in your package loads React, it looks up the file tree for a node_modules/react folder and finds only its own–not the one your application loads. This causes 2 different copies of React to load, which leads to all sorts of issues.

This is the most damning problem. It's one thing to have tools break occasionally, but for an entire category of libraries, npm link is fundamentally incompatible. These problems have put me off using npm link at all. I have wasted numerous hours trying to wrangle symlinks for a package I'm developing and have never gotten it to a point where it's reliable.

Now, I use npm pack.

npm pack

The pack command creates a .tgz file exactly the way it would if you were going to publish the package to npm. It pulls the name and version from package.json, resulting in a file like package-name-0.0.0.tgz. This can be copied, uploaded, or sent to a coworker. It's exactly the file that would be uploaded to npm if you published it.

~/workspace/package-name $ npm pack
Enter fullscreen mode Exit fullscreen mode

Once you have the file, you can install it. npm install can install from a lot more sources than just npm, and I highly suggest skimming through the docs. We have to specify the full path to the file, so I usually copy it to my home directory first for convenience.

~/workspace/package-name $ npm pack
~/workspace/package-name $ cp package-name-0.0.0.tgz ~
~/workspace/some-application $ npm install ~/package-name-0.0.0.tgz
Enter fullscreen mode Exit fullscreen mode

You could probably set up an alias or function in your terminal to automate this, but I don't do it frequently enough to bother. npm pack | tail -n 1 will output just the filename to standard out. (Since writing this, I've learned about yalc a tool that does this automatically)

This runs through a complete publish cycle–it even runs the publish npm script and the associated pre- and post-scripts. Packing it up and installing it is an excellent way to simulate publishing a package, and it avoids all of the quirks and problems of symlinking.

I know when I was first trying to publish packages to npm, one of the hurdles I faced was figuring out if it would actually work. Publishing feels so final; you put it up for the world to see and that version number can never be used again. npm pack helps me be more confident that it's going to work the way I expect it to.

Thanks for reading! I'm on Twitter as @vcarl_. I moderate Reactiflux, a chatroom for React developers and Nodeiflux, a chatroom for Node.JS developers. If you have any questions or suggestions, reach out!

Top comments (7)

gmartigny profile image
Guillaume Martigny

Nice article.

Just to add my 2 cents:
If you're building a complex package, you could want to split part of it into multiple sub-packages. It's (IMO) a clean programming structure that every logic has it's own file and require only what's necessary.
But doing dozen of npm link is maddening. And Lerna is such a great help with that.
It allow you to easily manage sub-packages from adding dependencies, running scripts or publishing.

ben profile image
Ben Halpern

Super useful, thanks for the post Carl!

svale profile image
Svale Fossåskaret

Very helpful! npm pack was new to me and just what I needed to verify changes to the files-field didn't break anything. Thanks!

margaretkrutikova profile image
Margarita Krutikova

This just solved the problem I have been battling in ages, and I can finally go to sleep now 😅
Thanks for the amazing article!

tamb profile image

Did not know about npm pack. That's awesome! Thank you!

qwertie_63 profile image
David Piepgrass

Why not use testpack-cli? It automates the process of running your unit tests against the package produced by npm pack.