【SAPUI5】UI5 Toolingを使ってみる

##UI5 Toolingとは
SAPUI5アプリを開発するための環境が2種類あります。

- WebIDE
- ローカルIDE（Visual Studio, Atomなど）

※2020/9/5追記：現在は[SAP Business Application Studio](https://developers.sap.com/tutorials/appstudio-onboarding.html)も使えます。

UI5 Toolingは、ローカルIDEでOpen UI5またはSAPUI5アプリを開発するためのツールです。Node.jsのモジュールとして提供されています。

[GitHub](https://github.com/SAP/ui5-tooling)
[Document](https://sap.github.io/ui5-tooling/)

UI5 Toolingを使ってみるシリーズの記事

- 【SAPUI5】UI5 Toolingを使ってみる（今回）
- [【SAPUI5】UI5 Tooling：ODataへの接続](https://qiita.com/tami/items/78ae7e4233df9fad9a47)
- [【SAPUI5】UI5 Tooling：ABAPサーバへデプロイ](https://qiita.com/tami/items/82973dc5ad54008ebec3)
- [【SAPUI5】UI5 Tooling：コードチェックとオートコンプリート](https://qiita.com/tami/items/5d3944c403ad89e9e75a)


##UI5 Toolingを使ってみようと思ったきっかけ
2019年のUI5conの[動画](https://www.youtube.com/playlist?list=PLHUs_FUbq4dUEwRA9tA8w0cOF0UaDKaKM)を見ていて、登壇者の多くがローカルIDEを使っているのに気づきました。Node.jsはオープンソースなので、さまざまな開発者がUI5関連のモジュールを開発しては公開しているようです。これらのモジュールを試してみるには、ローカルIDE + Node.jsという環境が必要ではないかと思ったのがきっかけです。

なお、私はNode.jsは初心者で、「npm installで必要なモジュールを入れる」という程度の理解です。

###WebIDEで困っていること
私は今のところローカルIDEに乗り換えるまでのモチベーションはないのですが、WebIDEで困ったのは以下の点です。

- SCPの不具合（？）で、Buildができないことがあった
- SCPのパスワードがわからなくなってしまい、不運も重なり丸一日ログインできなかった

WebIDEを使うと自分でコントロールできない部分が出てきてしまうので、それがどうしても困る場合はローカルIDEを使うのもありだと思います。

##環境設定
今回利用した環境は以下です。

- [Visual Studio Code](https://code.visualstudio.com/download)
- [Node.js](https://nodejs.org/en/download/)
- [Git](https://git-scm.com/downloads)

自宅の環境で実施しています。
会社のプロキシ環境では設定が変わるところがあるのでご注意ください。（プロキシ環境での設定内容は以下のブログを参照）

##今回のゴール
以下のブログを参考に、UI5 Toolingをインストールして使ってみます。
[End-To-End setup of local development environment with UI5 Tooling](https://blogs.sap.com/2019/11/05/end-to-end-setup-of-local-development-environment-with-ui5-tooling/)
[End-To-End setup of local development environment with UI5 Tooling – Part 2](https://blogs.sap.com/2019/11/05/end-to-end-setup-of-local-development-environment-with-ui5-tooling-part-2/)

##ステップ
1. 事前準備：グローバルに使うモジュールをインストールする
2. プロジェクトを格納するためのフォルダを作成
3. プロジェクトのテンプレートを生成する
4. 使用するライブラリのバージョンを指定する
5. ソースの変更がすぐにブラウザに反映されるようにする

##1. 事前準備：グローバルに使うモジュールをインストールする
以下のモジュールをインストールします。

[@ui5/cli](https://www.npmjs.com/package/@ui5/cli): UI5 Tooling

```
npm install --global @ui5/cli
```

[generator-easy-ui5](https://www.npmjs.com/package/generator-easy-ui5): UI5プロジェクトのテンプレートを生成するためのツール

```
npm install -g yo generator-easy-ui5
```

##2. プロジェクトを格納するためのフォルダを作成
PC内の任意の場所にUI5プロジェクトを格納するためのフォルダを作成します。
今回は"projects"というフォルダを作成し、ワークスペースに追加しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/38d59f6a-f24b-fd42-6ca2-4e371bc931a6.png)

##3. プロジェクトのテンプレートを生成する
ステップ1でインストールしたEasy UI5 Generatorを使ってプロジェクトのテンプレートを生成します。
ターミナルを開き、プロジェクトフォルダに移動したら以下のコマンドを入力します。

```
yo easy-ui5
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/2e001514-96d4-7c9a-08fb-601809c56dd5.png)

プロジェクトの設定について質問されるので答えていきます。

どのプラットフォームで動くアプリケーションか
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/ac9230c9-19c3-39f8-07cd-66aece52dec6.png)

UI5のライブラリをどこから取得するか
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/33b769bc-c9e5-b72c-2651-93ea00601e7a.png)

プロジェクトのために新しいディレクトリを作るかどうか
Noにすると、現在選択しているディレクトリの直下にwebappフォルダが作成される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/28883377-badf-33c8-f9c3-d4d90c2d312e.png)

プロジェクト名を入力
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/efc742e1-083a-fd43-d73e-6ed7498a7af2.png)

namespaceを入力
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/bd5daa72-76a6-58db-7d34-3f47fa0d04e6.png)

ビューのタイプを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/162ccac2-94af-1418-31f1-e48fed0f37f0.png)

メインビューの名前を入力
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/e8d9789d-fa35-24d2-b85c-f73689858e6b.png)

以上を入力すると、npm installが始まり必要なモジュールがインストールされます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/1d51a049-0684-cc98-c0c9-859fc3362e91.png)

インストールが終わると、以下のようにプロジェクトが作成されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/2802edc0-fb58-08ea-a2c3-17ba3c556243.png)

###実行してみる
カレントディレクトリを新規作成したプロジェクトのルートに移動させます。
以下のコマンドでサーバが起動し、ブラウザでアプリが実行されます。

```
npm start
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/916de115-4b70-11d0-1983-e0c4493f20ac.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/c1755c6e-0c34-5c77-3284-138c4eadf3c3.png)

起動したアプリケーションを終了させるには、`Ctrl + C`と入力します。

##4. 使用するライブラリのバージョンを指定する
ブラウザでSAPUI5のバージョンを確認すると、1.73.2となっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/893bbf15-8752-39d8-1d64-812901e42e94.png)

これは、index.htmlのbootstrapでsrcに指定されたソースが持っているバージョンです。CDNから取得しているので、CDNで利用可能な最新のSAPUI5のバージョンになっていると思われます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/a7870e86-37f9-4788-10a2-447c0f93b15c.png)

プロジェクトでは使用するUI5のバージョンを固定したい場合もあるので、ライブラリのバージョンを指定する方法を見ていきます。

＜ステップ＞
1. package.jsonでバージョンを指定する
2. sapui5-runtimeをインストールする
3. bootstrapのsrcをローカルにする
4. ui5-middleware-servestaticをインストールする

###package.jsonでバージョンを指定する
sapui5-runtimeをインストールする前（※）にまず、package.jsonファイルに以下を追加します。versionには、以下に記載のある有効なバージョンを指定します。
https://tools.hana.ondemand.com/#sapui5

```json
        "sapui5-runtime": {
                "version": "1.74.1"
        }     
```

###sapui5-runtimeをインストールする
[sapui5-runtime](https://www.npmjs.com/package/sapui5-runtime)は、SAPUI5 runtimeを以下からダウンロードしてくれるモジュールです。
https://tools.hana.ondemand.com/#sapui5

以下のコマンドを実行すると、SAPUI5 runtimeをダウンロードして解凍してくれます。（結構時間がかかります）

```
npm install -D sapui5-runtime
```

※sapui5-runtimeをインストールしてからバージョンの指定を変えたい場合は、`npm rebuild`を実行する必要があります。

インストール終了後、プロジェクトの中のnode_modulesフォルダ配下に以下のフォルダが作成されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/936b6ed4-0c98-35ce-ef93-4aea318e8e3b.png)

###bootstrapのsrcをローカルにする
Easy UI5 Generatorでプロジェクトを作成するときにContent delivery network (SAPUI5)を選択したので、index.htmlのbootstrapでは以下のように、CDNからsap-ui-core.jsを取得するようになっています。sap-ui-core.jsの参照先を上のステップでダウンロードしたリソースに変更したいので、まずは以下のように書き換えます。

変更前

```html:index.html
		<script id="sap-ui-bootstrap"
			src="https://sapui5.hana.ondemand.com/resources/sap-ui-core.js"
			...>
		</script>
```

変更後

```html:index.html
		<script id="sap-ui-bootstrap"
			src="../resources/sap-ui-core.js"
			...>
		</script>
```

###ui5-middleware-servestaticをインストールする
[ui5-middleware-servestatic](https://www.npmjs.com/package/ui5-middleware-servestatic)はUI5 Toolingの拡張で、これを使うとローカルにダウンロードしたUI5のリソースを参照することができます。ui5-middleware-xxxという名前で複数の拡張が用意されています。（詳しくは[こちら](https://github.com/petermuessig/ui5-ecosystem-showcase)）

以下のコマンドを実行します。

```
npm install ui5-middleware-servestatic --save-dev
```

package.jsonに以下を追加します。

```json
"ui5": {
        "dependencies": [
          "ui5-middleware-servestatic"
        ]
      }
```

全体はこんな感じになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/47e4a545-37fa-0fb7-b571-ff65cf1718cf.png)


ui5.yamlに以下を追加します。

```yaml
server:
  customMiddleware:
  - name: ui5-middleware-servestatic
    afterMiddleware: compression
    mountPath: /resources
    configuration:
      rootPath: "./node_modules/sapui5-runtime/lib/resources" <-ステップ2でダウンロードしたモジュールのパス
```

全体はこんな感じになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/d8d940da-0869-ded6-1e10-c3d8af78fd41.png)

###実行してみる
再び`npm start`を実行します。
バージョンを確認すると1.74.0となっており、さきほどと変わったのがわかります。
（指定したバージョンは1.74.1でしたが、なぜ1.74.0になっているのかはわかりませんでした・・・）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/375db1dc-078d-87c6-1b8f-c274b0a0ff65.png)

###複数プロジェクトで同じruntimeを参照するには
上の手順ではプロジェクト単位にSAPUI5のruntimeをダウンロードしていました。runtimeに関しては、開発中はローカルにダウンロードした一つのソースを参照すれば、都度ダウンロードする手間がはぶけます。
そこで、node_modules配下にあったsapui5-runtimeをprojectフォルダと同じ階層に移動して、以下のように参照します。こうすると、複数のプロジェクトで同じruntimeを参照することができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/a9aa5e16-2d55-032a-9640-44a3083be7b0.png)

```yaml
server:
  customMiddleware:
  - name: ui5-middleware-servestatic
    afterMiddleware: compression
    mountPath: /resources
    configuration:
      rootPath: "../../sapui5-runtime/lib/resources"
```
この場合、sapui5-runtimeへのdependencyは取ってしまってかまいません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/d04a225e-ea10-fa3c-2b7b-d86822830ded.png)

##5. ソースの変更がすぐにブラウザに反映されるようにする
ここまでは、ソースに何か変更をするたびにブラウザのリフレッシュが必要でしたが、[ui5-middleware-livereload](https://www.npmjs.com/package/ui5-middleware-livereload)という拡張を入れると、自動的にブラウザをリフレッシュしてくれます。

以下のコマンドを実行します。

```
npm install ui5-middleware-livereload --save-dev
```

package.jsonのui5>dependenciesの中に以下を追加します。

```json
"ui5": {
  "dependencies": [
    // ...
    "ui5-middleware-livereload",
    // ...
  ]
```

全体はこんな感じになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/543e78eb-b59a-3005-76e3-acae911c8868.png)

ui5.yamlに以下を追加します。

```yaml
  - name: ui5-middleware-livereload
    afterMiddleware: compression
    configuration:
      debug: true
      ext: "xml,json,properties"
      port: 35729
      path: "webapp"
```

全体はこんな感じになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/a6af664f-870b-701e-6896-9ee5820c7a4e.png)

###実行してみる
再びnpm startを実行します。コンソールにLiveReloadが起動したことが表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/1172921b-993e-f5a2-427c-0c14c019c3ee.png)


LiverReloadはうまくいかない場合があり（原因不明）、アプリに変更を加えてもブラウザがリフレッシュされません。`npm start`を何度か再実行したり、うまくいっている別のアプリを起動してから起動しなおすと、うまくいくことがあります。
うまくいっているときは、以下の赤枠のメッセージが表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/38b087a9-89b7-fd14-515d-2edc54448bc2.png)

この状態でビューに変更を加えると、ブラウザが自動でリフレッシュして変更が反映されます。

```xml:App.view.xml
	<App id="idAppControl">
		<pages>
			<Page title="{i18n>title}">
				<content>
					<Text text="testA" />
				</content>
			</Page>
		</pages>
	</App>
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/41feff5c-c3b9-77a6-e741-5808d2c3256d.png)