Gotchas When Publishing Modules in npm and Bower

Avatar of Kaloyan Kosev
Kaloyan Kosev on

Bower and npm are de-facto the package managers of the web. I doubt there are many front-end developers out there who haven’t heard of them or used them to manage dependencies.

Whilst many of us use them as consumers, one day you might decide to share a project of your own and become a contributor! This happened to me recently. I had the experience of publishing my open-source library on npm and Bower.

Although their official docs were quite good, I still ended up struggling with three little known gotchas. I won’t focus on the basics in this post. You can always find and read about them. I’ll instead focus on the gotchas.

Nowadays, it looks like even Bower tells people not to use Bower. However, in 2018, there are still many projects that depend on it. The state of JavaScript in 2017 survey shows that around 24% of surveyed developers still use Bower as a package manager. Therefore, I think it might take a little while before we see the end of Bower, which means it’s probably still worth supporting it to cover legacy-package-managed projects. I feel the pain of those of you working on a legacy project—that’s why I chose to publish my open source module there, too.

My hope is that after this you’ll be one step ahead when you decide to share your code with the world. Without any further ado, here are some gotchas I’ve come across when managing packages.

Removing a Package From npm

Why bother spending hours choosing a name, when you can focus on shipping the features first? In my first experience with npm, I was unfortunate to leave the name of my project “test-something.”

Guess what? A few days later, I found out that the un-publish option in the npm public registry is only allowed with versions published in the last 24 hours. If you are trying to un-publish a version published more than a day ago then you must contact support.

They state that it is generally considered bad practice to delete a library that other people depend on. I understand that but I’m 100% sure that no projects depend on a package called “test something.”

I was about to leave things alone, but my test package was going to be visible forever in my shiny npm user profile. Dislike!

I contacted support and they handled my request within the very same day. They still didn’t want to completely un-publish it but they did transfer it to the @npm user account and deprecated it with a deprecation note. This removed it from my profile (woohoo!) and from the search results. However, if someone knows the exact URL (or name) they can still install it. While that’s not totally ideal, the deprecation note will still be an alert that the package is no longer supported.

I think this might be related to the 11 lines of code, that Azer Koçulu deleted from npm and which kind of broke the internet for a moment. Safety first.

The moral of the story: make sure to choose your package name wisely!

Exporting Modules

Another gotcha I encountered was how to export my module. I wanted to do it in a universal way so that anyone can import it to the browser in any of the three most popular approaches. For example…

…with ES6:

// If a transpiler is configured (like webpack, Babel, Traceur Compiler or Rollup):
import MyModule from 'my-module';

…with CommonJS:

// If a module loader is configured (like RequireJS, Browserify or Neuter):
const MyModule = require('my-module');

…or by referencing the script file in the HTML:

<script ="/node_modules/my-module/index.js"></script>

What I was actually looking for is the Universal Module Definition pattern. It’s a pattern that provides a clean way to expose your module to different environments that consume modules in a variety of ways.

This pattern has a couple of variations, depending on what you really need. However, modules written this way are capable of working everywhere, be it in the client, on the server or elsewhere.

The standard pattern is:

(function (root, factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD. Register as an anonymous module.
    define(['dependency'], factory);
	} else if (typeof module === 'object' && module.exports) {
		  // Node. Does not work with strict CommonJS, but
		  // only CommonJS-like environments that support module.exports,
		  // like Node.
		  module.exports = factory(require('dependency'));
	} else {
    // Browser globals (root is window)
    root.returnExports = factory(root.dependency);
	}
}(this, function (dependency) {
  // Use dependency in some fashion.
  return {
    // Your module goes here
  };
}));

If you’re using Grunt, Gulp or webpack, you’ll find that there is a plugin that can wrap your modules like this for you. Plus, it’s in the core of webpack already!

Managing Distribution Files

This one was really tricky.

I am building a package for npm and Bower. I followed the pattern to keep the working files (ES6) in the src/ package directory and build my distribution files (ES5, compiled with Babel) in the dist/ directory.

I ignore the entire dist/ folder in the .gitignore file. You know the drill: source control should only contain source. If it’s generated from the source, it doesn’t belong there—it should be generated by your build process instead.

On the one hand (npm), I have a .npmignore which does exactly the opposite and ignores src/ instead of dist/. On npm, I only want my distribution files. That works out perfectly well.

On the other hand (Bower), the dist/ folder is missing in the repository and, therefore, the Bower package doesn’t include it. You see, Bower tracks your publicly available Git endpoint only. By pushing Git tags you release a new version on the Bower registry. Yes, it can ignore files, but they are related only to the files in your repository.

So, how can I publish the ignored by git dist/ folder contents on Bower?

I’m not sure it’s possible to do. The only workaround I found is to commit the distribution files in the repository. If you really want to keep those distribution files out of the repo, the trick is to commit them right before you release a tag. Release a tag. Remove them.

There is one more use case that gives me some peace of mind. Imagine somebody downloads a ZIP of your repository and drops it into their project. They won’t need your fancy build step. The production source is already there. All right, maybe that’s not so bad after all.

Wrapping Up

Both npm and Bower continue to be widely used and helpful ways to manage project dependencies, even if Bower is bowing out. While they’re great at what they do, being the owner and a contributor to a package listed in either package directory presents some challenges for us and I hope the ones I’ve outlined here help save other some time and possible headache.

Do you know any other ways to handle the gotchas covered here? Or have stumbled into gotchas of your own? Let me know in the comments!