banner



How To Create Angular Component Library

Blog

Let's see how reuse our components in different projects with Angular libraries

Creating Angular components libraries

Wednesday, January 08, 2020

It often happens we need to solve a problem already solved in a previous project using a simple copy and paste of the code. This is a fast and easy solution, but it may cause secondary effects, the worst of whom is the discovery of a bug that needs to be corrected in all projects where we passed the code. What if I want to add new functionality? Should I propagate it all over?

In all Angular projects I worked on, it was always necessary to create a component able to pick up data and show them in table format. Why don't we make this component usable for more than one project? Angular gives us this opportunity withAngular Library. In my previous article, I showed you how to create a component able to display data in table format and that allows the drag and drop of columns: let's make this component reusable in all our projects with a library!

From the AngularCLI we launch following commands:

ng new BlexinLibrary

Regarding the creation of a library, the official Angular documentation indicates to set the flag--create-application to false to indicate to the CLI it does not have to create an initial application but only an empty workspace. This is not the solution I choose, nor the one I prefer because it makes it difficult to make the debug of the library.
I suggest you create a classical Angular application working as a host and develop the library inside it so that you can test it before the release. In the project root folder, let's launch the command to create a library:

ng generate library DataTable

Note that the Angular CLI created a project folder; inside it, we can find a folder with the name of the library (Data Table). In the sub-folder data-table/src, we find a folderlib, which contains files that compose the project (components, services, modules, etc.), together with a file public-api.ts that declares what we want to make available inside our library.

/* * Public API Surface of data-table */    export * from './lib/data-table.service'; export * from './lib/data-table.component'; export * from './lib/data-table.module';          

We find out that in the library, a component, a service, and a module have already been created. The configuration file of the whole workspace, angular.json, is updated with a newlibrary-type project, which has the name we choose during the creation of the library.

{  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",  "version": 1,  "newProjectRoot": "projects",  "projects": {    "BlexinLibrary": {      "root": "",      "sourceRoot": "src",      "projectType": "application",      "prefix": "app",      ...    },    "BlexinLibrary-e2e": {      "root": "e2e/",      "projectType": "application",      "prefix": "",      ...    },    "DataTable": {      "root": "projects/data-table",      "sourceRoot": "projects/data-table/src",      "projectType": "library",      "prefix": "lib",      "architect": {        "build": {          "builder": "@angular-devkit/build-ng-packagr:build",          "options": {            "tsConfig": "projects/data-table/tsconfig.lib.json",            "project": "projects/data-table/ng-package.json"          }        },          

Now we can proceed with writing the code as in a standard Angular project. Taking the cue from my previous article, we delete the file that created the CLI and leave the data-table.component.ts  and the data-table.module.ts , and we move on to the construction of the component.

In the previous article, the table was not an independent component, but it was part of the app.component: therefore, we need to extract the component data-table from the app.component.
Looking at the template, we find that the data-table basically operates on two data structures:columns androws. Both these data structures must be supplied from library users, becoming ourInput. The .ts file of our component will be:

import { Component, Input } from '@angular/core';    @Component({  selector: 'blx-data-table',  templateUrl: './data-table.component.html',  styleUrls: ['./data-table.component.css'] }) export class DataTableComponent {  @Input() columns: string[];  @Input() rows: any[];     constructor() { } }          

We modify the selector fromlib-DataTable toblx-data-table, and we modify the prefix in the file tslint.json:

{  "extends": "../../tslint.json",  "rules": {    "directive-selector": [      true,      "attribute",      "blx",      "camelCase"    ],    "component-selector": [      true,      "element",      "blx",      "kebab-case"    ]  } }          

You can see below the template of our component:

<div class="p-5 m-5">  <div class="p-5 m-5">  <div class="table-responsive table-container">    <table class="table">      <thead class="thead-dark">        <tr dragula="table_columns" [(dragulaModel)]="columns">          <th *ngFor="let column of columns">            {{column}}          </th>        </tr>      </thead>      <tbody>        <tr *ngFor="let row of rows">          <td *ngFor="let column of columns">            {{row[column]}}          </td>        </tr>      </tbody>    </table>  </div> </div>          

The external library we are using for the drag&drop needs some CSS classes to show the desired effect. In the previous project, I put these classes in thestyle.css. Now I don't want anyone importing the library to have to worry about adding such classes to his/her project: they must be present in the library.
We include them in the filedata-table.component.css.

As I wrote, the filepublic_api.ts allows us to define what our users will see in the library. We must modify it to adjust it to the previously made service cancellation.

export * from './lib/data-table.component'; export * from './lib/data-table.module';          

The componentdata-table requires some external dependencies:ng2-dragula (drag&drop management) andbootstrap (CSS classes). We need to inform those who install the library that, to guarantee the right functioning, the addition of these dependencies to their project is needed. We modify then the filepackage.json in the data-table folder, adding to it the section peerDependencies .

{  "name": "data-table",  "version": "0.0.1",  "peerDependencies": {    "@angular/common": "^7.0.0",    "@angular/core": "^7.0.0",    "bootstrap": "^4.3.1",    "ng2-dragula": "^2.1.1"  } }          

Before the publication, we must be sure that everything is working fine. The initial choice to create an Angular project and not an empty workspace now gives us a significant advantage: to test the library, we only need to import its module in our app.module and use the component through the selector. This is how ourapp.component.html becomes:

<div style="text-align:center">  <h1>    Welcome to {{ title }}!  </h1> </div> <blx-data-table [columns]="columns" [rows]="rows"></blx-data-table>          

where columns and rows are defined in app.component.ts  and then passed in input to thedata-table. Before we can launch our application, we need to install both dependencies in our library (with instructionsnpm install ng2-dragula andnpm install bootstrap), add"node_modules/bootstrap/dist/css/bootstrap.css" among the styles of ourangular.json and in the end add(window as any).global = window; in thepolyfills.ts file, as suggested in the Dragula documentation.

We launch then the application withng serve

As we verified that everything is working fine, we can distribute it. Let's compile the library and add the name of the library to the build command:

ng build DataTable

When we finish compiling, the library will be available in the dist folder.

How to use the newly created library

We have two options: we can import it in a new project collecting it form its dist folder, or we can make it available together with its updates using the same ecosystem chosen by Angular: npm.
Let's create a new Angular project:

ng new demo-with-lib

Inside the structure of the just created project, we create a new lib folder, where we copy the folder containing the result of the build of the library. I can then install it with the command:

npm i ./libs/data-table

Now we also add the dependencies required for the right functioning and import the moduleDataTableModule in the app.module.ts to use the exposed component.

import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { DataTableModule } from 'data-table'; import { AppComponent } from './app.component';    @NgModule({  declarations: [    AppComponent  ],  imports: [    BrowserModule,    DataTableModule  ],  providers: [],  bootstrap: [AppComponent] }) export class AppModule { }          

We position the component with the proper tagblx-data-table in theapp.component.ts providing expected inputs:

<div class="text-center">  <h1>    Welcome to {{ title }}!  </h1> </div> <blx-data-table [columns]="columns" [rows]="rows"> </blx-data-table>          

Let's launch the application and verify that is working fine.

We have made progress: we can reuse the component everywhere we want. Actually, we have used the copy and paste again: not of the source code, but of the library distribution folder. What if we want other members of a team to use the library, providing them with a simple tool to follow its updates? What if I want to make it public, that's to say permit anybody all over the world to install it via npm?

At the address https://docs.npmjs.com/creating-and-publishing-private-packages , is available an official tutorial to publish a package on a public npm registry. We will follow a different path offered by GitHub over the past few months.

GitHub gives the chance to create our own repository thanks toGitHub Packages, where you can publish and distribute your library in private or public mode.

How to publish on GitHub Packages

In order to publish, install, and eventually delete a package from GitHub Packages, an access token is required. There are two ways to obtain one: using the personal Access Token with your username to authenticate on GitHub or using a GITHUB_TOKEN to authenticate on GitHub Actions.

I choose the personal access token. We need then to modify the file ~/.npmrc  and insert the following line:

//npm.pkg.github.com/:_authToken=TOKEN

and substitute "TOKEN" with your own token.

Now we need to create the file .npmrc  in the same folder where the package.json is present and insert the following line:

registry=https://npm.pkg.github.com/OWNER

{         "name": "@accountgit/packagename",      "version": "2.0.1",      "peerDependencies": {        "@angular/common": "^8.2.14",        "@angular/core": "^8.2.14",        "bootstrap": "^4.3.1",        "ng2-dragula": "^2.1.1",        ...      },      "repository": {        "type": "git",        "url": "git+https://github.com/accountgit/reponame.git"      }     }          

We can then publish it with the command:

$ npm publish

After the publication, we can find in our repository that the section package is populated, and it brings us a more detailed section on what has been published.

How to modify the library

How can we manage the normal life cycle of our library, such as the correction of bugs, the addition of new features, a substantial modification that makes it incompatible with previous versions? All this, allowing anyone who has installed the library to update the package in their projects safely.

It's time to manage the versioning of my library. In the package.json we find the fieldversion, which defines the current version of the library. Using Semantic Version, we can clarify to those who use our library, which versions of our package can be installed safely, that is with no need to modify your code to integrate our library.
In this way, the version field contains a string formatted as "major.minor.patch", where every block corresponds to a non-negative whole number. In the article by Antonio , you can find more information.

Let's come back to our modification: to solve our bugs, we must modify thepatch of our version number, increasing by one. After adding a new functionality compatible with the current code, we need likewise to update minor, increasing it by one.Major will be incremented when we make modifications that affect the API, as, in our case, the modification of the name of an INPUT property. As soon as we finish the modifications, we can publish the updated package, using the same command used before$ npm publish.

Regarding the clients using our library, following the commandnpm install, its update (get with the commandnpm update) depends on the configuration of the dependency in the package.json.

We have two possible configurations:

  • "name_of_package": "~major.minor.patch"
  • "name_of_package": "^major.minor.patch"

If you choose the first option, you download the package with the same major and minor, but with the last patch version available If you choose the second option, you download the package with the same major, but with the last minor and patch available version.

Using the tilde(~), we are indicating we want to keep our package except in case of a bug fix. Using thecaret(^), we are indicating we want to update the package even in case of addition of new functionalities compatible with the currently installed version.

Note that if you still didn't install the package,npm install will have the same effect ofnpm update, that is, it will find the last updated package, based on given guidelines in the package.json. It will be different if we already install packages locally: in this case, thenpm install is not enough to update the package, because the local one already follows given guidelines, then you have to usenpm update.

In the end, it is possible to specify if you want to install the last available version, independently of the one installed with the command$ npm install packagename@latest –save. You can then obtain the update of the package.json with the version number of the downloaded package.

The code is available on github to the following address: https://github.com/AARNOLD87/AngularLibrary

See you at the next article!

How To Create Angular Component Library

Source: https://blexin.com/en/blog-en/creating-angular-components-libraries/

Posted by: powersidowed.blogspot.com

0 Response to "How To Create Angular Component Library"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel