はじめに
今年の7月に、UI5でTypeScriptが使えるようになったとアナウンスがありました。
- UI5Conセッション:Enhanced TypeScript support for UI5 apps - A quick intro
- ブログ:Getting Started with TypeScript for UI5 Application Development
具体的には、@sapui5/ts-types-esmまたは@openui5/ts-types-esmというモジュールでUI5の型情報が提供されており、使うことができます。ただし、両モジュールともBeta Stateとなっており、今後互換性のない変更の可能性があります。よって、個人で試してみるのはいいが、プロジェクトで使うにはまだ早いという段階です。
このブログでは、以下の3点について書きたいと思います。TypeScriptに対応したUI5アプリについては、以下に詳細な説明があります。このブログではエッセンスをかいつまんでお伝えします。
Using TypeScript in UI5 Apps
- TypeScriptに対応したUI5プロジェクトの特徴
- プロジェクトの作成方法
- BTPにデプロイする方法(オプション)
※3.はTypeScriptか否かにかかわらず、UI5プロジェクトをBTPのLaunchpadで使えるようにする一般的な設定です。
1. TypeScriptに対応したUI5の特徴
1.1. そもそも、TypeScriptとは
こちらから引用・翻訳します。
- JavaScriptに型が追加されたもの
- 開発時にだけで使われる(ブラウザには理解されないので、実行前にビルドのステップが必要)
- Microsoftによって開発されたが、オープンソースで広く使われている
特徴は、ソースの中で変数や関数の宣言時に型を明示する必要があるということです。宣言で指定された型と、実際に割り当てようとした変数の型が違った場合、エディタ上でエラーが出ます。これによって、従来は動かしてみないとわからなかった不具合を開発時に知ることができます。
var suomeNumber: number;
始めてTypeScriptを触るという方には、以下のドキュメントがお勧めです。短くまとまっていてコードも載っているのでわかりやすいと思います。
TypeScript for JavaScript Programmers
1.2. UI5はどうやってTypeScriptに対応しているのか
UI5では、@sapui5/ts-types-esmまたは@openui5/ts-types-esmというモジュールによって型情報が提供されます。モジュールの中を見てみると、*.d.ts
というファイルがあり、この中でUI5の部品の型定義がされています。型定義はUI5のドキュメントをベースに生成されています。ドキュメントが完全でないと型の定義がされないので、「問題があれば以下にissuesを上げてください」ということになっています。
https://github.com/SAP/openui5/blob/master/CONTRIBUTING.md#report-an-issue
TypeScriptで書かれたソースは、Babelのプラグインであるbabel-plugin-transform-modules-ui5によって、従来のUI5のコードに変換されます。このプラグインはTypeScriptからJavaScriptへの変換だけでなく、ES6で書かれたコードからES5への変換も行ってくれます。つまり、プラグインを使うことでTypeScriptが使えるだけでなく、ES6でのモダンな書き方もできるようになります。
図:Getting Started with TypeScript for UI5 Application Developmentより引用
UI5に対応させるために必要な設定ファイルや各種モジュールのインストール方法は以下に載っています。
A Detailed Guide to Create a UI5 TypeScript App From Scratch in Five to Ten Steps
ただし、generator-easy-ui5を使えばTypeScriptに対応したプロジェクトを自動で生成してくれるので、裏の仕組みを全て知らなくてもよいと思います。
1.3. TypeScriptに対応したUI5の特徴
TypeScript (+ES6)に対応したUI5のソースには以下のような特徴があります。
モジュールのロードはimport xxx from ...
の形で行う
ES6に対応したおかげで、以下のような書き方ができるようになりました。
//従来の書き方
sap.ui.define(["sap/m/MessageBox"],
function(MessageBox) {
}
//新しい書き方
import MessageBox from "sap/m/MessageBox";
コントローラーはクラスとして定義する
ES6に対応したおかげで、以下のような書き方ができるようになりました。
//従来の書き方
return Controller.extend("namespace.projectName.controller.App", {})
//新しい書き方
export default class AppController extends Controller {}
メソッド定義で引数、および返り値の型を指定する
このように型を明示するところがTypeScriptの特徴です。
//従来の書き方
getMessage: function (name) {
return `Hello, ${name}`;
}
//新しい書き方
public getMessage(name:string): string {
return `Hello, ${name}`;
}
get系のメソッド呼び出しでは、必要に応じてas xxx
でキャストして型を明示する
以下はgenerator-easy-ui5で生成したTypeScriptのプロジェクトに入っているサンプルソースです。
//従来の書き方
this.getOwnerComponent().getContentDensityClass()
//新しい書き方
import AppComponent from "../Component";
...
(this.getOwnerComponent() as AppComponent).getContentDensityClass()
キャストをしなかった場合、以下のようにgetContentDensityClass
がComponentに存在しないというエラーになります。
背景
getOwnerComponent()の返り値はsap.ui.core.Component型です。ただし、sap.ui.core.ComponentにはgetContentDensityClassというメソッドがありません。このメソッドは、sap.ui.core.Componentを拡張したsrc/Component.tsで定義されたものだからです。そこで、getOwnerComponent()で取れるComponentの型を明示することによって、エラーを回避しています。
2. プロジェクトの作成方法
2.1. プロジェクトを生成
generator-easy-ui5を使ってプロジェクトを作成します。ts-app
というのがTypeScriptに対応したプロジェクト用のテンプレートです。
yo easy-ui5 ts-app
以下のように質問に答えます。UI5のバージョンは、デフォルトでは1.90.0が設定されています。UI5Conのセッションの中で、TypeScriptがサポートされるのは1.90以降と言われていました。
? How do you want to name this application? ui5TsDemo
? Which namespace do you want to use? miyasuta
? Which framework do you want to use? SAPUI5
? Which framework version do you want to use? 1.90.0
? Who is the author of the library? Mio Yasutake
? Would you like to create a new directory for the application? Yes
プロジェクトの構造は以下のようになります。通常のUI5プロジェクトだとwebappフォルダ配下にview, controllerなどのリソースが配置されますが、TypeScriptだとsrcフォルダになっています。
easy-ui5を使うと、サンプルソースがあらかじめ入った状態でプロジェクトが生成されます。
src/controller/App.controller.tsを見てみると、TypeScriptに対応したUI5の特徴で紹介した特徴があります。
import MessageBox from "sap/m/MessageBox";
import Controller from "sap/ui/core/mvc/Controller";
import AppComponent from "../Component";
/**
* @namespace miyasuta.ui5TsDemo.controller
*/
export default class AppController extends Controller {
public onInit() : void {
// apply content density mode to root view
this.getView().addStyleClass((this.getOwnerComponent() as AppComponent).getContentDensityClass());
}
public sayHello() : void {
MessageBox.show("Hello World!");
}
}
2.2. 実行
package.jsonには、"start"のコマンドが以下のように定義されています。
"start": "npm-run-all --parallel watch:ts start:ui5"
npm start
でそのまま実行してみましょう。
以下のブラウザ画面が立ち上がり、"Say Hello"ボタンを押すとダイアログが出力されます。
2.3. ビルド
以下のコマンドでビルドします。
npm run build
この結果、distフォルダにビルドされたファイルが作成されます。
App-dbg.controller.jsを見てみると、従来のUI5の書き方になっていることがわかります。
sap.ui.define(["sap/m/MessageBox", "sap/ui/core/mvc/Controller"], function (MessageBox, Controller) {
/**
* @namespace miyasuta.ui5TsDemo.controller
*/
const AppController = Controller.extend("miyasuta.ui5TsDemo.controller.AppController", {
onInit: function _onInit() {
// apply content density mode to root view
this.getView().addStyleClass(this.getOwnerComponent().getContentDensityClass());
},
sayHello: function _sayHello() {
MessageBox.show("Hello World!");
}
});
return AppController;
});
3. BTPにデプロイする方法(オプション)
generator-easy-ui5で生成したTypeScriptのプロジェクトには、デプロイに必要な設定が入っていません。BTPのLaunchpadから利用できるようにするため、以下の設定を行います。
3.1. index.htmlを修正
デフォルトでは、sap-ui-core.jsをローカルのリソースフォルダから持ってくる設定になっています。Launchpadから実行する場合はこのままでよいですが、HTML5 Appsメニューから実行する場合はindex.htmlが使われるので、取得元を以下のように変更する必要があります。
元の状態
src="resources/sap-ui-core.js"
これを、CDNからの取得に変更します。
src="https://sapui5.hana.ondemand.com/resources/sap-ui-core.js"
3.2. xs-app.json
srcフォルダの直下にxs-app.jsonファイルを追加します。
{
"welcomeFile": "/index.html",
"routes": [
{
"source": "^(.*)",
"target": "$1",
"authenticationType": "xsuaa",
"service": "html5-apps-repo-rt"
}
]
}
3.3. manifest.jsonを修正
Launchpadで使うため、crossNavigation、およびsap.cloud.serviceの設定を追加します。
"sap.app": {
...,
"crossNavigation": {
"inbounds": {
"intent1": {
"signature": {
"parameters": {},
"additionalParameters": "allowed"
},
"semanticObject": "TypeScriptSample",
"action": "display",
"title": "TypeScript Sample"
}
}
}
...
},
"sap.cloud": {
"service": "ui5tsdemo.service"
}
3.4. ui5-task-zipperの設定
ビルドした結果をzipするための設定です。まず、devDependenciesにui5-task-zipperを追加します。
npm i ui5-task-zipper --save-dev
インストールされたら、package.jsonのui5.dependenciesにも追加します。
"ui5": {
"dependencies": [
"ui5-middleware-livereload",
"ui5-task-zipper"
]
}
ui5.yamlに以下の設定を追加します。
builder:
customTasks:
- name: ui5-task-zipper
afterTask: uglify
configuration:
includeDependencies: false
archiveName: ui5tsdemo
3.5. mta.yamlを作成
デプロイするための設定です。mta.yamlファイルを新規作成します。
※以下のui5tsdemo
は必要に応じて、ご自身のプロジェクト名に置き換えてください
ID: ui5tsdemo
_schema-version: 3.2.0
version: 0.0.1
parameters:
enable-parallel-deployments: true
modules:
- name: ui5tsdemo_deployer
type: com.sap.application.content
path: .
requires:
- name: ui5tsdemo_html5_repo_host
parameters:
content-target: true
build-parameters:
build-result: resources
requires:
- name: ui5tsdemo
artifacts:
- dist/ui5tsdemo.zip
target-path: resources/
- name: ui5tsdemo
type: html5
path: .
build-parameters:
builder: custom
commands:
- npm install
- npm run build
supported-platforms: []
- name: ui5tsdemo_destination-content
type: com.sap.application.content
build-parameters:
no-source: true
requires:
- name: ui5tsdemo_uaa
parameters:
service-key:
name: ui5tsdemo_uaa-key
- name: ui5tsdemo_html5_repo_host
parameters:
service-key:
name: ui5tsdemo_html5_repo_host-key
- name: ui5tsdemo_destination
parameters:
content-target: true
parameters:
content:
instance:
existing_destinations_policy: update
destinations:
- Name: ui5tsdemo_html5_repo_host
ServiceInstanceName: ui5tsdemo_html5_repo_host
ServiceKeyName: ui5tsdemo_html5_repo_host-key
sap.cloud.service: ui5tsdemo.service
- Name: ui5tsdemo_uaa
Authentication: OAuth2UserTokenExchange
ServiceInstanceName: ui5tsdemo_uaa
ServiceKeyName: ui5tsdemo_uaa-key
sap.cloud.service: ui5tsdemo.service
resources:
- name: ui5tsdemo_destination
type: org.cloudfoundry.managed-service
parameters:
service-plan: lite
service: destination
config:
HTML5Runtime_enabled: true
version: 1.0.0
- name: ui5tsdemo_html5_repo_host
type: org.cloudfoundry.managed-service
parameters:
service-plan: app-host
service: html5-apps-repo
config:
sizeLimit: 2
- name: ui5tsdemo_uaa
type: org.cloudfoundry.managed-service
parameters:
path: ./xs-security.json
service-plan: application
service: xsuaa
プロジェクト直下にxs-security.jsonも作成しておきます。
{
"xsappname": "ui5tsdemo",
"tenant-mode": "dedicated"
}
3.6. ビルド、デプロイ
以下のコマンドでビルド、デプロイします。
mbt build
cf deploy mta_archives/ui5tsdemo_0.0.1.mtar
HTML5 Applicationのメニューからアプリを開けるようになっています。
思うこと
Babelのプラグインのおかげで、ES6に対応した書き方ができるようになったということが開発者にとってはうれしいのかな、と思います。これで、バックエンドとフロントエンドでコードの書き方を統一することができます。
また、私自身TypeScriptはほとんど使ったことがなかったので、慣れるため個人開発ではしばらくTypeScriptで書いてみようと思います。
参考
TypeScriptについて
UI5とTypeScript
- UI5でTypeScriptを使うための詳細なガイド:Using TypeScript in UI5 Apps
- TypeScriptで書かれた本格的なUI5アプリ:ui5-cap-event-app
- generatorを使わずにTypeScriptに対応させる方法:A Detailed Guide to Create a UI5 TypeScript App From Scratch in Five to Ten Steps
- UI5Con :Enhanced TypeScript support for UI5 apps - A quick intro
- ブログ:Getting Started with TypeScript for UI5 Application Development