Empezar desde el principio
Si la memoria me sirve bien, entonces desde la versión 6 en angular se hizo posible crear diferentes tipos de proyectos en un espacio de trabajo: aplicación y biblioteca.
Hasta este punto, las personas que querían crear una biblioteca de componentes probablemente usaron el excelente y útil paquete ng-packagr, que ayudó a crear el paquete en el formato aceptado para angular. En realidad, creé la biblioteca anterior usando esta herramienta. Ahora el equipo angular incluyó ng-packagr en angular-cli y esquemas agregados para crear y construir bibliotecas, expandió el formato angular.json y agregó algunas comodidades más. Pasemos de ng new a npm install, desde crear una biblioteca vacía hasta publicarla e importarla a un proyecto de terceros.
El espacio de trabajo se crea como siempre
ng new test-app
Se creará un espacio de trabajo y un proyecto de aplicación, eche un vistazo a angular.json
{ ... "projects": { "test-app": { ... "sourceRoot": "src", "projectType": "application", "prefix": "app" ... } ... } ... }
Ahora agregue el proyecto de biblioteca
ng generate library test-lib --prefix=tl
agregaremos la clave --prefix para indicar que los componentes y las directivas usarán el prefijo tl, es decir, las etiquetas de los componentes se verán como
<tl-component-name></tl-component-name>
Veamos ahora en angular.json, hemos agregado un nuevo proyecto
{ ... "projects": { "test-app": { "root": "", "sourceRoot": "src", "projectType": "application", "prefix": "app" ... }, ... "test-lib": { "root": "projects/test-lib", "sourceRoot": "projects/test-lib/src", "projectType": "library", "prefix": "tl" } ... } ... }
La siguiente estructura apareció en el directorio del proyecto.
- projects - test-lib ng-package.json package.json - src public-api.ts - lib test-lib.component.ts test-lib.module.ts test-lib.service.ts
Además, en tsconfig.json hay una adición en la sección de rutas
"paths": { "test-lib": [ "dist/test-lib" ], "test-lib/*": [ "dist/test-lib/*" ] }
Ahora, si ejecuta la aplicación,
ng serve
luego veremos una plantilla de aplicación angular de trabajo estándar
Crear funcionalidad de biblioteca
Creemos una biblioteca con un servicio, directiva y componente. Colocaremos el servicio y la directiva en diferentes módulos. Pasemos al directorio projects / test-lib / src / lib y elimine test-lib. *. Ts, también eliminemos el contenido de projects / test-lib / src / public-api.ts.
Pasemos a projects / test-lib / src / lib y creemos módulos, directivas, servicios y componentes.
ng g module list ng g module border ng g service list /* list*/ ng g component list /* border*/ ng g directive border
Rellene el componente, servicio y directiva con lógica. El componente mostrará una lista de filas enviadas a la entrada. La directiva es agregar un marco rojo, el servicio agregará la marca de tiempo actual al Observable cada segundo.
Servicio
import {Injectable} from '@angular/core'; import {Observable, Subject} from 'rxjs'; @Injectable({ providedIn: 'root' }) export class ListService { timer: any; private list$: Subject<string> = new Subject<string>(); list: Observable<string> = this.list$.asObservable(); constructor() { this.timer = setInterval(this.nextItem.bind(this), 1000); } nextItem() { const now = new Date(); const currentTime = now.getTime().toString(); this.list$.next(currentTime); } }
Lista de componentes y módulo
import {NgModule} from '@angular/core'; import {CommonModule} from '@angular/common'; import {ListComponent} from './list/list.component'; @NgModule({ declarations: [ ListComponent ], exports: [ ListComponent ], imports: [ CommonModule ] }) export class ListModule { } @Component({ selector: 'tl-list', template: ` <ul> <li *ngFor="let item of list">{{item}}</li> </ul>`, styleUrls: ['./list.component.css'], changeDetection: ChangeDetectionStrategy.OnPush }) export class ListComponent implements OnInit { @Input() list: string[]; constructor() { } ngOnInit() { } }
Marco
import {NgModule} from '@angular/core'; import {CommonModule} from '@angular/common'; import {BorderDirective} from './border.directive'; @NgModule({ declarations: [ BorderDirective ], exports: [ BorderDirective ], imports: [ CommonModule ] }) export class BorderModule { } import {Directive, ElementRef, OnInit} from '@angular/core'; @Directive({ selector: '[tlBorder]' }) export class BorderDirective implements OnInit { private element$: HTMLElement; constructor(private elementRef$: ElementRef) { this.element$ = elementRef$.nativeElement; } ngOnInit() { this.element$.style.border = 'solid 1px red'; } }
! Es importante Al generar componentes y bibliotecas, cli no crea exportaciones, así que asegúrese de agregar los componentes y directivas que deberían estar disponibles en la sección de exportaciones en los módulos.
Además, para que en el futuro las clases de la biblioteca estén disponibles, agregaremos algo de código a public-api.ts
export * from './lib/list.service'; export * from './lib/border/border.module'; export * from './lib/border/border.directive'; export * from './lib/list/list.module'; export * from './lib/list/list/list.component';
Conectar una biblioteca en una aplicación de prueba
Vamos a armar el proyecto de la biblioteca.
ng build test-lib --watch
A continuación, en app.module importaremos los módulos con el componente y la directiva y agregaremos la lógica
import {BrowserModule} from '@angular/platform-browser'; import {NgModule} from '@angular/core'; import {AppRoutingModule} from './app-routing.module'; import {AppComponent} from './app.component'; import {ListModule} from 'test-lib'; import {BorderModule} from 'test-lib'; @NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, AppRoutingModule, ListModule, BorderModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }
Y usa las piezas de nuestra biblioteca en la aplicación
import {Component, OnInit} from '@angular/core'; import {ListService} from 'test-lib'; @Component({ selector: 'app-root', template: ` <tl-list [list]="list"></tl-list> <div tlBorder>I am bordered now</div>`, styleUrls: ['./app.component.styl'] }) export class AppComponent implements OnInit { list: string[] = []; constructor(private svc$: ListService) { } ngOnInit() { this.svc$.list.subscribe((value => this.list = [...this.list, value])); } }
Ejecute y verifique la aplicación, todo funciona:

Asamblea y publicación
Queda por recopilar y publicar el paquete. Para el ensamblaje y la publicación, es conveniente agregar comandos a los scripts en la aplicación package.json
{ "name": "test-app", "version": "0.0.1", "scripts": { ... "lib:build": "ng build test-lib", "lib:watch": "ng build test-lib --watch", "lib:publish": "npm run lib:build && cd dist/test-lib && npm pack npm publish", ... } }
La biblioteca se compila, publica, ahora después de la instalación en cualquier otro proyecto angular
npm install test-lib
Puede usar componentes y directivas.
Pequeña nota
Tenemos una familia completa de paquetes npm en nuestra empresa, por lo que en nuestro caso el paquete debe publicarse con un espacio de nombres como
company / test-lib. Para hacer esto, solo haremos algunas ediciones.
Cambie el nombre del paquete en la biblioteca package.json
/* projects/test-lib/package.json */ { "name": "@company/test-lib", "version": "0.0.1", "peerDependencies": { "@angular/common": "^7.2.0", "@angular/core": "^7.2.0" } }
Y para que en la aplicación de prueba se pueda acceder a la biblioteca por nombre con espacio de nombres, arreglaremos un poco tsconfig
/* test-app/tsconfig.json */ *** "paths": { "@company/test-lib": [ "dist/test-lib" ], "@company/test-lib/*": [ "dist/test-lib/*" ] } ***
Y en la aplicación de prueba reemplazar las importaciones, por ejemplo
import {ListModule} from 'test-lib';
Reemplazar con
import {ListModule} from '@company/test-lib';
Este es el final.
PD: cuando estudié este tema, una vez leí los siguientes artículos
La serie de bibliotecas angularesCómo construir una biblioteca de componentes npm ready con Angular