近期在 Angular 项目开发过程中,有个需求,同样的界面需要在两个不同的项目用到(用户端、管理端)。于是,大家决定增加一个 Git 仓库,用于放置多项目复用的组件!
背景:由于该项目有很多权限限制,发布 npm 包需要走很多流程,所以,下面的方法尝试中,会使用优先不发包的方式!
一、使用 subtree
思路:
- 新建一个子项目*github.com/Heyff12/reu… angular 项目,方便引用并测试公用组件
- 在 src 目录之外,新建 reuse/src 目录,在该目录下,编写公用组件代码
- 第三方需要使用该公用组件的库,只需要拉取 reuse/src 目录即可
以下操作是在第三方库执行的操作
1、 拉取子项目代码
git subtree add --prefix=reuse https://github.com/Heyff12/reuseSon.git master --squash
2、修改后提交代码到子项目
需要先把当前修改提交到本项目(第三方项目),再执行下面的 subtree 推送
git subtree push --prefix=reuse https://github.com/Heyff12/reuseSon.git master
这个提交会更新 subtree 的库的代码; subtree 库需要 pull 获取最新改动
3、 拉取子项目最新代码
git subtree pull --prefix=reuse https://github.com/Heyff12/reuseSon.git master --squash
4、弊端
- 在 angular 项目中,组件需要 在 module 注册。 拉取过来的公用组件的 module 需要受到在第三方项目的 app.module.ts 中引入
- 需要增加配置编译
文件 tsconfig.app.json
"include": [
"reuse/src/app/components/**/*.ts",
],
"exclude": [
"reuse/src/app/components/**/*.spec.ts"
]
二、发布 npm 包
思路:
- 基于第一种方式,subtree 的操作有些繁琐,故尝试发包的方式
1、 在子项目发包
- npm init
- 新建 .npmignore 忽略文件
- npm login
- npm publish
备注: 包的名字以@开头时,比如 @hey_ff/testbutton,发布时,需要增加属性才能发包成功
npm publish --access public
2、在第三方项目安装插件
npm install @hey_ff/testbutton
3、使用方式
- 引入
文件 app.module.ts
import {TheButtonComponent} from '@hey_ff/testbutton/the-button/the-button.component'
@NgModule({
declarations: [
AppComponent,TheButtonComponent
],
- 发包的代码,即reuse/src 目录,是原生的未经编译的 angular 代码,所以需要在第三方项目进行编译配置
文件 tsconfig.app.json
"include": [
"node_modules/@hey_ff/testbutton/the-button/**/*.ts",
],
"exclude": [
"node_modules/@hey_ff/testbutton/the-button/**/*.spec.ts",
]
4、总结
跟第一种方式比起来,只是把获取公用组件库代码的方式从 subtree 换成了 npm install,整体并没有简化实际使用中的繁琐配置
三、子项目不发包,通过拉取公用组件代码,配置绝对路径到 package.json 实现引用
在前两种方式对比下,发布包也依然没有让使用变得更简洁,所以继续尝试不发包的方式。
1、将子项目的代码拉取到第三方项目,也可以使用第一种里面的 subtree 路径
2、修改第三方项目的 package.json,给公用组件的路径指定引入名称
"btn": "file:./reuse/src/app/components",
3、在 app.module.ts 引入
import {TheButtonComponent} from 'btn'
@NgModule({
declarations: [
AppComponent,TheButtonComponent
],
4、在 tsconfig.app.json 种加入编译
"include": [
"reuse/src/app/components/**/*.ts",
],
"exclude": [
"reuse/src/app/components/**/*.spec.ts"
]
四、子项目不发包,通过配置代码 Url 到 package.json 实现引用
上述方式,既然通过配置 package.json 实现,那依据 package.json 的功能,还可以不用拉取公用组件的代码实现!
github.com/Heyff12/reu… 这个库,只有公用组件的代码
1、修改第三方项目的 package.json
"btnUrl": "https://github.com/Heyff12/reuseBtn",
2、在 app.module.ts 引入
import {TheButtonComponent} from 'btnUrl'
@NgModule({
declarations: [
AppComponent,TheButtonComponent
],
3、在 tsconfig.app.json 种加入编译
"include": [
"node_modules/btnUrl/**/*.ts",
],
"exclude": [
"node_modules/btnUrl/**/*.spec.ts",
]
4、总结
基于目前的 4 种方式,只是优化了引入公用组件库的方式,实际使用依然繁琐,就当做是对于 package.json 的引用探索好了~
使用的繁琐,归根结底,就是由于引入的公用组件代码没有经过编译!!!
通过再次查看 angular 文档,下面着重进行制定代码的编译实现!
五、子项目发布编译后的 angular 组件包
1、在子项目构建 library 配置,可以 build、发布编译打包后的组件包
1.创建工作区
ng new xxxx --create-application=false
xxxx 为项目名
2.进入项目新建文件夹
cd xxxx
ng g library my-lib --prefix=ml
3.编译 ng build my-lib --prod
4.编译后会生成 dist 文件,进入 dist 文件 cd dist cd my-lib
5.打包
npm pack
6.发布 npm publish --access public
2、在第三方项目安装包,可以直接使用
import { MyLibModule } from '@hey_ff/my-lib';
@NgModule({
declarations: [AppComponent, TheButtonComponent],
imports: [BrowserModule, AppRoutingModule, MyLibModule],
3、如果不方便发布到 npm
1、在公用组件项目,把第一步的 打包好的文件 dist/my-lib push 到指定分支
git subtree push --prefix dist/my-lib origin reuse
2、在第三方项目 通过 指定分支路径 安装上面的打包好的文件
"reuse": "git@github.com:Heyff12/angularPackage.git#reuse",
3、 在第三方项目,正常使用
import { MyLibModule } from 'reuse';
@NgModule({
declarations: [AppComponent, TheButtonComponent],
imports: [BrowserModule, AppRoutingModule, MyLibModule],
六、不发 npm 包的最佳方案
- 第五种方式的,第 3 步
七、反思
上述实现过程,看完后感觉很扭曲。
- 为啥不发 npm 包?—— 特定项目,导致发包申请流程复杂,于是大家想走不麻烦更多无关人员的途径 😢
- 为啥在 package.json 浪费了时间?——误入歧途,陷入了对 package.json 的探索 😿
- 为啥不直接编译?—— 源自一个美好的不太成熟的想法,所有使用公用组件库的项目,都可以自行更改公用组件库的代码
八、总结
- 既然要开发公用组件,就保持公用组件开发的统一性,只在公用组件仓库进行代码开发和调试,其他库只负责使用
- 在公用组件仓库,配置可以对公用组件进行调试的设置
- 对于公用组件代码,一定进行编译打包,保障使用的简洁
- 在公用组件库,编译时,只编译公用组件的代码
- 虽然该文章以 angular 为例,也希望大家在其他语言开发遇到类似场景时,少走弯路!