本文基于 angular-cli
6.x 提供的 Library
相关命令。
我们创建一个名叫 hello-ui
的库,该库包含以下功能:
component
示例项目代码: https://github.com/taozhiw/hello-ui (opens new window)
Library
不能独立创建(关于该设计的相关讨论 (opens new window)),以下是 Angular 团队成员的解释:
There isn't a flag to do this on ng new but it is something we have discussed. I'd like to point out that usually one would want to test their libraries on a real app while developing though.
使用 ng new
命令创建 hello-ui-wrap
项目(以下该项目称为工作空间):
ng new hello-ui-wrap --style=scss
--style
可指定项目使用的样式预编译语言,其它 ng new
的参数可使用 ng new --help
查看,这样我们的工作空间就创建好了。项目创建完成 angular-cli
会自动使用 npm
安装相关依赖包,一般我会强制停掉使用 yarn
安装。安装完成,便可以使用 npm run start
启动,然后在浏览器打开 http://localhost:4200/ 便可以看到欢迎界面了。
使用 ng generate
命令:
ng generate library hello-ui --prefix=hu
--prefix=hu
指定了该库的组件名的前缀,一般如果库提供了组件的话,都是需要指定的。还有其它参数同样可使用 ng generate library --help
查看。命令执行完毕后,工作空间中多了一个 projects
文件夹,该文件夹中的 hello-ui
便是我们创建的库了,从目录的结构就可以看出,一个工作空间中是可以创建多个库的。
接着删掉库里面的 hello-ui.component.spec.ts
、hello-ui.component.ts
、hello-ui.service.spec.ts
、hello-ui.service.ts
文件,及清除掉 hello-ui.module.ts
、public_api.ts
对于这几个文件的引用代码。因为后续我们不会用到。
为了让组件能够按需导出 module
,我们给每个组件都创建一个 module
,对于 pipe
、directive
等我们都可以为其建立单独的 module
。
首先创建按钮模块,转到 hello-ui/src/lib
目录下(如果不切换目录,在工作空间下创建库的部件,需要加上 --project=hello-ui),执行创建模块的命令:
ng generate module button
命令执行完成后可看到在 hello-ui/src/lib
下多了一个 hello
文件夹,接着创建我们的按钮组件:
ng generate component button
创建完成后,修改 button.component.html
的内容为下面的内容:
<button>我是 hello-ui 的 button</button>
修改 button.module.ts
:
@NgModule({
imports: [CommonModule],
declarations: [ButtonComponent],
// 注意,必须 exports 出去,不然调用时会报找不到相关组件
exports: [ButtonComponent],
})
export class ButtonModule {}
修改 hello-ui.module.ts
:
@NgModule({
imports: [ButtonModule],
// 同样必须导出
exports: [ButtonModule],
})
export class HelloUiModule {}
修改 public_api.ts
:
库对外的东西都需要在此声明,不声明调用会报错。
export * from "./lib/hello-ui.module";
export * from "./lib/button/button.module";
export * from "./lib/button/button.component";
很简单,在 package.json
中加一个脚本配置:
"scripts": {
...
"build:lib": "ng build --prod hello-ui",
...
}
然后使用 npm run build:lib
或者 yarn build:lib
运行该命令,运行结束,就可以在工作空间下看到多了个 dist
目录, 在 dist
目录下的 hello-ui
文件夹便是打包后的目录。
像使用其它 npm 包一样,在 app.module.ts
中导入即可:
import { AppComponent } from "./app.component";
// 按需导入(虽然目前看起来没什么用,因为库里面就一个组件)
import { ButtonModule } from "hello-ui";
// 或者整个库导入
// import { HelloUiModule } from 'hello-ui';
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule, ButtonModule],
providers: [],
bootstrap: [AppComponent],
})
export class AppModule {}
然后修改下 app.component.html
,加上我们自己组件的调用:
<hu-button></hu-button>
然后重启服务,就可以看到我们的库已经可以调用了。
为什么我们的库能像 npm 安装的包一样导入,是因为我们在生成库的时候,angular-cli
帮我们在 tsconfig.json
中加上了下面的内容:
"paths": {
"hello-ui": [
"dist/hello-ui"
],
"hello-ui/*": [
"dist/hello-ui/*"
]
}
所以 Angular 在编译时,就会先从配置的 paths
去查找,然后再去 node_modules
去查找。
切换到 dist/hello-ui
下执行 npm publish
(关于 npm publish (opens new window)) 就行了。
如果库有依赖包,我们在其 package.json
的 dependencies
字段中配置下,还没有完,还需要在
ng-package.json
中配置下 whitelistedNonPeerDependencies
(关于 whitelistedNonPeerDependencies 的相关讨论 (opens new window)),例如我们的库依赖 clone
这个库,则需要配置:
"whitelistedNonPeerDependencies": ["clone"]
参考资料: