Building an Angular Library with the Angular CLI (version 6)

A library

Yay Angular 6 is out!!! The Angular CLI has also been updated to Version 6, many new fetaures have been added including the ability to easily create libraries. A unified format for creating an angular library has always been an issue, but with the new version of Angular 6, it’s now unified and easy.

We are going to be building an Angular library using the new API provided by the angular CLI. Let’s go!!!

Creating a project

Yes, we have to first create an angular project before creating a library. Before creating a new project make sure you’re on angular 6, you can verify by running

ng -version

The result should be something like this

Make sure you are on Angular version 6

else you can update to version 6 by running

npm install -g @angular/cli

Okay, let us create our project by running

ng new format-code-library

This would create the project and install the dependencies. Then move into the project directory by running

cd format-code-library

Creating the Library

We want to create our library by running,

ng generate library format-code

This command does the following

1. It creates our library with boilerplate code and all the relevent configurations in a projects folder at the root of the workspace.

2. It also updates the angular.json file with the necessary configurations for building and testing our library.

3. It installs the necessary packages for building our library

Quick Tip: Most times you would name your project the same name as you want your library, but when creating the library with the same name, Angular would throw an error that the project already exists on the workspace. Don’t give up yet, you can use the camel-case name and it would yield almost the same result, of course without errors this time, the difference would just be the naming in the angular.json file.

Talk is cheap let’s write code

Opening the project folder in projects/format-code, we would find some interesting files,

- ng-package.json — the configuration file used by ng-packagr to build our project

- package.json — Here we set details about our library, such as dependencies, peer-dependencies, e.t.c

- src/public-api/ts — This is our library’s entry point. All the files we need to be accessible in our compiled library should be exported here

- src/lib — where our code lies

In the src/lib sub-folder, we would find some boilerplate files generated by the CLI. First, we would delete format-code.component.css, format-code.service.ts and format-code.service.spec.ts and remove this line from src/public-api.ts since we would no longer be needing them

export * from './lib/format-code.service';

Now let’s open up format-code.component.ts and paste this in:

import { Component, OnInit, Input, Renderer2, ElementRef } from '@angular/core';
@Component({
selector: 'format-code',
template: `
<div>
<ng-content></ng-content>
</div>
`,
styles: [`
div {
padding: 20px;
margin: 10px auto;
box-shadow: 1px 3px 10px 1px rgba(0, 0, 0, 0.3);
border-radius: 7px;
}
`]
})
export class FormatCodeComponent implements OnInit {
@Input() color: string = "rgb(42,100,250)"
@Input() bgColor: string = "rgba(0,0,30,0.9)"
@Input() font: string = "consolas, monospace"
constructor(private renderer: Renderer2, private el: ElementRef) { }
ngOnInit() {
this.renderer.setStyle(this.el.nativeElement.firstElementChild, 'color', this.color)
this.renderer.setStyle(this.el.nativeElement.firstElementChild, 'backgroundColor', this.bgColor)
this.renderer.setStyle(this.el.nativeElement.firstElementChild, 'font-family', this.font)
}
}

This creates a simple component called format-code that accepts three input values color , bgColor and font with default values and sets them on the component. Viola, we are done!!!

Building and Trying out our new library

To try out our new library, we would first need to build it. Building our library is as easy as running

ng build format-code --prod

This command builds our library and places the build in dist/format-code folder.

To try out the library, we would just import it into the default project at src/ . Just open up src/app/app.module.ts and import the library like so:

import FormatCodeModule from 'format-code'
NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
FormatCodeModule
],
providers: [],
bootstrap: [AppComponent]
})

Now insert this into src/app/app.component.ts :

<format-code>
Lorem ipsum dolor, sit amet consectetur adipisicing elit. Magnam impedit architecto quibusdam nostrum cum vel porro in aliquid harum incidunt, dicta reprehenderit nulla, ipsum fugiat illo qui, error veniam obcaecati.
</format-code>

it would render something of this sort

Publishing our library

Most times we would need other files such as a README, a LICENSE file, a CHANGELOG and so on, but when we build our library, only the README is copied to the dist/format-code folder. To solve this issue, let’s create a scripts folder in the root, and a copy-artifacts.js file in it. In this file we would copy out the stuff we need

const fs = require('fs')
const path = require('path')
const artifacts = ['README.md', 'CHANGELOG.md', 'LICENSE.md']
artifacts.forEach(file => {
let fromPath = path.resolve(__dirname, '..', 'projects/format-code/', file)
let destPath = path.resolve(__dirname, '..', 'dist/format-code/', file)
fs.readFile(fromPath, 'utf-8', (err, data) => {
if (err) {
console.log('An error occured:', err)
return
}
fs.writeFile(destPath, data, (err) => {
if (err) {
console.log('An error occured:', err)
return
}
console.log(`Copied ${file}:`)
})
})
})

This code copies the artifacts specified in the artifacts array to the dist/format-code folder

We just need to run this after building the library. We can modify the root package.json to make this process easier, open up the file and add a script called postbuild: node scripts/copy-artifcts.js and then edit the build script to build our package. The script should look like this

"scripts": {
"ng": "ng”,
"start": "ng serve",
"build": "ng build format-code",
"postbuild": "node scripts/copy-artifacts.js",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
},

With this, once we run,

npm run build

Both commands would run. Life is easier. To publish to NPM, we would run the following:

cd dist/format-code
npm login
npm publish

That’s all!

TIP:

You can edit the defaultProject option in the angular.json file with the name of your library, so next time when you want to build you can just run

ng build --prod

Go build something!!!