Authoring an Open Source Library for Angular

I recently created an open source library to be used in Angular (formerly called Angular 2) projects. There were a few lessons learned along the road to creating this library, so I thought it would be good to share what I have learned from the process.

The library that I created and that will be used as the subject for many of the examples in this post is angular2-esri4-components. It is a series of components that can be used to work with maps and other features from the ArcGIS API for JavaScript v4. You can see an example of it in action here.

Setting Up the Library

Naming Convention

First things first, every library needs a name. As the name of Angular itself has been in flux over the last few months so has the naming convention for libraries written for it.

Initially, most libraries were adopting a name prefixed with “angular2-” or “ng2-”. Now that Angular 2 is no more and it is simply called Angular you are starting to see new libraries take on name prefixes like “angular-”, “ng-”, or even “ngx-” (seriously, Angular 4.0 now has a release candidate and Angular 5.0 will be here before we know it!). When I started angular2-esri4-components Angular 2 was still a thing hence the “angular2-” prefix.

package.json

Once you have picked a name for your library it is time to start setting up your project directory. To be able to publish to NPM you are going to need a package.json file. To create and initialize one execute the following command from the root of your new project directory:

npm init

You will be asked a few questions here about things like the name of your library and what kind of license you want to use. Don’t worry too much about this because this just sets up your package.json file and you can change any of the values later.

One thing to note here, though, is to make sure that you include an open source license like MIT (used on Angular) or Apache License 2.0. Without one of these licenses folks are technically not supposed to use your library, so that will probably rain a bit on your adoption parade.

dependencies vs. devDependencies vs. peerDependencies

Okay, how often do we write anything anymore that doesn’t rely on third party libraries? The answer is almost never. If you take a look at your node_modules folder even on a small project with just a handful of dependencies, I guarantee you that you will see a lot more there than you might expect. That being said, as you add other modules as dependencies to your library it is important to place them in the appropriate section of your package.json file.

The main things to remember here are that:

  • dependencies is for modules that will also be installed for anyone using your library such as @types/ modules that you don’t expect users would already have
  • peerDependencies is for modules that you expect users will already have (i.e. Angular) but you want warn them if they are missing
  • devDependencies is for modules that are just for you to use when developing your library

If you want a more thorough description check out the write-up by Ciro Santilli on Stack Overflow.

Build

Once you have some dependencies in place and some code writen, the next thing that you might concern yourself with is the build process preparing your project for distribution.

Compile with the Angular Compiler

More than likely your Angular library is going to be written in TypeScript. With that in mind, you might think that tsc would be a good choice for compiling your .ts files into .js. Well, you would be wrong.

There has been a big emphasis on Ahead-of-Time (AOT) compilation in the Angular world as of late and many apps are taking advantage of this. To allow your library to be used in a project that is utilizing AOT you should use the ngc command to compile your TypeScript. It is a utility that comes with @angular/compiler-cli and while compiling your TypeScript files will also create some metadata files that will help Angular work with your compiled code. You can read more about preparing your project for AOT here.

To use it you will need to add the following to your package.json file:

"devDependencies": {
"@angular/compiler": "^2.3.1",
"@angular/compiler-cli": "^2.3.1"
}

You will still put the configuration for your TypeScript compilation into your tsconfig.json file, but you can have an additional section called angularCompilerOptions that is just for the Angular compiler.

You might also want to add the following to your .gitignore file:

*.ngsummary.json
*.ngfactory.ts
*.metadata.json

These files are generated by the Angular Compiler and, therefore, do not need to be included in your Git repo. Including them will only muddy up your commit history, making it difficult to see what actual source code changes have been made.

Bundling and Minification

Because, come on! You want to be a good citizen, right?

I like to use rollup.js for bundling because it is so simple to configure and it seems to create the smallest bundle around. However, using other technologies like webpack are just fine, as well. To use rollup.js you’ll need to add a rollup.config.js similar to the one from angular2-esri4-components:

Then, for minification, I like to use an oldie but goodie, uglify-js. With the uglify-js module in place and a cleanup utility like rimraf the entire build process can look like this:

Notice the addition of the prepublish script, as well. This will execute any scripts that you want run prior to publishing your library to NPM. In this case, we will execute the build.

Finishing Touches on package.json

The last thing that needs to happen in the package.json is to prepare the library for import into other projects and expose the types.

"main": "bundles/angular2-esri4.umd.js",
"module": "index.js",
"typings": "index.d.ts",

Publishing to NPM

Next you will need to get your library out to where other developers are able to use it. That means publishing it to NPM.

The first step here is to create an NPM user account and add it to the .npmrc file on your machine. You can do this by executing the following command:

npm adduser

If you already have an NPM user account this will allow you to verify the account and add it to your .npmrc file. If you do not already have an account this will allow you to create one.

Once your NPM user account is registered locally you are ready to publish your library to NPM. You can do so by executing the following command:

npm publish

Updating and Maintaining Your Library

Making that initial release is rarely the end of the road in the life of an open source library. There usually will be issues reported by developers that decide to give your library a spin and feature enhancements that help bring your library to the next level.

As you continue development on your library you will probably want to try things out before you publish your changes to NPM. There are a couple of ways that you can do this.

npm link

The first method that I would like to discuss is creating a global symlink to the package folder for your library that can be used by other projects in your computer. To do this you will need to run the following command from the root folder of your library:

npm link

This will execute the prepublish script that was mentioned earlier to prepare your library for use and then create the global symlink to your library’s project folder.

You can then use your library in another local project by creating a symlink from the other project to the global symlink for your library. The way that this is done is by executing a command with the following structure from another project folder:

npm link [<@scope>/]<pkg>[@<version>]

Running npm link can be a really handy tool as it allows you to continue to develop on your library and have your changes immediately available to other projects that you have created a symlink to your library for.

Note: As of the writing of this blog post there is an issue with using npm link with projects using the Angular CLI (currently at v1.0.0-rc.1). Projects using the Angular CLI seem to be unable to detect the metadata.json files and, therefore, fail when compiling the project. A good alternative while this is an issue is to use npm pack.

npm pack

Another way that you can use your updated library before publishing updates is to create a tarball from your package that can be installed in other projects. You can do this by executing the following command from your library’s root folder:

npm pack

This will again execute the prepublsih script and place the contents of your the library’s build into a tarball file in the root of your project. You can then install this in another project by running the following command from that project’s folder:

npm install <tarball file>

Versioning NPM package

Once you have tested out your changes and are ready to publish a new version of your library, you will need to bump its version number. To do this you can run the following command providing the appropriate argument describing how you would like the version number to be bumped:

npm version [<newversion> | major | minor | patch]

This will set the new version number in the package.json and create a commit and tag in the local git repo representing the new version.

CHANGELOG.md

As you are making changes to your library, it is really helpful for developers who are keeping up-to-date with your library for you to keep a log of your changes. You can do this in a CHANGELOG.md file. For each published update to your library it is a good idea to add a section to this file with the following information:

  • The new version number
  • Any new features (if there are any)
  • Any bug fixes (if there are any)
  • Any breaking changes (if there are any)

Contributing Guidelines

As you are plugging away at developing your library, you may hope that other interested developers might reach out and offer you a hand. If this is the case it can be helpful to provide them with a guide that walks them through how they can contribute to your project. One of the best examples that I have found of a Contributing Guide was written by Kent C. Dodds and can be found at:

Unit Tests

Including unit tests in your library does a couple of things for you. First of all it helps you maintain a quality code base (obviously!). The not so obvious part is that it helps other developers that might be interested in contributing to your project better understand what the different areas of your library are intended to do. It can act as a kind of documentation for the library and, along with a contributing guideline, can be one of the most useful tools for other developers when contributing to your library.

Resources

There were a number of resources that I took advantage of when putting together this library. Below are some of the notable ones that I found most helpful: