JavaScriptのオブジェクトリテラルの前後にスペースを含めるべきか否か
波括弧(curly brace)のオブジェクトリテラルを 1 行で書く場合の話。
const withSpace = { name: 'yamada', locale: 'JP' }; // 空白あり const withoutSpace = {name: 'yamada', locale: 'JP'}; // 空白なし
🤔 実は規定がない
どれを見ても『オブジェクトリテラルを 1 行で書く場合』の規定がない。
ただし、いろいろなオープンソースのコードを見る限りでは、スペースありで書くケースの方が多いようだ。
🦉 スペースなしの方が一貫性がある
配列リテラルとオブジェクトリテラルを比べた場合、複数行で書く場合はこうなって同じ形式が使えるけど
const array = [ 'apple', 'google', 'facebook', 'amazon', ]; const obj = { name: 'apple', ceo: 'timothy donald cook', };
配列リテラルを単一行で書く場合は前後にスペースを含めないので、オブジェクトリテラルもこれに合わせた方が一貫性があるという考え。
const array = ['apple', 'google', 'facebook', 'amazon']; const obj = {name: 'apple', ceo: 'timothy donald cook'};
📝他の言語の場合
🍷 Ruby
Ruby Style Guide にはハッシュリテラル(JavaScriptでいうオブジェクトリテラルのこと)の書き方について記述されているが、好きな方を使えというスタイル。
Ruby 界隈でも JavaScript と同じようにスペースありで記述されているケースが多い。しかし、Ruby にはブロック構文が存在する。
array = ['apple', 'google', 'facebook', 'amazon'] array.each do |name| p name end array.each { |name| p name }
ブロックを複数行で書く場合は do...end
で記述することが推奨されるが、単一行で書く場合は波括弧が推奨される。
ブロック構文とハッシュリテラルの明確な区別のため、スペースなしの方が良いと考える。
🐍 Python
Python の場合は明確に「空白を入れるな」と規定されている。
今回のブログ記事も Python の書き方を学んだときに確かにそっちの方が一貫性あるな、と感じたので他の言語でも採用することにした。
🦋 ES6 と TypeScript の普及で使う機会が増えた
import 文で分割代入(Destructuring assignment)構文が多用されるので、単一行のオブジェクトリテラルを使うケースがかなり増えた。この機会に一貫させてスッキリさせようと思う。
import {DateUtil} from 'luxon'; import {Get, Controller, UseInterceptors} from '@nestjs/common';
🐹 Prettier でコードフォーマットする
ESLint や TSLint に単一行オブジェクトリテラルに対して警告を出す機能はないが、Prettier にはコードフォーマットさせるための bracketSpacing
オプションが存在する。
.prettierrc
{ "singleQuote": true, "trailingComma": "all", "bracketSpacing": false }
$ yarn global add prettier $ prettier --write '**/*.ts'
DockerのHEALTHCHECKをwgetでやる
Docker には HEALTHCHECK というコンテナが正常稼働しているか確認する機能がある。
何をもって『正常』と判断するかはコンテナを稼働する人が指定する。Nginx みたいな Web サービスのコンテナの場合は公式サンプルにもある通りcurl
を死活監視のためのコマンドとして利用している。
curl -f http://localhost/ || exit 1
自コンテナの Web サーバからステータスコード 200 が返れば、シェルの終了コードも 0
になるので正常と判定されるし、ステータスコード 404 とかが返れば終了コードは 1 以上
となるので(curl の場合は 22
だった)exit 1
が実行されて終了コード 1
となり異常と判定される仕組み。
ヘルスチェック結果は docker ps
時に healthy
なのか unhealty
なのか表示される。
AWS の ECS でもこれを利用して『異常』の場合は既存のインスタンスを自動停止して新たなインスタンスに差し替えてくれたりする。
⛰ Alpine Linux の場合
wget
は最初から入ってるけど curl
は入ってない。別にいれればいいだけの話なんだけど、コンテナサイズを最小化することでしのぎを削ってる人達(?)からすれば耐え難いことかもしれない。大丈夫 wget
でも同じことができる。
🚝 Nginx を使ったテスト
お試し用の Dockerfile はこちら。
nginx:mainline-alpine
は Nginx 公式の Alpine Linux でつくられた最新安定版のコンテナ。
ビルドして起動すると curl
を指定しているため、コマンドが存在せず起動後に unhealthy
となる。
$ docker build -t nginx-health-check . $ docker run -it --rm nginx-health-check
起動直後
$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 7661b8c061fe nginx-health-check "nginx -g 'daemon of…" 4 seconds ago Up 2 seconds (health: starting) 80/tcp eager_lichterman
起動から 8 秒後
$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 7661b8c061fe nginx-health-check "nginx -g 'daemon of…" 10 seconds ago Up 8 seconds (unhealthy) 80/tcp eager_lichterman
🚀 wget に書き換える
wget -q -O - http://localhost/ || exit 1
にする。-q
は標準出力を出さない指定。-O -
はファイル出力先を - 指定することでなしにする。つまり標準出力にするという意味。
FROM nginx:mainline-alpine HEALTHCHECK --interval=5s --timeout=3s --start-period=5s --retries=1 \ CMD wget -q -O - http://localhost/ || exit 1 CMD ["nginx", "-g", "daemon off;"]
コンテナを改めてビルド
$ docker build -t nginx-health-check . $ docker run -it --rm nginx-health-check
今度は healthy
となる。
$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES feba790fbc78 nginx-health-check "nginx -g 'daemon of…" 6 seconds ago Up 5 seconds (healthy) 80/tcp distracted_chandrasekhar
TypeScriptをはじめるとき知っておくと捗る
⚙️ tsconfig.json
tsc
コマンドで変換するときのための設定ファイル。
{ "compilerOptions": { "module": "commonjs", "declaration": false, "noImplicitAny": false, "removeComments": true, "noLib": false, "allowSyntheticDefaultImports": true, "emitDecoratorMetadata": true, "experimentalDecorators": true, "target": "es6", "sourceMap": true, "allowJs": true, "outDir": "./dist", "baseUrl": "./src" }, "include": [ "src/**/*" ], "exclude": [ "node_modules", "**/*.test.ts" ] }
一部しか理解できてないが、WebStorm や VS Code でデバッグ実行するなら "sourceMap": true
が必須。"outDir": "./dist"
で js ファイルの出力先を指定している。
exclude
では node_modules
配下やテストファイルを変換の対象外と指定している。
🌲 ディレクトリ構成
リポジトリを作ったときに以下のようなディレクトリ構成にするのが一般的みたい。
src
配下に ts ファイルを置き、tsc
コマンドで dist
配下に js ファイルと SourceMap を出力させる。実行するときは node dist/main.js
すれば良い。
├── dist │ ├── main.js │ └── main.js.map ├── node_modules ├── src │ └── main.ts ├── test │ └── main.test.ts ├── package.json ├── tsconfig.json └── yarn.lock
dist
は .gitignore
に追加しておきコミットしない。
サーバサイドの Node.js + TypeScript で使うときはデプロイ時にトランスパイルする手順を踏む。これも pakcage.json
に書いておけばいい。
"scripts": { "prestart:dev": "rm -rf dist && tsc", "start:dev": "node dist/main.js" }
yarn start:dev
するだけで prestart を終えた後に起動してくれる。npm-scripts を参照。
型定義ファイル
npm パッケージとして @types で提供されている。
TypeScript2.0 以前は tsd とか typing という型定義ファイルの管理ツールが使われていたそうだが、現在は必要な型情報がほしければ npm install @types/node
みたいな感じで個別にパッケージをインストールするだけでよくなった。
TypeScript ではデフォルトで node_modules/@types
配下の型を参照してくれる。
有名な npm パッケージで公開されているライブラリのほとんどは型定義ファイルが用意されている状況。TypeSearch というページで検索できる。
🏹 ts-node
TypeScript は拡張子 ts ファイルを tsc
コマンドで js ファイルに変換して実行するものだけど、ts-node を使えばそのまま実行できる。devDependencies
に加えておけば良い。
$ yarn add -D typescript ts-node
実行するときは
$ yarn run ts-node src/main.ts
あらかじめ package.json に記述しておけば yarn start
するだけでよくなる。
"scripts": { "start": "ts-node src/main.ts" }
でも ts-node
だとデバッグ実行できないみたいなので、自分はすぐに使わなくなった。console.log
デバッグが好きな人向け。
Node options:
に --inspect --require ts-node/register
を付加すれば IDE でもデバッグ実行できる。 → ts-nodeでデバッグ実行
🎙 トランスパイル ≒ コンパイル
ts ファイルを js ファイルに変換することをトランスパイルと言う。これも広義のコンパイルになるけど、コンパイルという用語は高水準な言語を低水準な言語に変換することを言うそうだ。
TypeScript や CoffeeScript を JavaScript に変換することのように、高水準な言語を高水準な言語に変換するのはトランスパイル。
でも厳密にトランスパイルという用語を使って説明してるサイトはあまりなく、単にコンパイルと言われてることの方が多い。