Skip to content

Instantly share code, notes, and snippets.

@vvo
Last active March 8, 2017 22:12
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vvo/84a94cfc0f94c91ea6b6 to your computer and use it in GitHub Desktop.
Save vvo/84a94cfc0f94c91ea6b6 to your computer and use it in GitHub Desktop.
About authoring frontend libraries, building them, publishing to npm and dependencies

You have a nice library published on npm but asking yourselve if you should declare your dependencies as lodash: "3.10.0" (known as "pin" a dependency) or lodash: "^3.10.0"?

As library authors we should not pin dependencies but ask our users to do use npm shrinkwrap in their own app.

Here's why:

Pinning dependencies will result in duplicated code and modules in builds

If you pin your dependencies the issue is that anyone using your module will may not benefit from shared dependencies. If your module user has lodash: "^3.11.0" then since you declared your library to use lodash: "3.10.0", there will be code duplication inside his build (or conflicts).

Of course even when using ^hats, if the major (Y.x.x) version is different between two libraries then you will get a different module.

But, with pinning it's a lot worse: As soon as the patch (x.x.Y) version of lodash will be different between your library lodash dependency and your user app lodash dependency, you will have duplicated lodash in your build!

Example of dependency pinning going wrong (duplicated code in the output): https://gist.github.com/vvo/5a2ec06c2752c6b35e48

It only protects you from bad minor upgrades on first level

When your library is used as a dependency. Depending on the moment a user does npm install super-pinned-library, it could work in January but fail in December.

You can protect your own library from bad minor upgrades of a first level dependency but all other sublevels dependencies could still fail given the way they are declared and the moment they are installed.

It's not even sufficient when generating a build for your library

If your library as a dist/, published on jsdelivr.com or cdnjs.com then to pin your dependencies will not be enough. Because sub dependencies install state will depend on the day/state of the person/system building your project.

For example even if you did not change any of your nicely pinned dependencies, when building your project in March you will get dependencies at a different state than when building in November.

A pattern I use for my frontend libraries that both needs to be on npm and builded somewhere is this:

  • package.json has dependencies using ^hats (avoid code duplication when used as a dependency in a build system)
  • npm-shrinkwrap.json generated for the library (npm shrinkwrap)
  • .npmignore has npm-shrinkwrap.json in it, because you do not want your npm users to use your npm-shrinkwrap.json, they will have their own
  • build process do npm install and npm run build and then you have a reproducible build that is not time dependent, only dependent of the actual code of your library

With all this, should you still pin your npm dependencies? I would say no.

Last, npm package for example has all his dependencies in github, but that's a road you can avoid with npm shrinkwrap even if it's still a bit buggy right now.

@bevacqua
Copy link

bevacqua commented Oct 9, 2015

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment