将 Angular 6 项目升级到 Angular 10

Angular 项目的升级说起来也简单,也复杂,也有踩坑的地方。

简单的方面就是,官方提供了升级的指导,访问 https://update.angular.io/ 选择项目的当前版本号和想要升级的版本号,就会出来相关的步骤作为指导。

复杂的地方就是,ng update 工具其实只能完成一部分工作,通常我们升级的过程中,会需要手工处理不少冲突与不兼容的地方,踩坑的地方也主要就在这里。

具体来说,有如下经验供参考:

1,不建议一次性从6 升级到 10,而建议逐个版本依次升级。因为每个版本迭代都可能有很多地方调整修改,涉及对应的依赖包版本的调整或者应用代码的修改。若一次跨多个版本升级,对于遇到问题时候的定位会造成困难。

有一点小细节需要注意:执行 ng update 升级成功并不代表代码一定能正常编译运行。因此,建议对于每个版本升级,都把代码启动起来测试,以验证升级是否成功。

2,注意各个依赖包的版本兼容问题

基本上每次升级,都伴随着对应的很多依赖库需要相应升级。ng update 能自动升级一部分,但不是全部。尤其是当你用了很多三方包的时候。一般 ng update 失败的话,常见的原因就是提示某某库依赖于另外某个库的某个版本,而你将要安装又是某个版本。这时候就需要对相关的包进行升级。

主要注意点是,对于版本的选择并非是最新版就最好,譬如当我们从 Angular 6 升级到 7 的时候,其实应选择的是最兼容当时 Angular 版本的包版本。譬如 Angular 7 发布于 2018年10月,而 Angular 8 发布于2019年6月,那么就可以在 npm 官方站查找所要升级的依赖包的版本历史,选择发布时间介于 2018年10月和2019年6月的则基本就可以。若仍然提示版本问题,则可以尝试其它版本。

3,Angular 8 升级到 Angular 9 遇到 typings.d.ts 中的类型定义未生效的问题,这个主要是在 Angular 9 中有了 tsconfig.app.json 文件,在 ng update 的过程中,该文件的对应配置错误导致,一般应修改如下内容:

{
  "extends": "../tsconfig.json",
  "compilerOptions": {
  "outDir": "../out-tsc/app",
  "baseUrl": "./",
  "types": []
  },
  "files": [
    "main.ts",
    "polyfills.ts"
  ],
  "include": [
    "**/*.d.ts",
    "typings.d.ts"
  ]
}

上面代码中最后那一项就是我们项目中丢失的,添加上去后,类型定义找不到的问题就解决了。

4,注意看官方提示,有些已经修改过的用法或者已经启用的用法就果断修改。这里主要涉及到两方面,一方面是 Angular 的变化,另一方面是 TypeScript 的变化。前者譬如 Angular 7  之后,废除了 @angular/http 而一律改用 @angular/common/http。又譬如 Angular 9 中,Module 定义中就去除了 entryComponent 的配置,所以删掉对应的语句即可。

5,有些三方库的写法发生了变化,有可能需要修改对应的代码。譬如我们项目中用到了 SweetAlert2 这个库。在升级到 Angular 10的时候,我们也将该库升级到了最新版本。这时候 ng update 升级整个项目虽然没遇到关于这个库的错误,但当运行项目的时候就遇到SweetAlert.fire()这个方法报错,具体来说,我们在这个方法的第一个参数里,有用 title 关键字来指定对话框的标题,但在新版本中,这个关键字改为了 icon。这是通过查找  SweetAlertOptions 的类型定义而知道的。所以依次修改掉即可。

总结下来,整个过程一要参考官方指导,二要认真研究出错信息,找到对应出处,其实问题都不难解决。

整个升级前后跨越了五天左右的时间,头三天花的时间较多,主要是各种踩坑及各种试错。由于有洁癖,后两天再花了一点点时间,用摸索出来的最合理的办法,将升级过程重新做了一遍。

最后,看一下漂亮的提交历史:(其实每个版本的升级都开了分支,每个升级其实并不止一次 commit,为了整洁,在 merge 回来的时候加了 –squash 参数)



熟悉的相随

于人群中多看你一眼
初见 就如已相识千年
宿命于此刻 撞进胸口
把几辈子的记忆泛起在心头

我曾一次次的随您同行吧?
上路,相遇,前路漫长
在多少世的轮回里
如影 相随
共赴远方

而再见是陌生的脸庞
心却说那是熟悉的模样
眼里升起闪烁的星星啊
那又是哪一世思念的感伤
再湿了眼眶

悼念肖姐

刚刚得知我的一位大姐肖教授过世了。感觉很突然,心里很悲痛。肖大姐人挺好,我们挺聊得来,这几年虽然不常见面,但每次见到都能聊挺长时间。

前两年她就一直跟我说,如果经过长沙,过去她家做客聊天。现在这已经是不可能的事了,谁能想到才五十几岁的她这么早就走了。

想想看,她那个时候会不会是已经知道了自己的病情了,也许要我们去做客在她看来是一个关于告别的邀请呢。而我们却没有赴约,成为遗憾。

人这一辈子,真的很无常。有缘相见的人,尽量珍惜吧。

无字

时光易老

等我再过些年

我也许会写这世上的风花雪月,我也许会写这人间的世态炎凉。

我也许会写山盟海誓,我也许会写生死无常。

我也许会想写尽我们每个人的一生。

如果写不下, 我也许只想静静睡眠,在一座无字的碑旁。

再次迁移Gitlab服务器

团队一直在用基于docker的gitlab。去年迁移过一次服务器,参见这篇文章

今年因为某个原因再次迁移。但按照之前的办法,却一直不成功,服务起不起来,报错信息既有跟文件权限有关的,也有跟SSL证书有关的。最后没时间折腾,就换了种方式,使用备份gitlab数据,再进行恢复的方式解决。

在确保新、旧服务器上 Gitlab 版本一致的情况下,先在旧服务器上备份数据:

sudo docker exec -it gitlab /bin/bash进入旧服务器 gitlab容器的命令行,执行如下备份命令

gitlab-rake gitlab:backup:create RAILS_ENV=production

此操作备份所有gitlab数据,在 backups文件夹下生成了1523788820_2018_04_15_10.6.3_gitlab_backup.tar文件。

然后使用SFTP或SCP,将备份数据拷贝到新服务器上同名文件夹下,然后进入 gitlab 容器的命令行执行恢复命令:

gitlab-rake gitlab:backup:restore RAILS_ENV=production BACKUP=1523788820_2018_04_15_10.6.3

此过程中,有几个要点要注意:

1,注意新旧gitlab版本要一致,对于使用docker技术来说,可以通过指定版本号来确保;

2,注意文件路径要正确;

3,注意备份文件复制到新服务器后,可能存在权限问题。因为 gitlab默认使用git用户来对文件进行读写,可以使用 sudo chown git:git 1523788820_2018_04_15_10.6.3_gitlab_backup 命令来修改文件owner

换用腾讯云的免费SSL

之前曾用过沃通的免费SSL,结果几个月前备谷歌宣布不再信任该机构。也曾用过starSSL,似乎也有相似问题。

后来曾用Let’s Encrypt,挺好用,但有两个缺点:

1,证书有效期太短,才半年,感觉眼睛一眨就得要去renew了;

2,在复杂配置的centos上面自动化很麻烦,我们站点设置了80端口自动转https,但certbot(Let’s Encrypt客户端)要工作必须先要能访问验证域名,需要放置验证文件能在80端口下访问。这也意味着每次我们renew证书还需要修改站点配置。自动化Renew反正是没用上。

近期正好看到腾讯有免费ssl,就去申请了一下。很方便,验证方式也比较容易。有效期一年,比Let’s Encrypt长。既然自动化不了,暂时就用他家的方案了。

使用JPA的级联更新问题

假设A对象与B对象是一对多的关系,B的集合作为A的属性children而存在。

class A{
……
@OneToMany(mappedBy=”parent”, cascade={CascadeType.ALL})
private Set<B> children;
……
}

使用CascadeType.ALL能够实现级联保存、级联删除。但是级联更新的时候遇到如下问题:

A.children.remove(child1);
A.children.add(child2);

这时候child2确实被添加到数据库了,但child1却并没有被删除。

其实只要加上orphanRemoval=true 就可以了

class A{
……
@OneToMany(mappedBy=”parent”, cascade={CascadeType.ALL},orphanRemoval=true)
private Set<B> children;
……
}