WSL と VSCode と Windows Terminal でコマンドプロンプトにさようなら

macOS から Windows に戻ってきて、「コマンドプロンプトかー、せめて PowerShell だよな」ということで PowerShell Core を使っていたのですが、そういえば WSL(Windows Subsystem for Linux) があったな、と思い出して、開発環境は全面的に WSL を使っていくことにしましたので、その手順をメモしておきます。

なおここで言う開発環境とは、Webアプリのフロントエンドを Angular で、バックエンドを node.js で開発することを指します（また、実際のところ Linux にはあまり詳しくないので、WSL とディストリとシェルを混同して表記している自信があります）。

## 1. WSL の導入

* [【WSL入門】第1回　Windows 10標準Linux環境WSLを始めよう：ITの教室 - ＠IT](https://www.atmarkit.co.jp/ait/articles/1903/18/news031.html)

を参考に、WSL を導入します。

## 2. Windows Terminal の導入

Windows Terminal は Windows 向けのターミナルクライアントで、現在はまだ Preview 版ですが、なかなか使いやすくカスタマイズ性も高いので愛用しています。

* [Windows Terminal (Preview) を入手 - Microsoft Store ja-JP](https://www.microsoft.com/ja-jp/p/windows-terminal-preview/9n0dx20hk701#activetab=pivot:overviewtab)
* [Windows Terminal (Preview) メモ - Qiita](https://qiita.com/rubytomato@github/items/e88cab84f36e44797cf2)

WSL をインストールすると、Windows Terminal にも「Ubuntu」という Profile が増えます。
Windows Terminal を起動したときに、Ubuntu の Terminal がデフォルトで開かれるようにするには、「ctrl + ,」を押して ``profiles.json`` を開き、``defaultProfile`` を変更します。

他にも、

* ``colorScheme`` を設定して見やすい色に変更
* ``startingDirectory`` で初期のディレクトリを設定
* ``keybindings`` を追加して ``ctrl+c`` と ``ctrl+v`` でコピペできるように(既定では ``ctrl+shift+c/v``)

を変更しています。Windows Terminal はこの ``profiles.json`` を編集することでいろいろカスタマイズできるので楽しいですね。参考までに私の設定を載せます。

**profiles.json**

```json
{
    "$schema": "https://aka.ms/terminal-profiles-schema",

    "defaultProfile": "{2c4de342-38b7-51cf-b940-2309a097f518}",

    "profiles":
    [
        ＜中略＞
        {
            "guid": "{2c4de342-38b7-51cf-b940-2309a097f518}",
            "hidden": false,
            "name": "Ubuntu",
            "colorScheme": "Campbell",
            "cursorShape": "emptyBox",
            "acrylicOpacity": 0.85,
            "useAcrylic": true,
            "cursorColor": "#FFFFFF",
            "fontFace": "Cascadia",
            "fontSize": 12,
            "startingDirectory": "C:\\dev",
            "source": "Windows.Terminal.Wsl"
        }
    ],
    "schemes": [
        {
            "name": "Campbell",
            "foreground": "#F2F2F2",
            "background": "#0C0C0C",
            "colors": [
                "#0C0C0C",
                "#C50F1F",
                "#13A10E",
                "#C19C00",
                "#0037DA",
                "#881798",
                "#3A96DD",
                "#CCCCCC",
                "#767676",
                "#E74856",
                "#16C60C",
                "#F9F1A5",
                "#3B78FF",
                "#B4009E",
                "#61D6D6",
                "#F2F2F2"
            ]
        }
＜中略＞
    ],

    // Add any keybinding overrides to this array.
    // To unbind a default keybinding, set the command to "unbound"
    "keybindings": [
        { "command": "copy", "keys": [ "ctrl+c" ] },
        { "command": "paste", "keys": [ "ctrl+v" ] }
    ]
}
```

## 3. VScode の Default Terminal を WSL に

WSL を導入すると Visual Studio Code の Terminal にも "wsl" が増えているので、``ctrl + shift + p`` → ``Terminal:Select default shell`` で、"wsl" に変更します。

なお、``.code-workspace`` に Terminal を指定することでワークスペース毎に Terminal を切り替えることもできるようですが、wsl が入っていない環境もあるので、私はあまりオススメしません。


## 4. VSCode のタスク実行を WSL で 

VScode の Default Terminal を WSL に変更しても、VScode のタスクの実行は、Windows 側で行われてしまうようで、これも WSL 上で実行させたいです。残念ながらこれを解決するには「WSL に依存したタスク」の記述が必要になります。

**./vscode/tasks.json**

```json
{
  "version": "2.0.0",
  "tasks": [
    {
      "label": "ng-serve",
      "type": "shell",
      "isBackground": true,
      "command": "ng serve",
      "problemMatcher": {
        "owner": "custom",
        "pattern": {
            "regexp": "^$"
        },
        "background": {
          "activeOnStart": true,
          "beginsPattern": ".*Angular Live Development Server.*",
          "endsPattern": ".*Compiled successfully.*"
        }
      }
    },
    {
      "label": "ng-serve-wsl",
      "type": "shell",
      "isBackground": true,
      "command": "\"ng serve\"",
      "options": {
        "shell": {
          "executable": "C:\\Windows\\System32\\wsl.exe",
          "args": [ "bash -ic" ]
        }
      },
      "problemMatcher": {
        "owner": "custom",
        "pattern": {
            "regexp": "^$"
        },
        "background": {
          "activeOnStart": true,
          "beginsPattern": ".*Angular Live Development Server.*",
          "endsPattern": ".*Compiled successfully.*"
        }
      }
    }
  ]
}
```

例えば、上記の ``tasks.json`` の例では、Angular のデバッグを行うための ``ng-serve`` というタスクを定義していますが、これは Windows 上で動作してしまうので、それに加えて WSL 上で動作させる設定を加えた ``ng-serve-wsl`` というタスクも用意しています。

WSL版の違いは、``options: { }`` で設定した ``wsl.exe`` の情報で、これはコマンドプロンプトで、

```
wsl.exe bash -ic "ng serve"
```

を実行することに相当します。
重要なのは bash の実行引数 ``-i`` で、これを指定しないと ``.bashrc`` が読み込まれない(= PATH が設定されない)ため、``ng`` が command not found エラーになってしまいます。


## 5. WSL 側に開発環境を構築する

git, node, npm, angular, python, aws-cli, firebase-cli などの開発に必要なツールは、WSL の方に入れていきます。
Ubuntu であれば大抵は apt-get でインストールします。

## まとめとちょっと面倒(冗長)なところ

WSL2 まで待っていようかなと思っていたのですが、WSL1 でも使ってみたらとても便利でした。

開発時によく使う Terminal, VSCode については、ほとんど Windows である事を意識せずに過ごす事ができるようになりました。
スクリプトなどは macOS と同じものがほぼ動きますし、Linux で動作する CI のリハーサルも容易になりました。

Windows との相互運用性が思っていたよりも高く、コマンドに ``.exe`` をつければ WSL 上からでも Windows コマンドが実行できるので、かゆいところに手が届いてるなと感じました(WSL から ``msbuild.exe`` を叩けば Windows でしか動作しない .NET アプリもビルドできるはずだし、そもそも WSL 側に .NET Core を入れてクロスプラットフォームで動作する .NET プログラムの動作確認をする事ももちろん可能です)。


ちょっと冗長なところとしては、

#### git の認証情報を Win/WSL どちらにも記憶させる必要がある

bash で git コマンドを叩くこともあれば、Gitクライアントアプリ([GitKraken](https://www.gitkraken.com/) や VSCode など)を使うこともあり、認証情報ストアを共通にする方法は知らないので、今のところ両方に記憶させています。

#### Windows パスから UNIX パスへの変換

「Windows のエクスプローラでパス名をコピーして、bash で ``cd`` する」ために、次のようなコマンドが必要です。

```terminal
cd $(wslpath -u "C:\dev\hoge")
```

Windows のパス文字列を ``wslpath`` 関数で UNIX パスに変換できるので、これを咬ませてディレクトリ移動しています。

#### チームの他のメンバは Windows の人が多い

ため、彼らの環境でも動作する事を前提にスクリプトを記述する必要がある場合、その動作確認のために PowerShell も併用し、結局 Windows 側にも node をインストールせざるを得なかったりします。
まあ、これはチームの事情です。
それでも、Windows Terminal は、タブで WSL と PowerShell どちらも管理できるので使いやすいです。

## 別解というか本命

VSCode 前提ですが、[Remote - WSL Extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-wsl) を利用することで、プロジェクトの開発をすべて WSL上 で行えるようになります。上記で説明した Terminal も、タスクの実行もすべてです。

* [Get Started with C++ and Windows Subsystem for Linux in Visual Studio Code](https://code.visualstudio.com/docs/cpp/config-wsl)
* [Developing in the Windows Subsystem for Linux with Visual Studio Code](https://code.visualstudio.com/docs/remote/wsl)

現在はまだ Preivew 版のため安定性が不安であること、リモート前提なため WSL でもなんか遅そう(主観です)な事、VSCodeの拡張機能がモノによってはリモート用をさらにインストールする必要があるなど、やや気になる点があるために少し試しただけで保留としました。