Home

Awesome

ng2-testable-lib

Building an Angular5 library with @angular/cli and ng-packagr

This project takes the developer through the process of building an environment to create, test and build an Angular5 library based on the ng-packaged repository.

Set up an Angular CLI project

Get benefits of @angular/cli :

ng new library-generator

Create the sample library

Create the library folder on the top of the angular app.

Create the library module sample/src/sample.module.ts

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';

@NgModule({
  imports: [
    CommonModule
  ],
  declarations: [],
  providers: [],
  exports: []
})
export class SampleModule { }

Create the library entry point sample/public_api.ts

export * from './src/sample.module'

Register the library

Open .angular-cli.json to add the app that describe the library (after the default app) :

{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "project": {
    "name": "ng-2-testable-lib"
  },
  "apps": [
    {
      // default app
    },
    {
      "root": "sample",
      "appRoot": "src",
      "name": "sample",
      "outDir": "dist/sample",
      "assets": [
        "assets"
      ],
      "index": "../src/index.html",
      "main": "../src/main.ts",
      "polyfills": "../src/polyfills.ts",
      "test": "test.ts",
      "tsconfig": "../src/tsconfig.app.json",
      "testTsconfig": "tsconfig.spec.json",
      "prefix": "",
      "styles": [
        "../src/styles.css"
      ],
      "scripts": [],
      "environmentSource": "../src/environments/environment.ts",
      "environments": {
        "dev": "../src/environments/environment.ts",
        "prod": "../src/environments/environment.prod.ts"
      }
    }
  ],
  // ...
}

Open tsconfig.json to map the library path :

{
  // ...
  "angularCompilerOptions": {
    "paths": {
      "sample": [ "../sample/public_api.ts" ]
    }
  },
  "compilerOptions": {
    // ...
    "paths": {
      "sample": ["../sample/public_api.ts"]
    }
  }
}

Relaunch vscode to ensure that the new typescript configuration is available.

Import the sample.module in src/app/app.module.ts. You should have benefits of vscode intellisense.

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { SampleModule } from "sample";

import { AppComponent } from './app.component';


@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    SampleModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Copy src/app/test.ts to sample/test.ts.

Copy src/app/tsconfig.spec.ts to sample/tsconfig.spec.ts.

This files will be required for running the sample library unit tests.

Ensure that everything is fine :

ng test

Create the sample-component

Use the --app parameter to specify the app that use it :

ng g component sample --app=sample

Take a look to the sample.module :

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { SampleComponent } from './sample/sample.component';

@NgModule({
  imports: [
    CommonModule
  ],
  declarations: [SampleComponent],
  providers: [],
  exports: []
})
export class SampleModule { }

Awesome, but you have to export manually the sample.component in the module :

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { SampleComponent } from './sample/sample.component';

@NgModule({
  imports: [
    CommonModule
  ],
  declarations: [SampleComponent],
  providers: [],
  exports: [SampleComponent]
})
export class SampleModule { }

and in sample/public_api.ts :

export * from './src/sample.module'
// All public members of the library must be added here.
export * from './src/sample/sample.component'

Add an instance of the sample-component in [src/app/app.component.html] :

<div style="text-align:center">
  <h1>
    Welcome to {{ title }}!
  </h1>
  <sample></sample>
</div>

Ensure that everything is fine :

ng serve

sample.component should be rendered as expected.

Testing

To execute src/app/app.component.spec.ts with success, the sample.module must be imported in the test bed configuration :

import { TestBed, async } from '@angular/core/testing';
import { AppComponent } from './app.component';
import { SampleModule } from "sample";
describe('AppComponent', () => {
  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [
        AppComponent
      ],
      imports: [
        SampleModule
      ]
    }).compileComponents();
  }));
  // ...
}

Run the tests of the app :

ng test

Run the tests of the library :

ng test --app=sample

Debugging with Chrome DevTools Overview

Open the debug page, open the Chrome DevTools Overview, open Sources tab, served files are in top/webpack.

Debugging with vscode

Add a launch chrome task :

{
    "name": "Launch debug",
    "type": "chrome",
    "request": "launch",
    "url": "http://localhost:9876/debug.html",
    "sourceMaps": true,
    "webRoot": "${workspaceRoot}"
}

Run ng test or ng test --app=sample.

Add some break points.

Run Launch debug.

Packaging the library

Install ng-packagr :

npm i -D ng-packagr

Create the sample/package.json that describe the library and the ng-packagr configuration :

{
  "name": "sample",
  "version": "1.0.0-alpha.0",
  "license": "MIT",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/raphael-volt/ng2-testable-lib-sample.git"
  },
  "author": "raphael-volt",
  "private": true,
  "peerDependencies": {
    "@angular/core": "^5.0.0",
    "@angular/common": "^5.0.0"
  },
  "ngPackage": {
    "$schema": "../node_modules/ng-packagr/ng-package.schema.json",
    "workingDirectory": "../.ng_build",
    "lib": {
      "entryFile": "public_api.ts"
    },
    "dest": "dist/sample"
  }
}

Create the build task in app package.json

{
  // ...
   "scripts": {
    // ...
    "build:sample": "ng-packagr -p sample/package.json"
  },
  // ...
}

then run it :

npm run build:sample

Generate the tgz archive :

cd dist/sample
npm pack

Install the library localy

cd to an angular app, then :

npm i <relative-path-to-archive>

Import module to app.module and in test bed configuration.

@TODO : publish to npm.