「Zephyr」の版間の差分

提供: Eospedia
移動: 案内検索
(フロントエンドアプリケーションの開発)
(新しいサービスを作る)
 
行349: 行349:
  
 
== Tips ==
 
== Tips ==
=== 新しいサービスを作る ===
+
=== 新しいserviceを作る ===
 
# /front-end/app/scripts/services/ServiceName.tsという名前のファイルを作る。
 
# /front-end/app/scripts/services/ServiceName.tsという名前のファイルを作る。
 
# /front-end/app/scripts/entry.ts中で、作ったファイルをimportする。
 
# /front-end/app/scripts/entry.ts中で、作ったファイルをimportする。
 
# /front-end/app/scripts/refernce.tsに作ったファイルのreferenceタグを書く。
 
# /front-end/app/scripts/refernce.tsに作ったファイルのreferenceタグを書く。
 
# /front-end/app/scripts/App.tsで、作ったserviceをzephyr moduleに追加する。
 
# /front-end/app/scripts/App.tsで、作ったserviceをzephyr moduleに追加する。

2016年3月30日 (水) 18:58時点における最新版

概要

 EosコマンドをWebブラウザ上で実行するためのアプリケーションである。 EosはCUIで実行する場合、OptionControlFileに基づいて実行時引数を解析している。 Zephyrでは、Webブラウザ上で動作するUIパーツをOptionControlFileを用いることで自動的に生成する。 OptionControlFileはそれぞれのコマンドのOptionControlFileを事前にJSON形式にパースし、Zephyrプロジェクトディレクトリの特定のディレクトリに格納してある。 Zephyrでは、JSON形式にパースされたOptionControlFileを使って、Webブラウザを通じてEosコマンドを実行するための様々な機能群を提供する。

必要なソフトウェア

以下のソフトウェアを事前にインストールしておく必要がある。 2016年3月現在、以下のバージョンでの動作を確認している。

  • Eos
  • Node.js v4.2.4
  • Ruby 1.9.3p551

インストール

Node.js(v4.2.4)のインストール

Node.jsのバージョン管理システムnvmを用いてインストールする。(https://github.com/creationix/nvm)

# nvmのインストール
$ wget -qO- https://raw.githubusercontent.com/creationix/nvm/v0.30.1/install.sh | bash
$ source .bashrc
# Node.js(v4.2.4)のインストール
$ nvm install v4.2.4

# .bashrcに追記
$ echo nvm use 4.2.4 >> ~/.bashrc


Zephyrのインストール

$ git clone git://git.osdn.jp/gitroot/eos/zephyr.git
$ cd zephyr
# 必要なnpmのパッケージをインストール

Zephyrでは、Node.jsのライブラリ管理システム(npm) に登録された様々なライブラリを使って開発されている。 事前にインストールしておく必要がある。

$ npm install
# .bashrcに追記し、PATHを通す
$ echo export PATH=/path/to/zephyr/node_modules/.bin:/path/to/zephyr/bin:\$PATH >> ~/.bashrc
$ echo export ZEPHYR_HOME=/path/to/zephyr >> ~/.bashrc

使い方

Zephyrディレクトリ中の/user-specific-files/OptionControlFileにJSONファイルが作成されていない場合、Zephyrを起動する前に、OptionControlFileをパースしておく必要がある。

# OptionControlFileのパース場合
$ zephyr parse
# Zephyrの起動
$ zephyr serve
# デバッグモードでの起動
$ zephyr debug

通常の起動、デバッグモードでの起動ともにWebブラウザを開き、アドレスバーにlocalhost:3000を入力し接続すると利用できます。 デバッグモードは、開発者のためのZephyr起動コマンドです。

ディレクトリ構成

 Zephyrのディレクトリ構成を以下に示す。

├── bin         zephyrコマンドのバイナリへのシンボリックリンク
├── cli         zephyrコマンドのソースコード
├── docker        docker用のファイル群(未実装)
├── front-end      Zephyrのフロントエンドアプリケーション               (ブラウザ上で動くHTML, CSS, JavaScriptなどで作られたアプリケーション)
├── node_modules     npmのライブラリ群
├── package.json     Zephyrのパッケージ情報
├── server        Zephyrのサーバサイドアプリケーション                (Node.jsで作られたアプリケーション)
├── test         テストコード
└── user-specific-files OptionControlFileなど、Zephyrのアプリケーションで利用する静的ファイル

Zephyrは大きく分けて三つのアプリケーションがある。 zephryコマンド、フロントエンドアプリケーション、サーバサイドアプリケーションで、それぞれcliディレクトリ、front-endディレクトリ、serverディレクトリにアプリケーションのソースコードがある。 Zephyrをインストールすると、zephyrコマンドが使えるようにするために、binディレクトリにcli/zephyr(JavaScriptのソースコード)へのシンボリックリンクを配置している。 インストールの際に、zephyr/binディレクトリをPATHに通すので、zephyrコマンドを実行できるようになる。(Zephyrのインストールを参照)

CLIアプリケーションの開発

 zephyrコマンドの種類を増やしたいときは、cliディレクトリにJavaScriptのソースコードを追加する。CLIアプリケーションはNode.js上で実行される。CommanderというNode.jsでコマンドを開発するためのライブラリをベースに書かれている。
 新しくzephyrのサブコマンドを開発する場合、cliディレクトリ内にzephyr-***というファイルを作る。この新しく作ったファイルにchmodコマンドで実行権限を付与すればよい。詳しくは、[tj/commander.js]を参照。

サーバサイドアプリケーションの開発

概要

 Webを通じてEosコマンドの実行をするためのアプリケーションである。全ての操作は、REST APIを通じて行う仕様となっている(一部、コンソールへの出力メッセージを通信する部分のみWeb Socketを利用している)。 [Express]というNode.jsのWebアプリケーションフレームワークを使って開発されている。 サーバサイドアプリケーションで開発するものは、

  • APIエンドポイントの開発(REST APIのアクセスポイント)
  • クラスの開発(特定の処理を行うクラスの作成や既存クラスの拡張)

の二通りがある。

ディレクトリ構成

 ├── api  各APIエンドポイントの処理が書かれたソースコード
├── app.js main部分
├── class 各クラスのソースコードが置いてあるディレクトリ
├── config.js zephyrに関する設定が書かれたファイル
├── express.js expressに関する設定が書かれたファイル
└── routes.js  ルーティングが設定されたファイル           APIエンドポイントの追加などが行われている

app.jsはExpressを使って書かれたサーバサイドアプリケーションの本体で、main関数のような部分です。各種設定ファイルの読み込み、APIエンドポイントの登録(ルーティングの追加)、クラスのインスタンス化、Webサーバの起動などが行われている。

APIエンドポイントの開発

追加

 APIエンドポイントを追加するときは、既存のものにならってapiディレクトリ以下にソースコードを追加してください。 この部分には、httpメソッド(GET, POST, PUT, DELETEなど)のハンドリングを行うコードを書きます。 複雑な処理を書きたいときは、別にクラスを作成しておき、そのクラスで実行を行うようにしてください。 APIエンドポイントの処理では、httpリクエストの処理、エンドポイントでのロジックの実装(必要に応じてクラスを使う)、httpレスポンスの処理を行います。 APIの設計(どのようにエンドポイントを作るか、エンドポイントの命名など)については、[Web API: The Good Parts]や[Webを支える技術 -HTTP、URI、HTML、そしてREST]が参考になります。

テスト

 作成したエンドポイントは、単独でのテストが可能です。[Postman]や[RESTClient]などの、ブラウザの拡張機能を使うことで、任意のエンドポイントに対して、任意のhttpメソッドで実行することができます。様々なパラメータを与えたときに、意図通りのレスポンスが返ってくるかどうかテストできます。
APIエンドポイントのテスト方法として、フロントエンドアプリケーションからアクセスしてみて試す方法があります。 ブラウザ上で動作するJavaScriptをテスト用に書き(フロントエンドアプリケーションに組み込んで)、特定のAPIエンドポイントにメソッドを実行して、Google Chromeデベロッパツール等でレスポンスを確認する、といった方法です。 これは、実際に動くアプリケーションに近いので、やりたくなる方法ではありますが、よくない方法です。 バグがあったときに、テスト用に書いたコードとAPIエンドポイントのコードのどちらにバグがあるのか判断するのが難しくなるからです。 実際に動くフロントエンドアプリケーションにテストコードを組み込むのも同様の理由でよくない方法です。 さらに、実際に動くフロントエンドのコードが汚くなる温床となるので、避けたほうがよいでしょう。 [Postman]や[RESTClient]のようなツールを使って、APIエンドポイントだけを独立してテストするのがオススメです。

一覧

 未編集。

クラスの開発

クラスの利用

 クラスを利用する.jsファイルで、requireすることでクラスを利用することができます。 requireすると、exportされたJavaScriptのオブジェクトを利用することができます。 一般的には、requireするごとにメモリが割り当てられるので、別々の参照先を指すことになるので注意が必要です。 例えば、class1.jsで書いたclass1を、api1.js、api2.js使う場合

// api1.js
var class1 = require('/path/to/class1.js');
// api2.js
var class1 = require('/path/to/class2.js');

api1.js内のclass1とapi2.js内のclass1では参照先が異なるので、それぞれ独立しています。

クラスの追加

 クラスを追加するときは、既存のものにならってclassディレクトリ以下にソースコードを追加してください。 クラスを記述した.jsファイルの最下部では、

module.exports = ******;

と記述することで、他のソースコードでrequireすると利用できるようになります。

2016年3月現在、Eos、DB、WebSocketという三つのクラスでは、どのapiから呼び出すときにも同じオブジェクトを参照したいので、技巧的に同一の参照を取得できるようにしている(デザインパターンのシングルトンで調べてみてください)。

このシングルトン化の方法はNode.jsのモジュールの仕組みを利用した技巧的な方法を利用しています。 詳しくは、[Node.js : exports と module.exports の違い(解説編)]や「CommonJS」、「RequireJS」、「Node.jsのモジュールシステム」等で調べてください。

テスト

下記コマンドをzephyrプロジェクトのディレクトリ内で実行することでテストコマンドを実行することができます。 テストコマンドの実行設定については、package.jsonに記述してあります。

$ npm test

テストには、[mocha]という、JavaScriptのテストランナーと、[chai]というJavaScriptのテスト用ライブラリを利用しています。テスト用のソースコードは、testディレクトリ以下にソースコードを書いてください。

プロダクションのコードでは、クラスは任意のAPIエンドポイントにリクエストがあったときに、APIエンドポイントの処理の中でrequireされ、使われます。 しかし、クラスの開発の際に、サーバを立ち上げてREST APIを叩いてみてテストするとデバッグが困難であるので、REST APIの部分とは独立させてクラスのみでテストを動かす、というフローで開発すると、効率が良くなります。。 テストコード内では、クラスをインスタンス化し、任意の引数でメソッドを実行したときに、適切な振る舞いをしているかどうかテストします。 詳細は、既存のテストコードを読んだり、「TDD」で検索してください。

一覧

 未編集。

フロントエンドアプリケーションの開発

言語、フレームワーク、ライブラリ

フロントエンドアプリケーションの開発では、便利に開発できるようにさまざまなツールを導入しています。フロントエンド開発のツールは、同じツールであってもさまざまな使い方ができることが多いので、Zephyrにおいて、それぞれのツールをどのように使っているかを記します。個々のツールがどういったものかについては、本やブログ記事を読む、既存のコードを読むなどして勉強してください。利用しているツールは以下に示します。

開発言語

  • TypeScript

フレームワーク

  • AngularJS

タスクランナー(C言語でいうmakeのようなもの)

  • Webpack
  • Gulp

TypeScript

フロントエンドアプリケーションの開発には、[TypeScript]という言語を利用しています。TypeScriptとは、静的型付けのないJavaScriptに静的型付けをすることができるようにした言語です。TypeScriptをコンパイルすると、コンパイラがJavaScriptのコードを生成(トランスパイル)します。JavaScriptはインタプリタなので実行時までエラーチェックできませんが、TypeScriptではコンパイラによって事前にエラーチェックをすることができます。Zephyrにおいて、TypeScriptを採用した理由は以下の通りです。

  • 肥大化したアプリケーションの体系化に、TypeScriptのクラス構文を有効であるため。
  • TypeScriptはJavaScriptのソースコードを生成するので、少なくともコンパイル後のコードについてはTypeScriptのバージョンアップにより仕様変更があっても、アプリケーション自体は影響を受けない。

TypeScriptの開発には以下が必要となります。

  1. TypeScriptのソースファイル(.ts)
  2. TypeScriptのコンパイラ
  3. TypeScriptの型定義ファイル
  4. コンパイラに渡すオプション or 設定ファイル

TypeScriptのコンパイラは、npmで事前にインストールしてあります(package.jsonの記述を確認してください)。TypeScriptのソースコードをコンパイル(トランスパイル)するには、コマンドに対してオプションを渡す、もしくは事前に設定ファイルを書いておき設定ファイルと同一のディレクトリでコマンドを実行する、の二通りの方法があります。Zephyrでは、/front-end/tsconfig.jsonに設定を記述しています。TypeScriptでJavaScriptのライブラリ、フレームワークを利用するためには、型定義ファイルが必要となります。有名なJavaScriptのライブラリの型定義ファイルのほとんどは、TSDというTypeScript型定義システムで取得することができます。tsdコマンドを使うことで、型定義ファイルのインストールが可能です。Zephyrでは、/front-end/typingsディレクトリに利用しているJavaScriptのライブラリ(AngularJSやその他関連ライブラリ)の型定義ファイルが置かれています。新しいライブラリを追加するときには、/front-endディレクトリでtsdコマンドを使ってインストールしてください。

AngularJS

 JavaScriptのフレームワーク、[AngularJS]を使って開発しています。AngularJSは学習コストが大きいですが、既存のソースコードを読む、書籍やブログを読むなどして勉強してください。Zephyrでは、TypeScriptとAngularJSを使って開発しているので、AngularJSのソース、TypeScriptで使うAngularJSの型定義ファイルがそれぞれnpmとtsdでインストールしています。

 AngularJSはバージョン1系と2系がありますが、Zephyrでは1系を利用しています。また、AngularJSの概念で「$scope」というものがありますが、バージョン1.4以降では「$scope」を使わず「bindToController」を使うことが推奨されています。Zephyrでは、「$scope」を使わずに、「bindToController」を利用しているので注意してください。

タスクランナーについて

 タスクランナーのWebpack、Gulp.jsで書かれたワークフローは、バグがなければ、既存のコードを書き直さずに、コマンドを叩くだけで継続して利用できると思います。GulpやWebpackは、開発時に発生するさまざまなマニュアル操作(コマンドを叩いてコンパイルする、コンパイルしたコードを任意のディレクトリにコピーする、など)を自動化するのに利用しています。

Webpack

 [Webpack]は、モジュール化を支援するツールです。/front-end/webpack.config.jsにWebpackの設定を記述しています。Zephyrの開発において、Webpackを使って自動化しているのは以下の処理です。

  1. TypeScriptで書かれたソースコードをJavaScriptにコンパイル(=トランスパイル)する。
  2. トランスパイルされたJavaScriptのコードを一つのファイルに結合し、bundle.jsに書き出す。

Gulpの利用

 [Gulp]は、フロントエンドの開発でよく利用されるタスクランナーです。Webpackのみでタスクを記述することもできますが、簡潔に書くことのできるGulpに慣れている、Gulpみので、モジュール管理やTypeScriptのトランスパイルを記述すると面倒、という理由でGulpとWebpackを併用しています。/front-end/gulpfile.jsにGulpの設定を記述しています。Zephyrの開発において、Gulpを使って自動化しているのは以下の処理です。

  1. TypeScriptのソースコードのトランスパイル(Webpackを利用したタスク)
  2. htmlファイルをdistディレクトリにコピー
  3. .sassファイルを.cssファイルにコンパイルし、distディレクトリにコピー
  4. templateディレクトリにある全てのtemplateファイルをdistディレクトリにコピー
  5. 1~4のソースコードの変更監視
  6. デフォルトタスク(= 1~5のタスクを依存関係に考慮し順番に実行する)

参考にしたWebサイト

AngularJS と TypeScript

AngularJS

Webpack

AngularJS と Webpack

TypeScriptとWebpack

TypeScript

ワークフロー

 フロントエンドアプリケーションを用いた開発のワークフローを以下に示します。

  1. .html、.scss、.tsファイルなどのソースファイルの編集
  2. .tsのトランスパイル、.scssのトランスパイルし
  3. アプリケーションに関連する全てのファイルをdistディレクトリに配置
  4. Webサーバを立ち上げる
  5. ブラウザ上でデバッグ

編集したソースコードにエラーがあれば、TypeScriptのトランスパイラやscssのコンパイラからエラーが出力されます(1,2)。2と3のワークフローは全てGulp、Webpackで自動化されています。マニュアルでの操作はほとんど必要ではありません。Webサーバの立ち上げについては、zephyrコマンド(=CLIアプリケーション)で行うことができるようになっています。これらを踏まえた上で、実際のオペレーションを以下に示します。

  1. .html、.scss、.tsファイルなどのソースファイルの編集する
  2. $ gulp を実行する (ワーキングディレクトリが/front-end/app 以下でないと、gulpコマンドの実行は出来ません)
  3. $ zephyr debug でWebサーバを立ち上げる
  4. ブラウザでlocalhost:3000に接続し、アプリケーションを操作しながらデバッグする

ディレクトリ構成

// /front-endディレクトリ

├── app         アプリケーションのソースコードが格納されているディレクトリ
├── dist        プロダクション用のコードが格納されているディレクトリ
├── gulpfile.js     Gulpの設定ファイル
├── tsconfig.json    TypeScriptトランスパイラの設定ファイル
├── tsd.json      TSDの設定ファイル
├── typings       TypeScriptの型定義ファイルが格納されているディレクトリ
└── webpack.config.js  Webpackの設定ファイル
// /front-end/appディレクトリ

├── index.html      メインのhtmlファイル
├── scripts        TypeScriptのソースコードが格納されたディレクトリ
├── style.scss      .scss(コンパイル後、.cssとなる)ファイル
└── templates       AngularJSで利用するテンプレートファイル(.html)
// /front-end/scriptsディレクトリ

├── App.ts        アプリケーションのメインファイル
├── controllers      controllerのソースファイルが格納されたディレクトリ
├── declares.ts      Zephyrで利用する型を定義したファイル
├── directives       directiveのソースファイルが格納されたディレクトリ
├── entry.ts        TypeScriptのソースファイル全てを読み込むentryファイル
├── factories       factoryのソースファイルが格納されたディレクトリ
├── filters         filterのソースファイルが格納されたディレクトリ
├── reference.ts      アプリケーション内で利用するreferenceを記述したファイル
└── services        serviceのソースファイルが格納されたディレクトリ

アプリケーションの構成

 AngularJSでは、controller、service、factory、filterなど、さまざまん機能を持ったコンポーネントを作ることができます。 Zephyrでは、TypeScriptのクラス構文や関数を使って、それらのコンポーネントを開発しました。 /front-end/app/scripts/App.tsがZephyrのアプリケーションのmainファイルです。 App.ts内で、Zephyrアプリケーションのmoduleを作り、利用するコンポーネントをzephyr moduleに追加しています。 zephyr moduleに追加されたコンポーネントは、zephyr module内のどこからでも利用できるようになります。

Zephyrアプリケーションには、三つの画面があり、それぞれexecution、workspace、historyです。 三つの画面は、App.tsの中でstateに登録されていて、それぞれのstateは、

  • localhost:3000/execution
  • localhost:3000/workspace
  • localhost:3000/history

のそれぞれのパスに対応しています。

それぞれのパスにアクセスされたときにそれぞれのstateに登録されたcontrollerが動く仕組みとなっています。

  • localhost:3000/executionへのアクセス → executionController
  • localhost:3000/workspaceへのアクセス → workspaceController
  • localhost:3000/historyへのアクセス → historyController

Zephyrでは、これらのcontrollerをそれぞれのページのメインのcotrollerとして開発しています。 このメインのcontroller中で、コンポーネントを注入し(DI: Dependency Injection)利用しています。 コンポーネントとして登録しておくことで、異なるcontroller中で、コンポーネントを再利用することが可能となり、コードの体系化や開発効率の向上につながります。 例えば、Zephyrは、「MyModal」というモダルウィンドウの操作に関連するserviceがありますが、executionページとworkspaceページの両方で同じコンポーネントを利用しています。 詳しくは、「DI」で検索して勉強してみてください。 また、stateを使ったページ遷移の管理は、[ui-router]というAngularJSのページ遷移を管理するライブラリを利用しているので、詳しくはソースコードを追ったり、ドキュメントを読んだりして勉強してください。

コンポーネントについて

 2016年3月現在、Zephyrで利用されている各コンポーネントについて簡単に説明します。 controller、service、factory、directive、filterというのは、AngularJSの概念なので、それぞれの概念についてはAngularJSののドキュメントは解説記事にて勉強するようにしてください。

controller

 Zephyrでは、stateに登録されたページのロジック管理、serviceのロジック管理、directiveのロジック管理に利用しています。 それぞれのcotrollerは、クラス化されています。 controllerに全てのロジックや操作について記述するのではなく、できるだけ外部のserviceやdirectiveに切り出し、controller内ではそれらのserviceやdirectiveをDIして利用するようにしています。 例えば、executionページのexecutionControllerでは、REST APIを呼び出すためのAPIEndPoint service、モダルウィンドウを呼び出すMyModal serviceなどをDIして利用しています。

service

 template(htmlのパーツ)を伴わない機能を切り出したものです。 それぞれのserviceはクラス化されています。 現在、以下のserviceが開発されています。 serviceの特性上、DIされるたびにインスタンスが生成されてしまうので、メモリリークに注意が必要です。

  • APIEndPoint REST APIの通信を請け負う。
  • Console   CLIでの標準出力を、Webブラウザ上に表示する部分の機能を請け負う。
  • MyModal   モダルウィンドウの部分のロジックや操作などを請け負う。
  • WebSocket  WebSocketの通信の追加や削除などを請け負う。

directive

template(htmlのパーツ)を伴った機能を切り出したものです。 それぞれのdirectiveはクラス化されています。 現在、以下のdirectiveが開発されています。

  • Command  executionページで使われており、各EosコマンドのUIの表示とその操作を請け負う。
  • Directory workspaceページ使われており、各ディレクトリの情報の管理を請け負う。
  • HeaderMenu 全てのページに表示される、ヘッダー部分の管理を請け負う。
  • Option    Command directive中で使われており、EosコマンドのそれぞれのオプションのUIの表示やその管理を請け負う。

factory

 2016年3月現在、Zephyrでは利用していません。 serviceと同じようにtemplateを伴わない機能に切り出しに利用できるが、factoryを使うとアプリケーション中でインスタンスは一つしか生成されません。 Zephyrアプリケーション中で、唯一存在するインスタンスを作りたいときに利用すればよいです。

fillter

 AngularJSで使われているデータ構造を何らかの形でフィルタりんグしたいときに利用します。 現在存在するのは、Tag filterで、コマンド選択画面で選択されたtagを持ったコマンドのみを表示するのに利用しています。 filterは、クラスではなく、関数として定義しています。

API一覧

未編集。

Tips

新しいserviceを作る

  1. /front-end/app/scripts/services/ServiceName.tsという名前のファイルを作る。
  2. /front-end/app/scripts/entry.ts中で、作ったファイルをimportする。
  3. /front-end/app/scripts/refernce.tsに作ったファイルのreferenceタグを書く。
  4. /front-end/app/scripts/App.tsで、作ったserviceをzephyr moduleに追加する。