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
- Code of conduct
- Contributing instructions
- 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
npm i -g angular-cli
ng new ng-simple-alert --create-application=false
We explicitly set the
--create-application flag to false. Without this flag, the
ng new 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.
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.
We successfully created a library project called
ng-simple-alert 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
alertMessage$ emits new messages. If we click on the close button the close subject streams false. The
close$ is merged into the
alertMessage$. So every time the
close$ 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
simple-alert-showcase 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
build & publish showcasestage is responsible for building our showcase and deploy it to
build & publish libstage builds our library and publishes it to
NPM. But that’s not all, it also commits the release assets back to our
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
ng lint 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
lint-staged in combination with a tool called
huskyis a tool that simplifies us the work with Git hooks.
lint-stagedis a tool that allows us to run linters against staged files.
npm i -D husky prettier lint-staged
Ok. we got us
Husky. But we still need to tell him what to do. Both,
lint-staged can be configured inside our
With this configuration,
Husky steps in and executes the
lint-staged command once we commit files.
lint-staged then takes all the
.ts files under
projects, runs prettier on it and adds them to
prettier runs, it looks for configs in the form of a
.prettierrc file. The
.prettierrc allows us to configure our desired formatting rules.
First up we also add a
format:check script which prints all the files that will be affected by
format:write 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
format:writecommand 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
sut (system under test). We then use jasmines
it methods to test our methods.
By default, the Angular CLI provides us the
ng test command which we can execute to run our test. But what about coverage?
Generating a coverage report 🕵️
ng test command accepts a flag named
--code-coverage which runs the test and writes the coverage report to a
coverage directory in our project
It’s a good practice to add a
test:lib-coverage 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.
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.
Codecov 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
report-coverage:lib. 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
build:lib script to build our library project and a
build:showcase script to build our showcase. It is important that the
build:showcase script builds our showcase with the correct
base-hreffor 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
npx to download and execute the
angular-cli-ghpages 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,
NPM still is the way to go.
Travis handles the publish. More on that later. The only prerequisite to publish a package to
NPM is an NPM account. To create your
NPM 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.
GitHub displays the
README.md which lies in the root directory of our project while
NPM uses the
README.md which lies in the library folder. In a nutshell,
GitHub displays another
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
README.md to the library directory.
So let’s install a tool called
npm i -D copyfiles
We also add a
copy:readme task which we use inside our
"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
README.md from our root directory to our library folder.
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
commitlint and the necessary tools. We then also configure them in our
As described above we want to call
commitlint once somebody commits to our repository. So we already have
husky installed. Let’s take advantage of that and use its
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
So once we commit —
commitlint 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.
semantic-release is a beautiful tool which does exactly that. To lower the barriers to getting started,
semantic-release 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
semantic-release-cli we change to our directory and run the following command.
semantic-release-cli 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.
semantic-release 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
CODECOV_TOKEN. So you should now see the following tokens.
semantic release for Angular
semantic-release 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”.
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
package.jsonin the root directory as well as our
package.jsonin 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
.releaserc for our semantic release.
pkgRoot property tells
semantic-release which package we want to publish. In our case its the package under
dist/ng-simple-alert which is our library.
plugin section is used to tell the
semantic-release CLI in which order the different plugins should be executed. So let’s go through those steps.
- First, the
@semantic-release/commit-analyzeris used to analyze the commits. This tool can then decide which kind of release (minor, major, patch) is needed.
@semantic-release/release-notes-generatorplugin creates the release notes.
@semantic-release/changelogplugin then uses those release notes and updates the
@semantic-release/npmthen 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
The problem is, that we don’t have just one
package.json, but two. One in our project
root and one under
projects/ng-simple-alert. Both should be updated with the new version.
This is not so easy and
semantic-release does not provide an out of the box solution. But it provides us to a plugin called
@semantic-release/exec 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
prepareCmd hook of the
@semantic-release/exec to execute the
adjust-version 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",
adjust-version uses a tool called
npm-run-all to run all tasks with the same prefix.
First, it runs the
adjust-version:lib task and then it also runs the
adjust-version:main task. Those tasks internally use a tool called
replace-json-property which I wrote some time ago.
CLI tool to replace a specific properties value with a new value in a JSON file. - kreuzerk/replace-json-property
replace-json-property simply overrides a property in a JSON file. In our case, we want to override the
version property with the newest released version.
Notice that we use the
$VERSION 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
package.json and to our
Commit the release assets
Last but not least, we need to add those files to git and commit them back to
GitHub. 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
[skip ci] 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
travis.ymlfile allows us to configure our Travis build.
We simply add a
.travis.yml 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
ng lintand 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
report-coverage:libtasks and uploaded to
- build & publish showcase: this stage is responsible for dealing with the showcase. It first builds the showcase with the correct
base-hrefand 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
CODE_OF_CONDUCT.md 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
CODE_OF_CONDUCT.md then hop over to https://www.contributor-covenant.org/
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.
CONTRIBUTING.md 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!
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.
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.
Contribute to kreuzerk/ng-simple-alert development by creating an account on GitHub.
🧞 🙏 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!