複数のメジャーバージョンをまたぐAngularプロジェクトのバージョンアップ方法 

## 作業準備
以下URLにあるように、公式によって複数のメジャーバージョンをまたいだバージョンアップもサポートされています。  

[Angularアップデートガイド](https://update.angular.io/?locale=ja-JP)

さっそくアップデートガイドをもとにバージョンアップを開始していきましょう。  

今回は、バージョン7からバージョン12へのアップデートを行っていきます。


## バージョンアップ開始
### Angular8へアップデート  
基本的にはアップデートガイドの指示にしたがって、コマンドの実行およびプロジェクトのチェックを行っていきます。  

アップデートガイドの内容を見てみると、メジャーバージョンに大きな差がある場合は、1つずつ順番にバージョンをあげていくみたいです。  
アップデートガイドにある通り次のコマンドを入力し、まずはプロジェクトのバージョンを8にアップデートします。  

```  
$ ng update @angular/cli@8 @angular/core@8
```
しかし次のエラーが発生し、コマンドを実行することができませんでした。  

```
Using package manager: 'npm'
Collecting installed dependencies...
Found 0 dependencies.
Package '@angular/cli' is not a dependency.
```  


インストールするパッケージが1つも見つかっていません。
現在（2021/05/18時点）のAngularCLI最新バージョンである12には、すでにバージョン8に関するパッケージは含まれていないようです。  
ですので次のコマンドを実行し、一度パソコンにインストールされているAngularCLI自体のバージョンを8に引き下げます。    

```
$ npm install -g @angular/cli@8.0.0
```
そのうえで先ほどのコマンドをもう一度実行してみたところ、違うエラーが発生しました。 

```  
Using package manager: 'npm'
Collecting installed dependencies...
Found 35 dependencies.
Fetching dependency metadata from registry...
                  Package "codelyzer" has an incompatible peer dependency to "@angular/core" (requires ">=2.3.1 <7.0.0 || >6.0.0-beta <7.0.0" (extended), would install "8.2.14").
                  Package "codelyzer" has an incompatible peer dependency to "@angular/common" (requires ">=2.3.1 <7.0.0 || >6.0.0-beta <7.0.0" (extended), would install "8.2.14").
                  Package "codelyzer" has an incompatible peer dependency to "@angular/compiler" (requires ">=2.3.1 <7.0.0 || >6.0.0-beta <7.0.0" (extended), would install "8.2.14").
                  Package "codelyzer" has an incompatible peer dependency to "@angular/platform-browser-dynamic" (requires ">=2.3.1 <7.0.0 || >6.0.0-beta <7.0.0" (extended), would install "8.2.14").
                  Package "codelyzer" has an incompatible peer dependency to "@angular/platform-browser" (requires ">=2.3.1 <7.0.0 || >6.0.0-beta <7.0.0" (extended), would install "8.2.14").
Incompatible peer dependencies found. See above.
```

調べてみたところ、ピア依存関係のバージョン不一致によるエラーのようです。  
ピア依存関係のバージョン不一致によるエラーの際には、他にも次のようなログが出力される場合があります。  

```
× Migration failed: Incompatible peer dependencies found.
Peer dependency warnings when installing dependencies means that those dependencies might not work correctly together.
You can use the '--force' option to ignore incompatible peer dependencies and instead address these warnings later.
```

その際には、ピア依存関係のバージョン不一致を無視するオプション「--force」を追加したコマンドを実行します。  

```
$ ng update @angular/cli@8 @angular/core@8 --force
```

無事に実行することができました。  
コマンドの出力ログにあるように脆弱性が発生しているので、「npm audit fix」コマンドを実行し修正を行いましょう。  

```
added 5 packages from 8 contributors, removed 1 package, updated 1 package and audited 1396 packages in 10.624s

61 packages are looking for funding
  run `npm fund` for details

found 31 vulnerabilities (17 low, 5 moderate, 9 high)
  run `npm audit fix` to fix them, or `npm audit` for details
```  

終了後必ずコミットを行いましょう。コミットを行わない場合、次のバージョンアップ手順中にエラーが発生してしまいます。

### 続けてアップデート  
次のコマンドを実行し、Node.jsのバージョンが10.13以降であることを確認します。  

```
$ node --version
```

Node.jsのバージョンを確認したら、プロジェクトのバージョンを9に変更します。  
前回のバージョンアップ以降から、アップデートガイドのチェック項目にしたがってプロジェクトを変更していた場合は再度コミットを行ってから、コマンドを実行してください。    

```
$ ng update @angular/core@9 @angular/cli@9
```
コミットを行っていれば、エラーは発生せずに実行できるはずです。コミットを行っていない場合、次のようなエラーが発生します。  

```
Repository is not clean. Please commit or stash any changes before updating.
```  
もし何らかの都合でコミットを行わずに続けてアップデートを行いたい場合は、次のコマンドのようにオプションを追加することによって、コマンドの実行を行うことができます。  

```
$ ng update @angular/core@9 @angular/cli@9 --allow-dirty
```  

### パッケージの追加  
Angular9から新しい関数が追加されたため、それを利用するための新しいパッケージを追加します。  

```
$ ng add @angular/localize
```

### その後  
あとは今まで行ったように、アップデートガイドの指示にしたがってプロジェクトのチェックを行いながらバージョンアップを繰り返すことによって、Angularプロジェクトを目的のバージョンにアップデートできます。  

<!-- ng updateコマンドによって、自動的に上がっていくからいらないかも。最新版が12で、プロジェクトを11にあげたいときとかはする必要あり？ -->
### 最後に
作業が終了したら忘れずに次のコマンドを実行し、作業開始時に下げたAngularCLI自体のバージョンを安定版に戻しておきましょう。  

```
$ npm install -g @angular/cli
```

## まとめ  
本記事では、複数のメジャーバージョンをまたぐAngularプロジェクトのバージョンアップを行いました。  
アップデートガイドのチェック項目を確認しながらメジャーバージョンを1つずつアップデートすることによって、複数のメジャーバージョンをまたぐAngularプロジェクトのバージョンアップを行うことができます。  


## 少し長いおまけ
バージョン11以降のAngularプロジェクトでは、TSLintとCodelyzerは非推奨になるので、ESLintへのマイグレーション方法について記載しておきます。  

### @angular-eslint/schematicsの追加  
次のコマンドを実行し、@angular-eslint/schematicsをプロジェクトに追加します。  

```
$ ng add @angular-eslint/schematics
```  

以下のようなログが出力され、パッケージをインストールすることができました。  

```
ℹ Using package manager: npm
✔ Found compatible package version: @angular-eslint/schematics@12.0.0.
✔ Package information loaded.

The package @angular-eslint/schematics@12.0.0 will be installed and executed.
Would you like to proceed? Yes
✔ Package successfully installed.
    
    All @angular-eslint dependencies have been successfully installed 🎉
    
    Please see https://github.com/angular-eslint/angular-eslint for how to add ESLint configuration to your project.

UPDATE package.json (1837 bytes)
✔ Packages installed successfully.
```  

### マイグレーション対象の選択  
マイグレーションを行うプロジェクトを選択します。  
angular.jsonにいくつprojectの定義があるかで変わり、複数のprojectを定義している場合には、移行対象を選択する必要があります。
今回は「bookmanagement-angular」というプロジェクトをマイグレーションするので、次のようなコマンドを実行します。  

```
$ ng g @angular-eslint/schematics:convert-tslint-to-eslint bookmanagement-angular
```  

無事にマイグレーションが完了し、.eslintrc.jsonファイルが生成されました。  


```
? Would you like to remove TSLint and its related config if there are no TSLint projects remaining after this conversion? Yes
? Would you like to ignore the existing TSLint config? Recommended if the TSLint config has not been altered much as it makes the new 
ESLint config cleaner. Yes
    
    INFO: We are now installing the "tslint-to-eslint-config" package into a tmp directory to aid with the conversion

    This may take a minute or two...

CREATE .eslintrc.json (1015 bytes)
UPDATE angular.json (3856 bytes)
```  

### TSLintの削除  
最後に次のコマンドを実行し、不要となったTSLintの削除を行います。  

```
$ rm tslint.json 
$ npm uninstall tslint
```  

### まとめ  
以上でマイグレーション作業が終了となります。  
今回はAngular7からバージョンアップしたAngular12のプロジェクトをCodelyzerとTSLintからESLintへマイグレーションしました。  
本記事がどなたかのお役に立てますように。