The ultimate guide to set up your Angular library project

Automated code formatting with Prettier & Husky, test coverage reports, deployed showcase and fully automated releases with Travis CI for your Angular library

Kevin Kreuzer
Jun 11, 2019 · 18 min read

Angular is such an awesome framework, and we all love it 😍 It’s a complete tool kit that helps us build amazing stuff.

And it gets even better. Angular also contains a great community. A community which continually grows and pushes Angular forward.

Therefore, it is not surprising that the framework has a massive ecosystem around it. From useful services to fully featured component libraries, the Angular ecosystem provides it all.

So nothing is impossible. Do you have an idea for a cool angular library? Then go on, participate, implement your library, and share it with the world! 🌎

What you will learn 👨‍🎓

The newest Angular versions already have excellent support for the creation of libraries. However, developing and testing is only one part when creating your Angular library. Another part is shipping the artifact. 🚢

Delivering software requires some steps; we need to run tests, build our artifact, publish it, update the project with the release assets, and document the release.

As software engineers, we tend to automate recurring manual steps. So that’s what we are going to do here. Automating the release of an Angular library is not an easy task. Especially not, if you not only want to automate the release but also the handling of the release assets.

This blog post aspires to give you an ultimate guide on a fully automated and complete setup for your Angular library. It covers many topics and may, therefore, be best read in multiple goes.

So, without further ado, let’s grep a ☕ and jump right into it!

Table of contents

Getting started — create your Angular library

  • Generate your Angular library
  • Show what you got — generate a showcase
  • A simple alert library
  • Implement a showcase

Fully automated releases — the ultimate setup

  • The overall idea
  • Linting & Code style
  • Testing & Coverage
  • Build & publish the showcase
  • Publish your library — handle the release assets

Further assets

  • Code of conduct
  • Contributing instructions

Conclusion

  • Summary
  • Working example

Generate your Angular library 📚

Imagine we work in a company where different project teams work on different SPA’s. At the after work 🍺 we tell our colleagues about our impressive alerting library we just implemented today.

They are enthusiastic about our alerting library and want to use it as well. Furthermore, they even think it would be great to make it Open Source so that everybody can benefit from our work. What a great thought!

So the next day we enter the office and start with our library which we call .

The first thing we need to do is to create our library project. We open up a terminal of our choice and type the following command which uses the Angular CLI to create a new folder with the basic setup.

In case you have not installed the Angular CLI yet. Go ahead, open a terminal and type

ng new ng-simple-alert --create-application=false

We explicitly set the flag to false. Without this flag, the command would generate an application with the same name as the folder, which is not what we want. We want to create a library, not an application.

The result of the execution above is an empty repository. We will now change to this directory and generate our actual library into it.

cd ng-simple-alert
ng generate library ng-simple-alert

We now end up with a library project which is set up under .

Show what you got — generate a showcase 🎦

It's a good practice to not only implement your library but also a showcase. The showcase uses the library and gives you an impression of the libraries behavior when a consumer uses it.

In other words; the showcase kinda is your first consumer.

ng generate application ng-alert-showcase

We end up with the following folder structure.

projects
|__ng-simple-alert
|__ng-simple-alert-showcase
|__ng-simple-alert-e2e

We successfully created a library project called and a corresponding showcase called .

A simple alert library 🚨

Excellent. We now have our project setup; let’s implement the library. The goal of our library is to provide a service and a component which can be used to display some simple alerts.

Let’s first implement the service.

Our service exposes the different alert methods and streams them into the .

Next, let’s create the component which actually displays the messages.

This component just displays a message once the emits new messages. If we click on the close button the close subject streams false. The is merged into the . So every time the emits false, the messages will disappear.

That’s it. Our library is ready. 💪

Your first consumer — implementing a showcase

So let’s change in our project and implement a showcase where we use our library.

So we import the library and use the service to display some messages. We can then also start up the showcase with .

Neat! Showcase and library are ready, let’s now jump to the advanced stuff. Which is the whole setup for automated releases!

One of the most repetitive and annoying parts when maintaining an Open Source project is to release fixes and features manually. To automate tasks, we need the help of some continuous integration server.

There are different good CI servers out there, but we are going to use Travis because it is compelling, easy to use, and has fantastic integration with GitHub.

The overall idea 👨‍🎓

Let’s have a look at the following graphic which illustrates the overall concept.

  • Every time we merge a commit to our master branch our library is linted.
  • Next, the tests are executed and a coverage report is generated. This coverage report is then uploaded to a reporting tool called .
  • The stage is responsible for building our showcase and deploy it to .
  • The stage builds our library and publishes it to . But that’s not all, it also commits the release assets back to our repository.

Each step requires some setup and configuration. Let’s see how to configure each step to build the concept illustrated above.

Follow me on Twitter or medium to get notified about my newest blog posts!🐥

This part of our library setup is all about code quality. The Angular CLI provides us with the command, which lints our project based on a specific set of rules.

The linting task checks if our project contains any linting errors. However, we still need to fix them manually. Wouldn’t it be cool to have them automatically fixed on each commit?

Opinionated Codestyle with Husky 🐶 and Prettier

How often did you hear developers arguing about whether to use tabs or spaces, whether to use single quotes or double quotes? We all have different opinions when it comes to code style and formatting. Of course we have, after all, we are passionate about code.❤️

It’s one thing to find some rules you agree on; another thing is to apply those rules in your project. In my opinion, this is especially crucial in Open Source projects.

In an OpenSource project, you may get contributors around the globe, with different opinions and different setups. So it is essential to have an automated way to adjust changes based on your opinionated coding guidelines.

A pretty neat way to achieve this is by using .

Prettier is a command line tool that auto-formats your Typescript code.

Prettier alone is already cool, but its true power comes when we automatically run it in a pre-commit hook. Therefore we are going to use in combination with a tool called 🐶

is a tool that simplifies us the work with Git hooks.

is a tool that allows us to run linters against staged files.

npm i -D husky prettier lint-staged

Ok. we got us . But we still need to tell him what to do. Both, and can be configured inside our .

"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
}
,
"lint-staged": {
"projects/**/*.ts": [
"prettier --write",
"git add"
]
}

With this configuration, steps in and executes the command once we commit files. then takes all the files under , runs prettier on it and adds them to .

When runs, it looks for configs in the form of a file. The allows us to configure our desired formatting rules.

{
"printWidth": 120,
"singleQuote": true,
"tabWidth": 2
}

First up we also add a script which prints all the files that will be affected by . will then actually write the files.

"format:check": "prettier --list-different 'projects/**/*.ts'",
"format:write": "prettier --write 'projects/**/*.ts'",

It’s always important that you initially once run the command and commit and push the affected files.

Why do we even lint then?

That’s a reasonable question. Why to lint, if prettier already takes care of the formatting?

Well, it's not needed for regular commits.

But, nowadays, most repository services like GitHub or Stash allow you to edit and commit a file over a web interface quickly. In those cases, prettier will not run and there might be unexpected errors which can be prevented by linting our project.

Like this blogpost? Share it on twitter! 🐦

Write unit tests ✍️

An essential aspect of every successful software project is testing. There are different forms of testing. Unit testing is by far the most important form of testing.

Unit tests ensure that our functions work the way we expected. They also help us guarantee that refactorings or changes don’t break existing features.

Let’s go ahead and test our .

We use the beforeEach hook to create us a (system under test). We then use jasmines methods to test our methods.

By default, the Angular CLI provides us the command which we can execute to run our test. But what about coverage?

Generating a coverage report 🕵️

The command accepts a flag named which runs the test and writes the coverage report to a directory in our project .

It’s a good practice to add a command to our .

"test:lib-coverage": "ng test ng-alert --code-coverage --watch=false",

Nice — with this setup we can run tests locally and write a local coverage report. But this does not help us that much as it's only generated on our build system. Let’s visualize the coverage and integrate it with GitHub.

Codecov

Coverage reports on our build system can be picked up and uploaded to a coverage tool named .

Codecov is a tool that provides highly integrated tools to group, merge, archive, and compare coverage reports.

provides us with a nice library which we can install with the following command:

npm i -D codecov

We also add a new task called . As the name indicates, this task is responsible for uploading our coverage reports to Codecov.

"report-coverage:lib": "cat ./coverage/ng-alert/lcov.info | codecov",

Enable Travis to upload reports to Codecov

As mentioned before we are going to use Travis as a build system. After signing up to codecov.io with our GitHub account, we can hop over to Travis and select the repository for which we want to activate Codecov.

Codecov provides us with a token which we can copy and add an environment variable under our project settings in Travis. The token should be added under the key: .

It’s always nice to have a deployed demo version of your library. GitHub Pages is the perfect match for hosting static files. It’s easy to use and integrates well with our GitHub repository.

Before we automate the deployment of GitHub pages, let’s first structure our build scripts in our .

"build": "npm run build:lib && npm run build:demo",
"build:lib": "npm run copy:readme && ng build ng-sortgrid",
"build:showcase": "ng build ng-alert-showcase --base-href='https://kreuzerk.github.io/ng-simple-alert/'",

We add a script to build our library project and a script to build our showcase. It is important that the script builds our showcase with the correct .

The for GitHub pages is

With those scripts, we are able to build our library for GitHub pages. But we also need an actual deploy step.

"publish:demo": "npx angular-cli-ghpages --dir=./dist/ng-alert-showcase",

This deploy step uses to download and execute the . The then takes care of uploading the passed in directory which is our showcase.

NPM — the node package manager 📦

We implemented our library, and we will also share it so that others can benefit from it. Even thought GitHub recently introduced a package registry, for the moment, still is the way to go.

Travis handles the publish. More on that later. The only prerequisite to publish a package to is an NPM account. To create your account you can go to npmjs.com and sign up.

README.md — the most important doc

Readmes are an important form of documentation. They document the purpose and the API of your library.

displays the which lies in the root directory of our project while uses the which lies in the library folder. In a nutshell, displays another than .

So we could maintain two readmes. However, that’s annoying and error prone. Therefore we are only going to maintain one, which is the one in our root directory. A pre-build step will then copy this to the library directory.

So let’s install a tool called .

npm i -D copyfiles

We also add a task which we use inside our task.

"copy:readme": "copyfiles ./README.md ./dist/ng-simple-alert",
"build:lib": "npm run copy:readme && ng build ng-simple-alert"

With these scripts, each library build also copies the from our root directory to our library folder.

Conventional commits

To get started, we need a convention which allows tools to interpret commit messages and automatically perform tasks. Conventional commit messages allow us to do precisely that.

The conventional commits specification is a common standard for adding human and machine readable meaning to commit messages

Furthermore, meaningful and well-structured commit messages make your project clearer and more accessible to new contributors and ease the forensic process of understanding what changed.

The following graphic explains how conventional commits work.

Having conventional commits does not only help in the forensic process of bug searching or understanding the history of your repository. Conventional commits are really useful because they can be interpreted by automation tools.

So it is really important that every contributor sticks to the commit message format. Therefore we use tools which will help us check the commit message format to be a valid conventional commit.

npm i -D @commitlint/cli @commitlint/config-conventional @commitlint/prompt

We install and the necessary tools. We then also configure them in our

"commitlint": {
"extends": [
"@commitlint/config-conventional"
]
}

As described above we want to call once somebody commits to our repository. So we already have installed. Let’s take advantage of that and use its hook.

"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"

So once we commit — runs and our commit message is checked to be a valid conventional commit.

With this setup, we automatically ensure that all commit messages are in a valid conventional commit format.

Semantic release CI

We talked about automated tools that can interpret your conventional commits to automate tasks. As mentioned before, the overall goal is to release packages based on the commit message automatically.

is a beautiful tool which does exactly that. To lower the barriers to getting started, provides us an awesome CLI to kickstart automatic releasing. Let’s take advantage of that and install the .

npm install -g semantic-release-cli

Once we globally installed the we change to our directory and run the following command.

cd ng-simple-alert
semantic-release-cli setup

The then takes us through the following steps. We simply need to enter our NPM and GitHub credentials.

The CLI also lets us choose the continuous integration server we want to use. In our case it’s Travis.

now adds tokens which are needed to publish our package to NPM and to commit release assets back to our repository. You find them under project settings in Travis. In a previous step, we already added our . So you should now see the following tokens.

semantic release for Angular

The CLI does a lot of things out of the box. But it was built as a generic tool which supports all sorts of libraries.

The reason we can not use the standard configurations is “release assets”.

Release assets

When we talk about release assets, we talk about all the files that are affected by the release. Those files are essential for documentation and comprehensibility of our repository. Thanks to them, visitors to our project can quickly grasp changes between releases.

To keep our repository comfort with the current release the following things should happen in on each release.

  • Update the
  • Tag the master branch with the release version
  • Update the version of our in the root directory as well as our in our library project.

To handle our release assets correctly we need to configure our semantic release.

Configure the semantic release for Angular

When building an Angular library, we encounter a special setup with a different folder structure. To handle this setup we need to add some custom configuration in the form of a for our semantic release.

The property tells which package we want to publish. In our case its the package under which is our library.

The section is used to tell the CLI in which order the different plugins should be executed. So let’s go through those steps.

  • First, the is used to analyze the commits. This tool can then decide which kind of release (minor, major, patch) is needed.
  • The plugin creates the release notes.
  • The plugin then uses those release notes and updates the .
  • The then bumps the version and publishes the library to .

Until here everything is quite standard and can also be applied to non-Angular libraries. The tricky part comes now when we want to synchronize the versions of our .

Synchronize package.json

The problem is, that we don’t have just one , but two. One in our project and one under . Both should be updated with the new version.

This is not so easy and does not provide an out of the box solution. But it provides us to a plugin called which allows us to run custom commands.

npm i -D @semantic-release/exec

So we can now configure custom commands which should be executed during the build. Let’s again have a look at the configuration.

We use the hook of the to execute the script defined in our .

"adjust-version": "npm-run-all adjust-version:*",    
"adjust-version:lib": "rjp projects/ng-simple-alert/package.json version $VERSION",
"adjust-version:main": "rjp package.json version $VERSION",

The uses a tool called to run all tasks with the same prefix.

First, it runs the task and then it also runs the task. Those tasks internally use a tool called which I wrote some time ago.

The simply overrides a property in a JSON file. In our case, we want to override the property with the newest released version.

Notice that we use the to access the newest release version. If you are curious on how this mechanism works I recommend you to check out my blog post about “Access variables in npm scripts”

When we execute those scripts, the new release version is written to our and to our .

Commit the release assets

Last but not least, we need to add those files to git and commit them back to . We need to add all the files we adjusted during the release, which are the following ones:

It is also important to use a specific commit message to not retrigger a build. A commit message that includes . is interpreted by Travis and no build will be executed.

Putting the Puzzle together

So far we talked a lot about Travis, automated releasing, coverage reports and GitHub pages. We already did a lot of setup and configuration.

Now it is finally time to put the single pieces of the puzzle together. So let’s add the glue, the !

The file allows us to configure our Travis build.

We simply add a to the root of our project.

Our Travis build is now nicely structured and contains the following stages.

  • Lint: the linting stage is quite self-explaining. It just runs and lints our project on possible issues.
  • Test: the test stage runs the library tests with coverage. The coverage reports are generated on Travis, they are then picked up the tasks and uploaded to .
  • build & publish showcase: this stage is responsible for dealing with the showcase. It first builds the showcase with the correct and then uses the pages provider from Travis to publish it to GitHub pages.
  • build & publish lib: this is probably the most important build step. It builds our library and publishes it to NPM.

Code of conduct

Open source should be accessible for everybody. Doesn’t matter the gender, the color, or other circumstances. We are all equal. Therefore it is important to add a to your project.

The code of conduct helps to welcome all people to contribute and pledges in return to value them as whole human beings and to foster an atmosphere of kindness, cooperation, and understanding.

If you want to know more about the code of conduct or get a concrete example of a then hop over to https://www.contributor-covenant.org/

Contributing instructions

Good software is mostly not written by one person, it’s written by a team or a group of people. People with different ideas and different ways of thinking.

In a nutshell, contributors are core to a library. Therefore you should make your project accessible for new contributors.

Add a to the root of your project and describe your project setup. Explain how they can locally set up the project and where they can get help if they get stuck.

Help them contribute to your project!

Summary

Angular is awesome. Besides its core, it's above all the community and the rich ecosystem around it. The Angular team itself appreciates the value the community is providing and therefore encourages us to build libraries. To do so, the CLI provides us with the tools to get started.

However, implementing the software is only one part of building an Angular library. Shipping is another part which requires a lot of manual steps.

There are a lot of great tools to support us in the automatization of those tasks. The automatization of the release process eases the work in community projects.

However, still, if we want to do it right, there are many things to think of. Especially when it comes to the release assets. In my opinion, it is important to have a clean setup and handle the release assets right.

I know its a lot, but believe me, once set up, it makes your life easier and your open source project more accessible to others and easier to maintain.

Working example

I know that we encountered a lot of aspects in this blog post. After all, it’s an ultimate guide 😉

If you are too lazy to go through all the steps you can easily star and fork the working example used in this blog post.

🧞‍ 🙏 Give some 👏🏻 by clicking multiple times on the button on the left side if you enjoyed this post.

Feel free to check out some of my other articles about frontend development.

Tomas Trajan thanks a lot for the review and the comments!

Angular In Depth

The place where advanced Angular concepts are explained

Thanks to Tomas Trajan

Kevin Kreuzer

Written by

Passionate freelance frontend engineer. ❤️ Always eager to learn, share and expand knowledge.

Angular In Depth

The place where advanced Angular concepts are explained

More From Medium

More from Angular In Depth

More from Angular In Depth

More from Angular In Depth

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade