SAP Cloud Platform Cloud FoundryでVueを動かす方法

#はじめに
タイトルのとおり、SAP Cloud PlatformでVueアプリを動かしたいなぁというのが動機です。
普通に考えると、コイツもただのWebアプリなんだから、HTML5モジュールとしてデプロイしたら動くはずなのですが、専用のプラグインを発見しました。無理やりMTAプロジェクトをいじるより、プラグインのほうがスマートに違いない！ということで、早速動かしてみました。

#アーキテクチャ
こんな感じのものを作ります。
![VueSAP.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319797/2ab9a119-fc89-b20e-4fd8-f71de8d403b5.png)

#作り方
##事前準備
いくつか環境構築が必要なのですが、ここではさらっと列挙だけしておきます。

* SAP Cloud Platform on Cloud Foundryのtrialアカウントを作成する
* trialアカウントのCFを有効化して、orgやspaceを作成し、必要リソースを割り当てる
* 開発PCにCloud Foundry CLI、Node.js、npm、Vue CLIをインストールする
* SAP NPM registryを設定する

##1. Approuterを作る
Vueプロジェクトを作成します。

```terminal
$ vue create my-approuter --default
```
上で作成したプロジェクトにプラグインをインストールします。アカウントや関連サービスの名前の入力を求められるので、自分のアカウント（sxxxxxxxxxxtrial）とサービス名（ここではデフォルトにしました）を入力します。

```terminal
$ vue add scp-cf-approuter
```
SAP Cloud Platformで、xsuaaサービスインスタンスとdestinationサービスインスタンスを作成します。
manifest.yamlから、approuteerの依存サービスが分かります。
サービスインスタンス名は、yamlに定義されている名前と一致させる必要があります。

```yaml
# manifest.yaml
---
#application settings
applications:

#approuter settings
- name: approuter                             
  memory: 128M                                
  routes:                                     
    - route: approuter-sxxxxxxxxxxtrial.cfapps.eu10.hana.ondemand.com
  env:                                        # env variables 
    TENANT_HOST_PATTERN: 'approuter-(.*).cfapps.eu10.hana.ondemand.com' 
    SAP_JWT_TRUST_ACL: '[{"clientid":"*","identityzone":"*"}]'
  services:                                   # binded services 
    - my-xsuaa           # instantie to uaa service 
    - my-destination

```
Service MarketplaceからAuthorization and Trust ManagementとDestinationのタイルをクリックして、New Instanceからインスタンスを作成します。Destinationのタイルが見えない場合は、リソースが割り当たってないので、EntitlementsでDestinationを追加します。Destinationには、アプリのURLを定義します。まだこの時点ではアプリを作っていないので後から設定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319797/d632d3da-3c3f-3189-1214-c584455f4584.png)

インスタンスが作成されると、Service Instancesに表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319797/c1262bfe-5594-43b1-13f0-9c4a2dc3190f.png)

あとはapprouterをビルド＆デプロイするだけなのですが、そのままだと以下のようなエラーでデプロイに失敗しました。

```terminal
   -----> Installing binaries
          engines.node (package.json): 9.9.X
          engines.npm (package.json): 5.6.x
          **ERROR** Unable to install node: no match found for 9.9.X in [8.15.1 8.16.0 10.15.3 10.16.0 12.3.1 12.6.0]
   Failed to compile droplet: Failed to run all supply scripts: exit status 14

```
なので、package.jsonを修正します。ここでは、8.15.Xにしました。

```json
{
  …
  "engines": {
    "node": "9.9.X", // ここを対応しているバージョンに変更する
    "npm": "5.6.x"
  }
}

```
デプロイします。ログインしていない場合は、cf loginでログインしてください。

```terminal
$ npm run build && cf push
```

##2. Appを作る
Vueプロジェクトを作成します。

```terminal
$ vue create my-app
```
上で作成したプロジェクトにプラグインをインストールします。アカウントや関連サービス名を聞かれるので、設定します。xsuaaサービスは、前手順で作成したxsuaaサービス名を入力します。それ以外は、今回使用しないので一旦デフォルトのままでOKです。

```terminal
$ vue add scp-cf-approuter
```
サービスの依存関係を潰さないとデプロイエラーになるため、ソースを少し手直しします。また、Vuetifyの初期化エラーのためデプロイできても何も表示されないという現象が発生したので、そこも直しておきます。

まず、manifest.yamlから使わないサービスをコメントアウトします。

```yaml
---
#application settings
applications:

- name: myapp                
  routes:
    - route:  https://myapp-p2001700579trial.cfapps.eu10.hana.ondemand.com
  memory: 128M                                 
  env: 
    SAP_JWT_TRUST_ACL: '[{"clientid":"*","identityzone":"*"}]'
    SAP_SCC_LOCATION_IDS: '[""]'
    SAP_SCC_BACKEND_DESTINATION: 'mycompany_sap_dev'
  services:                                    
    - my-xsuaa            
    #- my-connector-company # これをコメントアウト

```
src/main.jsを編集します。

```diff
import Vue from 'vue'

import axios from './plugins/axios'
Vue.prototype.$http = axios;


- import './plugins/vuetify'
+ import Vuetify from "vuetify";

import App from './App.vue'
import router from './router'
import store from './store'
import './registerServiceWorker'

Vue.config.productionTip = false
+ Vue.use(Vuetify);
+ const opts = {};

new Vue({
  router,
  store,
+  vuetify: new Vuetify(opts),
  render: h => h(App)
}).$mount('#app')

```
デプロイします。

```terminal
$ npm run build && cf push
```
##3. Destinationを設定する
my-destinationにアプリのURLを設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319797/7f2ede79-93e4-adb2-1304-b11608ae58f5.png)
ちなみに、manifest.yamlで環境変数として渡すこともできますが、not recommended とのことです。

```yaml
    destinations: >
      [
        {
          "name":"myapp",                                             
          "url":"https://myapp-s0000000000trial.cfapps.eu10.hana.ondemand.com/",    
          "forwardAuthToken": true                                    
        }
      ]
```

##4. 動かしてみる
approuterのURLにアクセスします。認証後、Welcome to your approuterと表示されればOKです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319797/542361a8-f856-c5c8-4e3b-673784f16080.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319797/031a3f62-104b-f400-b62b-379467d22a26.png)
approuter経由でアプリケーションを呼び出します。Welcome to your appと表示されればOKです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319797/d43d60fd-7a2c-3485-bfb0-a591a2542d23.png)

#さいごに
VueSAPを動かしてみました。今回は使用しませんでしたが、バックエンドの呼び出しも簡単にできるみたいなので、いろいろやってみたいと思います。

#参考情報
[VueSAP](https://bertdeterd.github.io/vuepress-scp-cf/)