尋常でないもふもふ

a software engineer blog

ts-nodeをIDEでデバッグ実行

ts-node は TypeScript ファイルをコンパイルせずにそのまま実行できるライブラリ。
開発環境でお世話になるが、デバッグ実行するやり方の日本語情報がなかったので書いておく。

基本的なこと

node コマンドの option として --inspect をつければデバッグ実行になる。--require をつけることで node_modules のライブラリを読み込むことができる。

$ node --inspect --require ts-node/register src/main.ts
Debugger listening on ws://127.0.0.1:9229/690c42e8-c2d4-407a-b768-6c5270241775
For help, see: https://nodejs.org/en/docs/inspector

これで WebSocket の ws://127.0.0.1:9229 で待ち受けてるので、IDE 等からアタッチすることでデバッギングできる状態になっているというわけ。

ts-node のインストール

$ npm install ts-node -D
$ yarn add ts-node -D

WebStorm でのやり方

実行

--inspect --require ts-node/register して実行する ts ファイルを指定するだけ。 f:id:jnst:20180910162556p:plain

Jest でテスト

--inspect --require ts-node/register して実行するテストファイルを指定するだけ。

f:id:jnst:20180910162618p:plain

結果

f:id:jnst:20180910163534p:plain

VS Code でも同様のやり方でデバッグ実行できる。

TypeORMの@CreateDateColumnの精度を0にする

TypeORM では RailsActiveRecord と同じようにプライマリキーの id カラムをオートインクリメントさせたり、INSERT 時に created_at カラム、UPDATE 時に updated_at カラムを自動更新したりできる。

Entity クラス

import {CreateDateColumn, Entity, PrimaryGeneratedColumn, UpdateDateColumn} from 'typeorm';

@Entity('samples')
export class Sample {
  @PrimaryGeneratedColumn()
  id: number;

  @CreateDateColumn({name: 'created_at'})
  createdAt: Date;

  @UpdateDateColumn({name: 'updated_at'})
  updatedAt: Date;
}

ActiveRecord との違い

ActiveRecord では DATETIME の精度がデフォルトの 0 となり、値としては 2018-01-01 00:00:00 のようになる。

Field Type Null Key Default Extra
id int(11) NO PRI NULL auto_increment
created_at datetime NO NULL
updated_at datetime NO NULL

TypeORM は DATETIME の精度が 6 となり、値としては 2018-01-01 00:00:00.000000 のようにマイクロ秒まで扱う設定となる。

Field Type Null Key Default Extra
id int(11) NO PRI NULL auto_increment
created_at datetime(6) NO CURRENT_TIMESTAMP(6)
updated_at datetime(6) NO CURRENT_TIMESTAMP(6)

精度を 0 にする

要件次第ではあるがマイクロ秒どころかミリ秒すらいらなかったので ActiveRecord と同じように精度 0 にしたい。

@CreateDateColumn({name: 'created_at', precision: 0, default: () => 'NOW()'})
createdAt: Date;

@UpdateDateColumn({name: 'updated_at', precision: 0, default: () => 'NOW()'})
updatedAt: Date;

precision で精度を 0 指定する。これだけだとデフォルト値が CURRENT_TIMESTAMP(6) となってしまいエラーになるので、公式 FAQ に書いてあるやり方でデフォルト値も書き換える。

Mac環境でgRPCのC++コードをDockerつかって生成

🖼 背景

Protocol Buffers のコード生成だけなら Homebrew でインストール可能な protoc コマンドさえあればいいが、

$ brew install protobuf
$ protoc --version
libprotoc 3.6.0

gRPC コードを生成するなら grpc_cpp_plugin が必要となる。

$ which grpc_cpp_plugin
/usr/local/bin/grpc_cpp_plugin

残念なことに Homebrewgo get ではインストールできず、Macmake build, make install しなければならない。

WARNING: After installing with make install there is no easy way to uninstall,
which can cause issues if you later want to remove the grpc and/or protobuf installation or upgrade to a newer version.

make を使う方式だと公式ドキュメントにも「一度インストールしてしまえば削除するのは難しいからアップグレードのときとか困るよ」と書いてある…。

🌿 環境を汚さずに Docker でコード生成を行う

上のやり方を試したところ確かに C++ コードの生成はできたが、イケてないので Docker を使ってコード生成することにする。
前提として下記のようなディレクトリ構成にした。protobuf ディレクトリにいろんな .proto ファイルが配置されていて、codegen ディレクトリに生成コードを出力。Dockerfile とスクリプトtools ディレクトリに置いた。

project
├── protobuf
│   └── rpc
│       ├── auth
│       │   └── auth.proto
│       ├── rpc.proto
│       ├── setting
│       │   └── language.proto
│       └── user
│           └── user.proto
├── codegen
│   └── .gitkeep
└── tools
    └── Dockerfile
    │
    └── gen_grpc_cpp.sh

🐳 Dockerfile

gRPC 公式が C++ 用の Docker イメージを公開しているのでそれを使う。
docker run すると bash が起動するので protocgrpc_cpp_plugin が使えることがわかる。

$ docker run -it --rm grpc/cxx

root@55d8450a784e:/# protoc --version
libprotoc 3.5.0
root@55d8450a784e:/# which grpc_cpp_plugin
/usr/local/bin/grpc_cpp_plugin

この Docker イメージを利用した Docker ファイルが下記。

gist.github.com

ホストの ./protobuf ディレクトリをコンテナの /workspace/protobuf ディレクトリへすべてコピーし、コンパイルを実行している。gRPC コードを生成する場合は --grpc_out オプションを使う必要がある。
末尾で対象ファイルを指定しているが **/*.proto再帰的に配下のディレクトリすべてを対象に加えてほしいところだけど、そうは動作してくれないので、階層数に応じて複数ディレクトリを愚直に指定している。

🐚 tools/gen_grpc_cpp.sh

上記の Docker イメージを使うシェルスクリプトを書いた。流れとしては、

  1. Docker ビルド
  2. Docker 実行
  3. コンテナのファイルをホストにコピー
  4. 後始末

gist.github.com

3番のコンテナ内のファイルをホスト(Mac)にコピーするには docker cp を使うしかないため、このシェルスクリプトが必要となる。もしこのコピーが Dockerfile に記述できるようになれば Docker 実行だけでコード生成&コピーできるようになるが、今の所できないようだ。