動かざることバグの如し

近づきたいよ 君の理想に

Nodejs最新版でファイルの存在チェックをする

令和最新版Nodejsって響きよくないですか?

環境

  • Nodejs v14

概要

よくある、指定したパスのファイルが存在するかのチェック

いくつか方法があるのでメモ

【方法1】fs.existsSync()を使う

一番オーソドックスというか古典的。どのNodejsのバージョンでも実行できる。

const fs = require('fs')
if (fs.existsSync('/etc/passwd')) {
  console.log('The path exists.')
} else {
  console.log('The path not exists.')
}

メリットはコード数が少なくてシンプル、デメリットはSyncだからpromiseとの相性が良くないかも

ちなみに fs.exists()は非推奨なので注意

公式ドキュメントを確認しても、

Deprecated: Use fs.stat() or fs.access() instead.

って書いてある。使うな。あとQiitaとかでみんなよく勘違いしてるのが、上のfs.existsSync()は非推奨ではなく、現役でもぜんぜん使える。

【方法2】 fs.lstat() && stat.isFile()を使う

fs.exists()はpromise化できないので、async/awaitを使いたいって場合はこっち。

const fs = require('fs').promises
async function fileExists(filepath) {
  try {
    return !!(await fs.lstat(filepath))
  } catch (e) {
    return false
  }
}

fileExists('/etc/passwd')
  .then(res => console.log(res))

ポイントはasync/await使いたいので、requireを require('fs').promises にする必要がある点、fs.lstat()したときに、ファイルが存在しない場合例外が発生してしまう点。なので、今回はtry catchで囲って存在する場合はstat.isFile()でさらにチェックしてる。

単にディレクトリとかシンボリックリンク含めてパスが存在する場合だけ確認する場合は fs.lstat() である時点でtrue返せばいい。

ちなみに lstatの返り値のstatではファイルかどうかとかディレクトリかどうかといったチェックができるので、以下のように書くとディレクトリのときのみtrueといった処理がかける。

const fs = require('fs').promises
async function fileExists(filepath) {
  try {
    return (await fs.lstat(filepath)).isFile()
  } catch (e) {
    return false
  }
}

fileExists('/etc/')
  .then(res => console.log(res))

蛇足

fs.exists()が非推奨になった経緯は以下のサイトがとても詳しい。ちゃんとした理由があって納得した。

fs.exists()がdeprecatedになった理由 ¦ 学ぶ、考える、書き出す。

Fastifyで静的ファイルを返す方法

環境

  • Fastify 3.x

やりたいこと

画像とかサーバーにある静的ファイルをを返したい

バイナルファイルもきちんと表示できるようにしたい

【方法1】fs.readFileを使う

一番ベーシック。Fastityに限らず、nodejs使ってるなら標準メソッドで解決しようって考え方である。

せっかくなのでここではasync/awaitを使って実装してみる。

'use strict'
const fs = require('fs').promises

module.exports = async function (fastify, opts) {
  fastify.get('/image', async (req, reply) => {
    const buffer = await fs.readFile('demo.png')
    reply.type('image/png')
    reply.send(buffer)
  })  
}

これで /imageにアクセスすると demo.pngを表示できるAPIサーバーを作成できた。

【方法2】fastify-static

そもそも公式で静的ファイルを表示するのに特化したFastifyのプラグイン、fastify-staticが公開されている。

github.com

これを使わない手はないと思うので早速インストール

yarn add fastify-static

例として、public/demo.pngを表示するAPIを作るとする。

const fastifyStatic = require('fastify-static')
const path = require('path')

module.exports = async function (fastify, opts) {

  fastify.register(fastifyStatic, {
    root: path.join(process.cwd(), 'public')
  })

  fastify.get('/image', (req, reply) => {
    return reply.sendFile('demo.png')
  })
}

ポイントはfastifyStaticをfastify.register()するときのオプションとしてrootは必須ということ

しかも絶対パスなので若干面倒。。。今回はprocess.cwd()でNodejsの実行絶対パスを基点とするようにした

【方法3】

Bulma CSSで画像とテキストを横並びにする方法

あんまりBulma使ってる人見ないよね。。。

環境

  • Bulma CSS 0.75

完成イメージ

ちょうどこんな感じ

f:id:thr3a:20201205124123p:plain

コード

上のサンプル見れば終了なんだが一応説明

<div class="columns is-vcentered">
  <div class="column has-text-centered">
    <figure class="image is-128x128 is-inline-block">
      <img src="https://bulma.io/images/placeholders/128x128.png">
    </figure>
  </div>
  <div class="column">
    <h1 class="title">
      タイトル
    </h1>
    <h2 class="subtitle">
      サブタイトル
    </h2>
  </div>
</div>

.columnsでカラムコンテナを作り、その中で画像と文字をそれぞれカラムとして入れている。

. is-vcenteredをつけることで文字列が画像の高さの中心に来るようになる。

fastifyでAPIサーバーを作成、GCPに音速デプロイ

結論

fastify使うなら fastify-cli使え

環境

  • Nodejs 10
  • fastify v3.0.0

概要

Nodejsでサーバーfastify-cliを使ってAPIサーバーのひな壇を作って、GCPのCloud Runにデプロイするところまでやってみる。

インストール

まずはfastify-cliをインストール 公式ではグローバルインストールが推奨されている

npm install fastify-cli --global

これで fastify コマンドが使えるようになる。

ひな壇作成

fastify generate YOUR_APP_NAME
cd yourapp
yarn install

するとこんな感じのひな壇が生成される。

├── app.js
├── node_modules
├── package.json
├── plugins
│   ├── README.md
│   └── support.js
├── routes
│   ├── README.md
│   ├── example
│   └── root.js
├── test
│   ├── helper.js
│   ├── plugins
│   └── routes
└── yarn.lock

MVCでいうControllerにあたるのはroutesディレクトリ。特にroutes/root.jsが一番重要

起動

yarn dev

で、http://127.0.0.1:3000 にアクセスすると

{"root":true}

JSONが表示されるはず。これはさっきの routes/root.js で制御されている。

routes/example/index.js にもあるように、ルーティングを足していきたければ、都度ディレクトリを切って fastify.get等を追加していくだけ。簡単。

デプロイ

今回は GCPCloud Runにデプロイしてみる。

公式ドキュメントにサーバーレスのデプロイ方法が詳しく載っているので参考になる。

github.com

まずはGCPのコンテナレジストリにログイン

gcloud auth configure-docker

ルートディレクトリにDockerfileを作成し、以下

FROM node:10

WORKDIR /app

COPY package.json ./
COPY yarn.lock ./

RUN npm install --only=production

COPY . .

CMD [ "npm", "start" ]

ビルド

docker build -t asia.gcr.io/[PROJECT_ID]/[APP_NAME]:latest .

GCP側でビルドする場合は以下(料金がかかるので注意

gcloud builds submit --tag asia.gcr.io/[PROJECT_ID]/[APP_NAME]

うまくビルドができたら、ローカルで確認してみる

docker run --rm -p 3000:3000 asia.gcr.io/[PROJECT_ID]/fastify-example:latest

これで curl http://localhost:3000/してJSONが返ってくればおk

いざデプロイ

gcloud beta run deploy [APP_NAME] \
  --image asia.gcr.io/[PROJECT_ID]/[APP_NAME] \
  --platform managed \
  --region=asia-northeast1

GCP Compute Engineでディスク拡張を無停止で行う

コマンド知れば簡単だった

やりたいこと

起動しているGCP仮想マシンのディスク容量が不足してきたので拡張したい。

やり方

ホスト側

まずMacbookとか自分のPC側でgcloudコマンドを使って操作する。

gcloudコマンドのインストールは以下から

gcloud auth login で認証できる

例えば以下は100GBに増やしたい場合。100GBぶん増やすのではなく、ディスク容量が100GBになるので注意

gcloud compute disks resize [YOUR_INSTANCE_NAME] --size 100GB

そのあと、対象の

サーバー側

sshで対象インスタンスにログインし、ディスクの拡張を行う

growpart /dev/sda 1
resize2fs /dev/sda1

ってだけ。これで df -h とかで確認すると100GBになっているはず

growpartコマンド自体はUbuntuにプリインストールされているコマンドで、別にGCP専用ってわけではなさそう。

検証OS