npm scripts 内では zshの**が使えないのでmochaの場合はそのまま渡すこと

npmのpackage.jsonに以下のように書いていたら、明らかに実行されるファイルが少なくてどうしたものかと思っていました。

"scripts": {
  "test": "mocha --opts spec/client/support/default.opts spec/client/**/*.spec.js"
}

理由は詳細には調べてませんが、おそらくこのスクリプトがzshではなくbashで実行されるためでしょう。

npm/npm#10481 によると、mochaは "**" をzsh的な意味で展開するのでそのまま渡せばいいということでした。

はたして以下のように書き換えるとちゃんと動きました。

"scripts": {
  "test": "mocha --opts spec/client/support/default.opts 'spec/client/**/*.spec.js'"
}

Orma v3.0.0-rc1 for Android Studio v2.2 / Android Gradle Plugin v2.2

Orma v2.x は Android Gradle Plugin v2.2 と同時に使えないという問題がありまして、このたびこれを修正した v3.0.0-rc1 を出しました。RCとはいうものの、中身はdeprecated methodsを消したくらいであまり変えていないので、安定性は v2.6.0 と大差ないはずです。

github.com

Orma v3.x は逆に Android Gradle Plugin v2.2 より古いものとは同時に使えないのでご注意ください。

また、Orma v3.0.0-rc1 は RxJava v1.2.0 の、晴れて @Beta となった Completable を使っています。したがって、RxJavaのアップグレードも必要です。

v3.0.0 正規版は #189 を修正したら出すつもりでいます。これがわりと内部的に大規模な変更が必要なので、RCを更にいくつかリリースすることになるかもしれません。

#write_code_every_day の試みから1年たってどうだったか

そういえば write_code_every_day 活動をやろうと思い立ったのがちょうど1年くらい前だったなと思いだしたので振り返りです。

この話をしたのは Rebuild: 120: Swiftonomics (gfx) だったかな?

で、GitHubの草の現状です(ログアウトしてpublic contributionsのみ計測):

https://github.com/gfx

f:id:gfx:20160917220559p:plain

はい、5月くらいまではそれなりに継続して、そのあとしばらく空白の多い日々で、最近また少し復活しているという感じでしょうか。

もともとこの活動は日々のアウトプットを増やすのが目的で、GitHubの草は所詮モチベーションを上げるための小道具としての位置づけです。なので、草を継続するためのハック、たとえば日付変更の前後にわけてコミットして草を稼ぐなどはしないと決めていました。こだわりすぎてストレスを感じたり家族との関係が荒れたりするのは本末転倒ですからね。

実際この活動のおかげでOrmaの開発やブラッシュアップがかなり進んだので、やってよかったなと思いますし、これからも継続的にやっていこうという思いを新たにしました。逆に、デメリットは特に感じませんでした。わりとゆるくやっていたからかもしれませんが、このくらいでいいのかなと思っています。

そういえば、GitHubのアップデートで過去の草も見れるようになったので見てみたのですが、学生最後の年の2010年のコントリビューション数が4000超えていて驚きました。学生時代はそれなりに忙しかったと思っていましたが、やはり社会人とくらべると余暇はあったのだなあと。

f:id:gfx:20160917221734p:plain

最近はどういうaltJsが使われているのか

Twitterでアンケートとりました。偏りはあると思いますが、採用判断の参考にどうぞ。

おおむね6割がJavaScript (or Babel)、2割がTypeScript、1割がCoffeeScript、Flowはだいぶ少ない、という感じでしょうか。

TypeScriptが意外と使われてますね、1割くらいかと思っていました。

dts-gen(1) でJavaScripファイルからdtsを生成する

2016-09-12のJS: Polymer 2.0 Preview、Service Worker入門、JSから型定義ファイルの生成 - JSer.infogen-flow-filesdts-gen を知ったのでちょっとだけ使ってみました。

gen-flow-files (as of flow v0.32.0)

Release v0.32.0 · facebook/flow · GitHub

We're starting work on flow gen-flow-files, which consumes Flow code and outputs .flow files containing only the types exported. It's alpha-level and we're still iterating on it, so use at your own peril!

flow(1)のサブコマンドで、flow type annotation付きのJSファイルから型定義ファイルを抽出するものです。処理対象のコードは、すべて型アノテーション付きでなければいけません。

ふつうのJSファイルには使えないので、何に使うのかよくわかりませんでした。npm packageを作る際、pure JSと型定義ファイルに分割する用でしょうか。TypeScriptはそうしているので。

dts-gen (as of v0.4.16)

GitHub - Microsoft/dts-gen: dts-gen creates starter TypeScript definition files for any module or library.

こちらは独立したコマンドで、素のJSから TypeScript definition files (dts) を生成するコマンドです。

いまのところ入力はglobalにインストールされたモジュールかロードされたシンボルのみなので使い勝手がイマイチですが、説明にある通り手書きでdtsを書く際のスターターとして使い、そのままだとanyが多いので型を書き足していくような使い方を想定していそうです。

たとえばnodejs標準ライブラリのchild_processはこんな感じです。

dts-gen -s -m child_process
export class ChildProcess {
    constructor();
    kill(sig: any): any;
    ref(): void;
    spawn(options: any): any;
    unref(): void;
}
export function exec(command: any, ...args: any[]): any;
export function execFile(file: any, ...args: any[]): any;
export function execFileSync(...args: any[]): any;
export function execSync(command: any, ...args: any[]): any;
export function fork(modulePath: any, ...args: any[]): any;
export function spawn(...args: any[]): any;
export function spawnSync(...args: any[]): any;

class ChildProcess のメソッドはそこそこ揃ってますが、プロパティは全滅ですね。 ChildProcess#disconnect() など見当たらないメソッドもあります。

コードを読んでみると、入力を純粋にJSのオブジェクトとして評価してそこから情報を取り出しているだけの非常に単純なものなのでした。将来的にはフロー解析して型推論してくれるとよさそうです。なお、tscの --allowJs との差などは調べてません。

2016年9月現在だとReactアプリのTypeScript採用は時期尚早(※追記あり)

追記(2019/04/16): 2017年半ばにここで触れているプロジェクトはTSに移行しました。今となってはTS+Reactの組み合わせは全く問題がなく、むしろ非常に相性のよい組み合わせであるとすらいえます。

TypeScript化の調査 2016年9月現在(React v15.3.1, TypeScript 2.0-rc)の話です。

いま開発しているウェブアプリのフロントエンドをTypeScript化しようと思ってちょっと調べてみたんですが、今やるのはいくらTypeScript推進派でもちょっと厳しいなと。

  • TypeScriptでimportできるライブラリは、TypeScriptのコード(.ts)またはdts: TypeScript definition files (.d.ts) のみ
  • Reactは素のJS + 一部FlowType なのでdtsの公式提供は期待できない
  • DefinitelyTypedのdtsは手動でメンテナンスされているよう
    • https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/react
    • これが現在 v0.14 ベースで古い
    • v15.3ベースに修正するにしても作業量が多すぎてつらい
    • 仮に今がんばってv15.3ベースにしたとしても将来にわたって最新版に追従し続けるのがつらい
    • つまりこの規模の大型ライブラリのdtsを手作業でメンテナンスし続けるのはつらい

将来的には、 ReactコードのほぼすべてにFlowTypeアノテーションがついてdtsがそこから自動生成されるというようにはできるだろうと思っているのですが、現状そうではないので、繰り返しになりますが現時点での導入はかなり厳しいと思います。

次のように、v15.3のランタイムとv0.14のdtsを組み合わせてなんとなく動かすことはできるんですが、たぶん茨の道だろうと思いますね…:


追記:

--allowJs でとりあえず導入みたいなのはありかもしれないですね。TypeScriptの恩恵を受けられないので素のJSよりどのくらい楽になるかはちょっとやってみないとわかりませんが。

CircleCIの"Auto-cancel redundant builds"を有効にするとPRごとの冗長なCIをキャンセルできる

2016/7/27 にこんなアップデートがあったようです。

Project SettingsAdvanced Settings に設定項目があります。

f:id:gfx:20160904155004p:plain

With the exception of your default branch, we will automatically cancel any queued or running builds on a branch when a newer build is triggered on that same branch. This feature will only apply to builds triggered by pushes to GitHub.

説明にあるとおり、あるブランチの最新のビルドがトリガーされたとき、そのトリガーされたもの以外の実行中ないしキューにあるビルドをキャンセルする機能です。ただし、デフォルトブランチ(=開発ブランチ)ではこの自動キャンセルを行いません。

pull-requestの更新が多くてビルドキューが増えてしまうようであれば有効にしてみてはいかがでしょうか。というかデフォルト有効でもいいくらいですね。

PlantUML Web APIをSpark Framework + Kotlinなウェブアプリにしてみた

PlantUML を使うとき、 java -jar plantuml.jar だとほんの小さなダイアグラムの生成にも数秒かかってしまいます。ローカルではそれでいいかもしれませんが、ウェブアプリに組み込むのはちょっとイマイチですよね。

PlantUMLはJava製ツールなのでJavaのウェブアプリにしてしまえば高速になるはず、と思ってやってみました。

リポジトリ: https://github.com/gfx/plantuml-service

ウェブアプリといってもパスが /svg/:source しかないような最小限のものです。 :source はPlantUML Text Encodingでエンコードされたソース、または生のPlantUMLソースです。特にキャッシュなどはしませんが、手元のMBAだと小さなダイアグラムの生成で70msほどになったので実用に耐えそうです。

PlantUMLは plantuml-serverというウェブアプリも存在しますが、これはどちらかというとデモなので、純粋にもう少し小さなものが欲しかったのでした。

ウェブアプリケーションフレームワークとしては、SinatraライクなSparkを使ってみましたが、この程度の小さなものだとJettyを直接使っても大差ないかもしれません。Kotlinで書いたのは完全に趣味です。またビルドツールとしてはmavenではなくgradleを使っています。

これはデモも兼ねてHerokuにデプロイしています。Gradleで依存性の解決を行っているので特にKotlin由来の問題はありません。いつものHerokuアプリのように以下のファイルを用意するだけですね。

  • app.json
  • Procfile
  • system.properties (Java8を明示するため)

あとは Deploying Gradle Apps on Heroku | Heroku Dev Centerにしたがって、 build.gradlestage というタスクを用意して、そこでビルドを行うようにします。

以上。まだこれ自体はプロダクションに導入しているわけではありませんが、当初の目的であった高速化は達成できました。PlantUMLをJVMで動くウェブアプリにするというアイデアは効果がありそうです。

TypeScript 2.0+NodeJSツールを開発するときのプロジェクト構成

npm dependenciesを更新してGitHub Compare Viewのリンク付きでPRするツールを定期実行する - Islands in the byte stream

このci-npm-updateはTypeScript 2.0 (beta) で書いたので、TypeScript+NodeJSツールを開発するときのプロジェクト構成の一例としてざっと解説しておきます。

最近はRailsなどのウェブアプリのJSもnpmで管理するようになったため、そういう条件でNodeJSツールを開発することも増えてくることでしょう。

Table of Contents

エディタ

Visual Studio CodeはさすがにTypeScriptサポートはしっかりしていて、次のようにTypeScriptの型定義にしたがって補完をだせます。補完の際に引っかかりを感じることもないですし、構文エラーの指摘なども迅速です。

f:id:gfx:20160731215342p:plain

ただし今回はTypeScript 2.0 betaを使いたいので、 npm install --dev typescript@beta で入れたtypescript language service*1を使うような設定が必要です。

今回は .vscode/settings.json に、以下のようなJSONを設定しました。

{
    "typescript.tsdk": "./node_modules/typescript/lib/"
}

vscodeで本格的にプログラミングするのが初めてなら、ざっとドキュメントも目を通しておくといいでしょう。

とりあえずvscodeで最初におぼえるべきショートカット (for Mac) は command + shift + p (コマンドパレット)です。これはIntelliJ IDEAでいうところの command + shfit + a で、エディタコマンドを検索して実行するためのものです。最初はショートカットを無理におぼえるのではなく、コマンドパレット経由で呼び出すのが楽だと思います。

tsconfig.json

tsconfig.jsonはTypeScript compiler (tsc) に与える設定です。これを適切に設定しておくと、引数なしでtsc(1)を起動してもよしなにビルドしてくれます。

リファレンス:

tsconfig.json · TypeScript

ci-npm-updateでの設定:

ci-npm-update/tsconfig.json at master · gfx/ci-npm-update · GitHub

またtsconfigを作るときにプロジェクトの構成と配布形式を意識することになります。

つまり、今回はnpm distとして配布するので、TypeScriptソースファイルは配布物に含めず、ビルドしたJSと型定義ファイル *.d.ts をパッケージに含めます*2。また開発中は度々ビルドしてJSと型定義ファイルを生成するので、その成果物をどこに置くかを決めます。

成果物はデフォルトだとTSファイルと同じディレクトリにおかれます。このへんは好みだと思うのですが、私はこの挙動を変えたかったので、以下のような構成にしました。

  • src/ - TSファイル。npm distには含めない
  • lib/ - JSファイルと型定義ファイル。npm distに含める

そしてこれにしたがって outDir を設定します。

TSLint

コーディングスタイルを強制するツールです。

Visual Studio Codeのエクステンションを入れると編集中に報告してくれるのではかどります。

TSLint | Visual Studio Marketplace

なおtslintは "tslint:recommended" というプリセットがあるのですが、Visual Studio Codeのデフォルトのフォーマットルールだと警告をだす設定があり、一部変えています。なるべく奨励と銘打たれたスタイルで行きたいのですが、難しいものですね。

ci-npm-update/tslint.json at master · gfx/ci-npm-update · GitHub

Task Runner

今回はシンプルにしたかったし、TSファイルをビルドするだけなのでgulpやgruntは使ってません。そのかわり、npm scriptsを設定してコマンド一つでビルドできるようにしています。

ci-npm-update/package.json at master · gfx/ci-npm-update · GitHub

ビルドの際にtslintも通すようにしているので、たとえばmissing semicolonのよようなちょっとしたtslint違反でもビルドが通らないのですが、このへんは慣れれば減ってくるはずです。

Visual Studio Code Tasks

npm scriptsをvscodeから起動するために .vscode/tasks.json を設定しています。

リファレンス:

Tasks in visual Studio Code

プロジェクトの設定:

ci-npm-update/tasks.json at master · gfx/ci-npm-update · GitHub

(このJSONにはコメントを書けるようだ…)

開発中よく使うのは command+shift+b のビルドコマンドでした。

shrinkwrap

このプロジェクトでは npm-shrinkwrap.json をコミットしていますが、プロジェクトのドッグフーディングのために入れているだけです。。普通のCLIツールやライブラリではこれは不要なので真似しないでください。

所感

TypeScript 2.0とその開発環境は非常に良く出来ていると感じます。もはやES5とは別物といっていいくらい快適ですし、ES2015とくらべても生産性(かけた時間に対する品質のよさ)が高いと思います。

ウェブアプリでもどんどん使っていきたい。

See Also

*1:型定義に基づいた補完などを行うサービスで、TypeScript配布キットに付属しています。

*2:TSファイルも配布物に含めたいところですが、vvakame氏いわく、それをするとtscコンパイラがTSファイルと型定義ファイル両方みにいってしまうという問題があるとか。

npm dependenciesを更新してGitHub Compare Viewのリンク付きでPRするツールを定期実行する

タイトルに要素を詰め込みすぎましたが、要は CircleCIを使ってbundle updateを定期実行する - Qiitanpm update 版です。web appのJavaScriptライブラリ管理にnpmを使うとき、依存関係のアップデートを継続的に行うためのツールです。

https://github.com/bitjourney/ci-npm-update

これはいまのところGitHub専用です*1。CIサービスはドッグフーディングも兼ねてCircle CI用の起動スクリプトを同梱してますが、実際には ci-npm-update を定期実行するだけなので簡単に代替可能です。

これはCircle CI + Heroku Schedulerで動かしていて、以下のようなフローです。Circle CIはJenkins含め他のCIでも動かせますし、Heroku Schedulerはcronなどでも代替できます。

  1. Heroku Schedulerはci-npm-updateを実行するためのパラメータを渡してCircle CIのビルドを起動する
  2. ビルドのdeploymentフェーズで ci-npm-update --execute を実行する
  3. ci-npm-updateは npm-shrinkwrap.json を削除したあと npm install をしなおす((npm update --depth 9999 のほうが効率がいいはずなのですが、こちらはある程度の規模のプロジェクトだとOOMで落ちてしまうので npm install しなおすことにしました。))
  4. ci-npm-updateはさらに npm shrinkwrap で依存関係のバージョンを固定し、変更をcommitし、pushし、githubのpull-requestをつくる
  5. このときpull-requestはアップデートの前後のnpm-shrinkwrap.jsonをもとにgithub compare viewへのリンクをつくり、PRの本文に入れる

送られるpull-requestはこんな感じです。

https://github.com/gfx/ci-npm-update/pull/8

f:id:gfx:20160728000115p:plain


さて、それではこれを定期的に実行する必要がありますが、これは元エントリのとおりCircle CIのparameterized buildをHeroku Schedulerで起動します。

そのアプリのテンプレートも同リポジトリに入っているので、簡単に試したければ "Deploy to Heroku" ボタンで適当にHeroku appをつくり、Heroku Schedulerで定期実行します。たとえばci-npm-update自身の設定はこんな感じ。

f:id:gfx:20160728000608p:plain

あとは各種設定が必要ですね。

設定

Heroku

"Deploy to Heroku" ボタンでアプリを生成するときにCIRCLECI_TOKEN などの設定が必要なので、それらを指定してください。

TRIGGER_NAME は circle.yml でci-npm-updateを起動する条件分岐に使います。必要なければデフォルトでかまいません。

circle.yml

Heroku appの TRIGGER_NAME が渡ってきたらci-npm-updateを起動する、という設定を追加します。

ci-npm-update自身の設定はこんな感じです。

https://github.com/gfx/ci-npm-update/blob/master/circle.yml

抜粋:

deployment:
  update-dependencies:
    branch: master
    commands:
      - >
        if [ -n "${NPM_UPDATE}" ] ; then
          bin/ci-npm-update --execute
        fi

Circle CI

Circle Ciからは、(1) github repoにgit pushする権限 (2) github repoにpull-requestを送る権限 がそれぞれ必要です。

まずpushする権限をつくるために、repoに対してread/writeできるuser keyを作ります。

Circle CIの Project Settings -> Checkout SSH key -> Add user key

f:id:gfx:20160728002103p:plain

次に、GitHubのaccess tokenを生成してCircle CIに設定します。

GitHub Settings -> Personal access tokens で "repo" scopeをもつaccess tokenを生成し、 Circle CI projectの環境変数で GITHUB_ACCESS_TOKEN という名前で設定してください。

また、Circle CIでgit commitをするために git config user.namegit config user.email が必要なので、それぞれ環境変数GIT_USER_NAMEGIT_USER_EMAILを通じて設定します。

設定が済むとこんな感じです。

f:id:gfx:20160728091520p:plain

検証

もろもろうまくいっていれば、以下のコマンドでHeroku Schedulerを待たずにci-npm-updateを起動でき、pull-requstが送られるはずです。

heroku run -a $app './build-circleci'

成功すると、create pull-request apiの結果であるJSONが表示されます。

また、ローカルで実行する場合は、無引数で実行するとdry runモードで実行しPRの内容を確認できます。ただし、dry-runモードでも node_modules/ の内容はアップデートされるのでご注意ください。

まだ作ったばかりで導入実績も少ないですが、よければ使ってみてフィードバックをいただけると嬉しいです。

*1:github enterpriseでも動くはずですが試してません。他のgit hosting serviceも要望があれば対応するかも。