Build your own Angular library and publish it to NPM 1033 words.
Last Updated
In this lesson, I will show you how to build an Angular Library from scratch using NgPackagr. My main motivation for this article is that Google Analytics recently changed their main API to gtag.js, but solid Angular libraries were lacking, so I decided to build one from scratch. NgPackagr made the bundling process very easy.
Angular packages are standardized by the Angular Package Format, but generating this output manually is difficult. NgPackager will do all the stuff you don’t want to deal with, like generating the bundles (FESM2015, FESM5, and UMD), creating your types, and ensuring that the end result is AOT compatible.
Full source code [Angular NgPackager Tutorial](https://github.com/AngularFirebase/103-angular-ngpackagr-tutorial).
IMPORTANT Update for Angular v6.0
Angular CLI v6.0 introduced a new command that will save much of the manual configuration required in the this lesson.
# Generate a library
ng generate library awesome
# Build it
np run awesome:build
# Install it in your app
npm install dist/awesome
While the code in the following steps is still valid, I highly recommend using the CLI to eliminate the manual creation of files.
Step 1 - Build an Angular CLI Project
Let’s generate an app and give it a module and component. The app itself is not part of the library, but will be used for integration testing.
ng new awesomePackage --routing
cd awesomePackage
Now lets create a feature module and add some resources to it.
ng g module toast
ng g service toast/toast -m toast
ng g component toast/toast-message --export
I’m not going to cover how to build the actual app, but it’s just simple toast notification system. It includes a service that controls he message content/visibility and component that shows the actual message to the end user.
Step 2 - Setup your Lib
Create a folder in the root of your project named lib (or whatever you want) - this is where the source code for our library will exist.
Inside this the lib folder create the following elements.
- src/ source code
- package.json package definition
- public_api.ts to export your public Angular modules
- README.md so people know how to use your library
Then move the files from your toast feature module to the src folder in lib.
Creating an Angular Module for Root
The library’s module works mostly like it does in Angular, but the main difference is the way services are provided. In many cases, developers may need to pass configuration options to a library. This can be accomplished by defining a forRoot
method, which returns an object typed to ModuleWithProviders interface.
import { NgModule, ModuleWithProviders } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ToastService } from './toast.service';
import { ToastMessageComponent } from './toast-message/toast-message.component';
@NgModule({
imports: [ CommonModule ],
declarations: [ToastMessageComponent],
exports: [ToastMessageComponent]
})
export class ToastModule {
public static forRoot(config): ModuleWithProviders {
return {
ngModule: ToastModule,
providers: [
ToastService,
{ provide: 'config', useValue: config }
]
};
}
}
The end-user of the lib would use this module in their app like so:
ToastModule.forRoot({ apiKey: 'shhhhh' })
Injecting Configuration Options
If we need to use the data passed to the module via forRoot
, we can do so by using the @Inject
decorator in the constructor.
@Injectable()
export class ToastService {
constructor( @Inject('config') private config ) { }
}
Step 3 - Configure for NgPackagr
NgPackagr makes a few reasonable requirements of us to perform its magic.
Install
Install NgPackagr.
npm install ng-packagr --save-dev
Public API
In lib/public_api.ts export the interfaces that the developer should be able to access.
export * from './src/toast-message/toast-message.component';
export * from './src/toast.module';
export * from './src/toast.service';
lib/package.json
In the lib/package.json we will define our library’s NPM details. Make sure the name of the package is available on NPM if your project is open source.
The special section is ngPackage
, which is used by NgPackagr to locate the public API file for your project.
Your package should not have any dependentcies, only peerDependencies and devDependencies
{
"name": "super-toasty",
"version": "0.0.1",
"author": "Jeff Delaney <hello@angularfirebase.com>",
"license": "MIT",
"peerDependencies": {
"@angular/core": ">=5.0.0",
"@angular/common": ">=5.0.0"
},
"ngPackage": {
"$schema": "./node_modules/ng-packagr/ng-package.schema.json",
"lib": {
"entryFile": "public_api.ts"
},
"dest": "dist"
}
}
NPM Script
In the package.json (in the root of the project, not lib) add a build script.
"scripts": {
// ...
"build:lib": "ng-packagr -p lib/package.json"
}
Now run npm run build:lib
and you should see output like this:
Step 4 - Do some Integration Testing
Now it’s time to do some integration testing. Install the local package and serve the Angular app.
npm i lib/dist
ng serve
Then import the library in the app module.
import { ToastModule } from 'super-toasty';
@NgModule({
imports: [
ToastModule.forRoot({ brand: 'wohnverwaltung.com' })
]
})
Because we provided a service, we can inject it into our components.
import { ToastService } from 'super-toasty';
@Component({...})
export class AppComponent {
constructor(toast: ToastService) {
toast.show()
}
}
And because we exported a component, we can use it in our templates.
<toast-message></toast-message>
Step 5 - Publish to NPM
Publishing to NPM is super easy. First, make sure you’re logged into your account, then run the publish command pointing to lib/dist.
npm whoami
npm publish lib/dist
Congrats! The world is free to use for Angular Package by running:
npm install your-awesome-package
Best Practices when Writing Angular Libraries
On a final note, let’s talk about some best practices when building angular libraries.
Don’t touch the DOM
If your library touches he DOM directly, such as document.getElementById('foo')
, it will break other developer’s apps when they use Angular with server or web worker platforms. If you must do this, wrap your code in a try/catch block.
Strong Type
Your public API should be strong-typed. Developers like Angular because of the awesome tooling provided by TypeScript. Try to make end-users of your package as happy as possible by leveraging types.
Bad
someMethod(options: any) { ... }
Good
export interface Options {
foo: string;
bar: boolean;
}
someMethod(options: Options) { ... }
Write Documentation
Duh!
Write Unit and Integration Tests
As your library grows in complexity it becomes easy to introduce bugs and regressions. Write some tests an implement use continuous integration to ensure every commit meets your spec. Tests will also make it easier for other developers to contribute to the codebase without breaking everything.
In this lesson, I will show you how to build an Angular Library from scratch using NgPackagr. My main motivation for this article is that Google Analytics recently changed their main API to gtag.js, but solid Angular libraries were lacking, so I decided to build one from scratch. NgPackagr made the bundling process very easy.
Angular packages are standardized by the Angular Package Format, but generating this output manually is difficult. NgPackager will do all the stuff you don’t want to deal with, like generating the bundles (FESM2015, FESM5, and UMD), creating your types, and ensuring that the end result is AOT compatible.
Full source code [Angular NgPackager Tutorial](https://github.com/AngularFirebase/103-angular-ngpackagr-tutorial).
IMPORTANT Update for Angular v6.0
Angular …
Upgrade to PRO for the Full Lesson
Monthly
- Unlimited access to PRO courses
- Cancel anytime
- Slack #pro-member invite
- AngularFirebase Survival Guide Book
- No ads
Quarterly
- All monthly tier benefits
- 💰 33.33% discount
- 🔥 Free Sticker
---- OR ----
You must be logged in to view this content.