Angular:创建和发布库

从头开始


如果对的没问题,那么从版本6开始就可以在一个工作空间中创建不同类型的项目:应用程序和库。

在那一刻之前,想要创建组件库的人最有可能使用了出色且有用的ng-packagr软件包,该软件包有助于以angular可接受的格式创建软件包。 实际上,我使用此工具创建了以前的库。 现在,角度团队在angular-cli中加入了ng-packagr,并添加了用于创建和构建库的原理图,扩展了angular.json格式并添加了更多便利设施。 现在让我们从ng new到npm install-从创建一个空库到发布它并将其导入到第三方项目中。

工作区照常创建

ng new test-app 

将创建工作区和应用程序项目,看一下angular.json

 { ... "projects": { "test-app": { ... "sourceRoot": "src", "projectType": "application", "prefix": "app" ... } ... } ... } 

现在添加库项目

 ng generate library test-lib --prefix=tl 

我们将添加--prefix键,以指示组件和指令将使用tl前缀,也就是说,组件标签看起来像

 <tl-component-name></tl-component-name> 

让我们现在在angular.json中看到,我们添加了一个新项目

 { ... "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" } ... } ... } 

以下结构出现在项目目录中

 - 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 

另外,在tsconfig.json中,路径部分中有一个附加项

 "paths": { "test-lib": [ "dist/test-lib" ], "test-lib/*": [ "dist/test-lib/*" ] } 

现在,如果您运行该应用程序,
 ng serve 
然后我们将看到一个标准的工作角度应用模板

创建库功能


让我们创建一个包含服务,指令和组件的库。 我们将服务和指令放置在不同的模块中。 让我们移至projects / test-lib / src / lib目录并删除test-lib。*。TS,还删除project / test-lib / src / public-api.ts的内容。

让我们转到project / test-lib / src / lib并创建模块,指令,服务和组件

 ng g module list ng g module border ng g service list /*  list*/ ng g component list /*  border*/ ng g directive border 

用逻辑填充组件,服务和指令。 该组件将显示提交给输入的行的列表。 指令是添加一个红色框,该服务每秒将当前时间戳添加到Observable。

服务专区

 /*list.service.ts*/ 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); } } 

组件清单和模块

 /*list.module.ts*/ 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 { } /*list.component.ts*/ @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() { } } 

车架

 /*border.module.ts*/ 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 { } /*border.directive.ts*/ 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'; } } 

! 这很重要。 生成组件和库时,cli不会创建导出,因此请确保添加模块中的export部分中应该可用的组件和指令。

此外,为了将来可以使用库中的类,我们将一些代码添加到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'; 

在测试应用程序中连接库


让我们组装图书馆项目

 ng build test-lib --watch 

接下来在app.module中,我们将使用组件和指令导入模块,并添加逻辑

 /*app.module.ts*/ 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 { } 

并在应用程序中使用我们库中的片段

 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])); } } 

运行并检查应用程序,一切正常:



汇编和出版


它仍然可以收集和发布程序包。 对于组装和发布,将命令添加到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", ... } } 

安装在任何其他Angular项目中后,库现在可以编译,发布
 npm install test-lib 

您可以使用组件和指令。

小笔记


我们公司中有一整套npm软件包,因此在本例中,该软件包应以名称空间发布为company / test-lib。 为此,我们将做一些更改

重命名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" } } 

因此,在测试应用程序中,可以通过名称空间和名称空间访问该库,我们将对tsconfig进行一些修复

 /* test-app/tsconfig.json */ *** "paths": { "@company/test-lib": [ "dist/test-lib" ], "@company/test-lib/*": [ "dist/test-lib/*" ] } *** 

并在测试应用程序中替换导入,例如

 import {ListModule} from 'test-lib'; 

替换为

 import {ListModule} from '@company/test-lib'; 

到此为止。

PS:学习这个主题时,我曾经阅读以下文章
角库系列

如何使用Angular构建npm ready组件库

Source: https://habr.com/ru/post/zh-CN452262/


All Articles