Typescriptをいろいろ試してみた

ゴールデンウィークを利用して、Typescriptをいろいろ試してみました。
JavaScriptでWebアプリケーションを構築する際のベースとして使っている、Nodeyardと同じような感じで使える、Typeyardを作ってみました。

以下の方針で作っています。

  • クライアントサイド、サーバサイド共にTypescriptで記述する
  • クライアントサイドはWebpackを使う
  • スクランナーを利用せず、npm run scriptでビルドする

テストやソースチェック、devサーバなどひとまず自分が使いたい機能は用意することができました。
その中で気付いたことなどを、雑多になりますが書いていきます。

tscが少し使いづらい

Typescriptのコンパイラであるtscの設定が、少し柔軟性に欠ける。

tsconfig.jsonコンパイル対象のファイルをfilesで、除外するファイルをexcludeで指定するのですが、この2つを組み合わせて使うことができません。また、globなどを使ってパターンで指定することができず、ファイル名かディレクトリ名を直接指定することしかできません。

サーバサイドのコードは、ファイルごとにコンパイルして特定のディレクトリに出力したいのですが、クライアントサイドのコードはWebpackを使ってビルドするため、コンパイル対象に含めたくはありません。
excludeに、node_modulesなどと一緒にクライアントサイドのコードのディレクトリを指定すればコンパイルは問題ないのですが、atom-typescriptがtsconfig.jsonを見て動いているようで、クライアントサイドのコードでコード保管等が動いてくれなくなります。

今回は、tsconfig.jsonatom-typescriptとWebpackが参照するから定義はするけれども、実際にサーバサイドのコードをコンパイルする際は、cliでパラメータを渡すようにしました。
サーバサイド用のconfigファイルを定義してそれを指定する…ということができればよかったのですがそれもできない模様。
/src/app.tsというエントリーファイルを用意して、依存するファイルのみコンパイルされるというような形にしています。

Webpackが便利

今回初めてWebpackを使ってみたのですが、いい感じかも。
アプリケーションが利用するスタイルシートや画像などのリソースも一括して管理できるので、クライアントサイドのビルドタスクをいろいろ定義せず、1つで済ますことができるのは非常に便利。
file-loaderで画像をディレクトリ構造や名前を維持したまま、特定のディレクトリに出力することができるので、expressのテンプレートエンジンから利用するのも問題ない感じ。
全体的な考え方は、Reactととても相性が良いと思います。

Express + Typescript

typingsでexpress、express-serve-static-core、serve-static、node、mimeを--save --ambientオプションでまずはインストール。あとは利用するミドルウェアの型定義を適宜インストール。
今回試した範囲では、特に問題は発生せず。
Expressのオブジェクトを利用する関数を定義するときなどは、型を確認して明示的に指定しないといけないけれど、Expressのオブジェクトやメソッドを利用する場合は、型推論が賢くてほぼES6と同様の書き方で大丈夫っぽい。
エラー生成でhttp-errorsを試してみたけど、最終的なエラーハンドリングを行う箇所で、

app.use((err: Error, req, res, next) => {
  const error = err as HttpErrors.HttpError;

  res.status(error.status || 500);

  const params = {
    error: (process.env.NODE_ENV !== "production") ? error : null,
    message: error.message
  };

  if (/^\/api/.test(req.originalUrl)) {
    res.send(params);
  } else {
    res.render("error", params);
  }
});

のようにダウンキャストすることで利用可能。
コンパイルされたコードには型チェックは含まれなので、問題なく動作します。

特にORM系に動的にプロパティを生やすライブラリが多いのですが、それらをTypescriptでどう扱うのかは要確認。
コンパイルを通すために、何らかの型定義が必要なのかも。

React + Typescript

React自体がコンポーネントを定義して組み立てるという思想なので、各コンポーネントのstateやpropsが型で明示的に示されるのが非常に便利。
atom-typescriptでは、tsxのテンプレートリテラルでpropsの候補まで表示してくれるのではかどります。
reduxを使ったパターンとかは今後検討する予定。

SwiftyEventsのSwift 2.2への対応 +α

自作のSwiftのライブラリ、SwiftyEventsSwift 2.2への対応を実施しました。

対応と言っても、

  • protocol内の"typealias"を"associatedtype"に置き換え 参考
  • テストコード内のインクリメント(++)を"+= 1"に置き換え 参考

に対応しただけでしたが。

Swift 2.2では非推奨の記述を用いていたとしてもWarningとなるだけで、ソースコードのビルド自体は可能です。
ただ、Swift 3.0では後方互換は切り捨てられるようなので、徐々に対応は必要だと思われます。参考


+αとして、Carthageで管理しているサードパーティーライブラリのXcode 7.3での利用について。

メジャーなライブラリはだいぶ対応が進んできてると思いますが、まだ対応していないライブラリをXcode 7.3で利用する場合。
CarthageにはPrebuildという機能があり、プレビルドされたバイナリがGithubに存在する場合は、自動的にそちらを利用するようになっています。
そのため、プレビルドがXcode 7.3より以前のバージョンでコンパイルされていた場合、Xcodeの新しいバージョンでリビルドするようにという警告が出て、アプリをビルドすることができません。
そのような場合、carthage update --no-use-binariesのように、--no-use-binariesフラグをつけて実行することでプレビルドを利用せずに、チェックアウトしたプロジェクトを手元でコンパイルしたバイナリを利用できるようになります。
Swift 2.2で非推奨になった記述を含んでいる場合はビルド時に幾つかのWarningが表示されますが、コンパイル自体は問題なく実行され、アプリケーションに組み込むことが可能となります。

Raspberry Pi で iBeacon を発見するための調査メモ

近いうちに試してみることになるかもしれないのでメモ。

Raspberry PiBluetoothを使えるようにするために

Raspberry Pi を Bluetooth Low Energy (BLE) の Peripheral として動作させるで、BLE の Peripheral として動作させたことはあるので参考に。

RPi Bluetooth LE が詳しい。

あとはこのあたりを参考に。
https://github.com/sandeepmistry/noble#prerequisites

apt-getで BlueZ をインストールできるが、バージョンが 4.99 で BLE のサポートが完全ではないらしい。
BLE のスキャニングだけならおそらく問題はないと思うけど、使えない場合はビルドが必要。

Node.js でプログラミングするために

sandeepmistry/node-bleacon でいけるっぽい。
スキャニングは Central モジュールの noble に、発信は Peripheral 側の bleno に依存している。

UUID を指定しなくてもスキャニングは可能。…というか実装を見てみたら、全部取得してから通知するかどうかの判断をしている模様。
UUID は配列で複数渡すこともできるから、違う種類の iBeacon が混在していても大丈夫そう。

iBeacon と Raspberry Pi の距離の測定

node-bleacon では MeasuredPower や RSSI の値を取得可能。
ただし、それらの値だけでは距離の算出は難しい。

iBeaconのRSSIでiPhoneの二次元座標をとれたらいいな
屋内測位をやってみました

大雑把な距離なら proximity を使えばいいけど、具体的な距離を出したい場合はキャリブレーションが必要っぽい。
Raspberry Pi では収集だけして、フィンガープリンティングの値の設定と距離の算出をサーバ側でするようにしたら個別にソースをいじらなくてもいいかも。

Node.jsのあれこれ

今のプロジェクトで、Node.jsを使ったAPIサーバの開発を行っていて、その時のいろいろをメモ。

Node 5.0.0への対応

プロジェクトではv0.12.7で開発を進めているけど、自分で使っているBoilerplateはv5.0.0に対応を。
node_modulesのディレクトリ構成が変更になっていて、従来までnpmが依存するパッケージはそのnpmのnode_modulesに配置されていたのが、全てnode_modules直下に配置されるように。
アプリケーションでの利用はほとんど影響はないと思うけど、利用しているnpmの依存パッケージを直接利用している場合は注意が必要。
gulpタスクでBabelのRequire Hookを利用するのに、gulp-babel内部のbabel-coreを呼び出している部分はパスの修正を実施。

Bable 6.0への対応

Babel 6.0からトランスパイルの部分がモジュール化され、別途インストールする必要が。
Babel 5と同様の変換を行うプリセットが提示されていたので、ひとまず"es2015", "react", "stage-2"をpresetsに指定。
また、Require Hookで利用する際にもpresetsなどを指定する必要があり。
インポート時に指定でできるけど、gulp-babel等で同じことを複数箇所に書くのは嫌なので、.babelrcに設定をまとめて記述。
package.jsonと同じディレクトリに配置しておくと、gulp-bableやbabelify、Require Hookなどでの実行時に、それを見に行ってくれる。

以下を参考に。
6.0.0 Released
FAQ
babel6での変更点 Gulp・Webpackの設定

export defaultの挙動

ECMAScript 2015の仕様として、export default xxxmodule.exports.default = xxxとなる。
Babelによって変換されたコードは当然このように変換されるので、CommonJSのvar xxx = require('./xxx')でインポートするとxxx = { default: xxx }となる。
require('./xxx').defaultとするか、エクスポートする側でmodule.exports = xxxとするか。
もしくはES2015 modules to CommonJS transformプラグインに追加。
Nodeyardではexpress-generatorで出力された/bin/wwwがインポートする対象の、app.jsだけCommonJS形式のエクスポートとしている。
全部変換の対象にすればいいのだろうけど。

Sequelizeで既存のテーブルにアクセス

sequelize-clisequelize initでModelへのエントリーポイントとなる/models/index.jsを生成。
あとは手動なりコマンドなりで、/modelsディレクトリに、index.jsが読み込める形式でModelの定義していく。

テーブル定義がスネークケースとなっているのをキャメルケースとして扱いたいこと、timestampが不要なことから、以下を記述。

{
  timestamps: false,
  underscored: true,
  freezeTableName: true,
  tableName: 'table_name',
  associate: (models) => {}
}

idはPostgreSQLのシーケンスを使っているので、idの定義を以下のように。

id: {
  type: DataTypes.INTEGER,
  primaryKey: true,
  autoIncrement: true
}

詳しくはWorking with legacy tablesを。

PostgreSQLでユーザ定義型の確認

以下のSQLで確認できる。

SELECT t.typname, e.enumlabel 
  FROM pg_type t, pg_enum e 
  WHERE t.oid = e.enumtypid;

ここを参照。

MacBook Pro (Retina, 13-inch, Late 2012)にEl Capitanをクリーンインストール

プライベートで使っているMacBook Proに、El Capitanをクリーンインストールしました。
Yosemiteの時から、OSのアップデートのタイミングでクリーンインストールするようにしています。
理由は、開発環境をリセットしたり、インストールするアプリケーションやパッケージを整理したいから。あと、Macを使ってるとストレージを圧迫する「その他」を一掃するため。

クリーンインストールの方法については、去年書いたMacBook Pro (Retina, 13-inch, Late 2012)にYosemiteをクリーンインストールと同じ方法で問題なく行えました。
いくつか聞いていた不具合にも遭遇することなく、スムーズにインストールが完了。

設定の変更と、インストールしたアプリケーションなどをメモ。

システム環境設定

一般

  • 「書類を閉じる時に変更内容を保持するかどうかを確認」にチェック
  • 「アプリケーションを終了するときにウィンドウを閉じる」にチェック
  • 「最近使った項目」を5に変更

Dock

  • 「ウィンドウタイトルバーのダブルクリックで」を「しまう」に
  • 「ウィンドウをアプリケーションアイコンにしまう」にチェック
  • 「Dockを自動的に隠す/表示」にチェック

セキュリティとプライバシー

ファイアウォール

キーボード

  • 「キーのリピート」をもっとも速く
  • 「リピート入力認識までの時間」をもっとも短くs

トラックパッド

  • 全ての項目にチェック
  • 「軌跡の速さ」をもっとも速く

アクセシビリティ

マウス/トラックパッド

トラックパッドオプション

  • 「ドラッグを有効にする」にチェックを入れ、「3本指のドラッグ」を選択

今までトラックパッドの設定でドラッグの方法を選択できていたのですが、El Capitanではアクセシビリティの方に移動しています。

アプリケーションのインストール

Apple Store

Xcodeのインストール後は、ターミナルで以下のコマンドを入力してコマンドラインツールをインストール

$ xcode-select --install

インターネット経由

ChromeはHomebrew Caskでもインストールできるのですが、1Passwordのエクステンションをインストールすることができなかったのでホームページからダウンロードしたものをインストールしています。
Carthageは今まではhomebrewで管理していたのですが、OSのアップデートでSwiftのバージョンが2にあがり、ビルドできなくなってしまったのでここからパッケージをダウンロードしてインストールしています。
インストールしたパッケージを削除する時はMacでインストールしたパッケージを削除するを参考に。

Homebrew

  • git
  • nodebrew

nodebrewでnodeをインストールする際にFailed to create the fileのエラーが出たので、以下のコマンドでディレクトリを作成。

$ mkdir -p ~/.nodebrew/src

Homebrew Cask

以下のコマンドでCaskをインストール

$ brew install caskroom/cask/brew-cask
  • Dropbox
  • iTerm2
  • Atom
  • PSequel
  • AppCleaner
  • Flux
  • CheatSheet
  • Alfred
  • Colors

ひとまずはこんな感じで。
El Capitanになって、画面の切り替えなどがスムーズになったような気が。
ライブ変換は最初は戸惑うけど、変換精度もかなり高くて便利かも。
Split ViewはWindow Tidyを使うから、自分はあまり使わないような気が。左右だけじゃなくって、上下とかも対応していたらよかったのですが。

AWS上の Node.js アプリケーションに HTTPS でアクセス可能にする

9月からのプロジェクトでは AWS を使っています。
今までインフラを扱ったことがほとんどなくて、AWS も今回初めてアカウントを作って恐々触っているレベルですが、タイトルのことは割とすんなりと。
ただやっぱりある程度インフラのことは気にする必要があって、改めて Heroku はおかん。

EC2 インスタンスに Node.js と npm をインストールする

公式のガイドを参考にインスタンスを起動
User Guide for Linux Instances

ssh でアクセスし、まずビルドに必要なライブラリをインストール

$ sudo yum update

$ sudo yum install gcc-c++ make
$ sudo yum install openssl-devel

GitHub からバージョン指定で clone してインストール
yum を使うと v0.10 系となるため、この方法を取っています

$ sudo yum install git

$ git clone --depth=1 -b v0.12.7 git://github.com/nodejs/node.git

$ cd node
$ ./configure
$ make
$ sudo make install

Amazon Linux は root のパスが特殊らしいので、以下の変更を実施

$ sudo su
$ visudo
Defaults    secure_path = /sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin

続いて npm をインストール
Node.js の v0.12.7 にバンドルされているバージョンの npm をインストールし、npm コマンドでアップデートを行いました

$ git clone --depth=1 -b v2.11.3 https://github.com/npm/npm.git
$ cd npm
$ sudo make install
$ sudo npm update -g npm

How to install node and mongodb on Amazon EC2
上記のページを参考にしています。
nodebrew とかを使わなかったのは root のパスの問題と EC2 ならバージョンを上げるのならまた一から作るんだよね、というようなことを考えつつ。
この辺りの考え方はどうなのでしょうか、教えてえらい人。

ELB の作成と SSL 証明書の設定

ELB の作成と証明書の設定は公式のドキュメントの通りに
Developer Guide

SSL 自己証明書の作成

ELB に設定する SSL 自己証明書は、オレオレ証明書をopensslで作る(詳細版)を参考に。

以下のコマンドで秘密鍵、証明書署名要求ファイル、証明書を作成

$ openssl genrsa 2048 > server.key
$ openssl req -new -key server.key > server.csr
$ openssl x509 -days 3650 -req -signkey server.key < server.csr > server.crt

ELB の SSL Termination は、秘密鍵に鍵がついているとダメなのようなので、以下のコマンドで解除

$ openssl rsa -in server.key > server-released.key

AWS で設定する際は、PEM 形式じゃないとだめ。
openssl はデフォルトで PEM 形式で出力されるようなので、cat で秘密鍵と証明書の中身を表示して貼り付け。


インフラ初心者でもいちおうなんとかなるっぽい。
ただセキュリティグループとかどう整理すればいいのかはまだわからない。。
この辺りは多分技術書を読んだ方が早そう。

社内勉強会での発表資料

Apple Watch アプリを開発した時に気をつけたほうがいいなと思ったことを発表しました。