Edited at

Nuxt.js+Express+TypeORMで100の質問メーカーを作った

100の質問メーカー」というWebサービスを先日リリースしました。10, 100, 1000の質問を作ったり、それを回答して遊ぶサービスです。

main.png


構成

下記のような構成で開発しました。今回はアプリケーション側はフロントもバックも全部Node.jsにしてみました。


  • TypeScript

  • Node.js 11

  • Express 4

  • Nuxt.js 2.4

  • TypeORM 0.2

  • Buefy

  • Google Compute Engine (f1-micro)

  • Google Cloud SQL


全部Node.jsで作ってみてどうだったか

快適でもあり、面倒でもあり…という感じでした。


快適なところ


Nuxt.js便利

色々フロントエンドのフレームワークはありますが、やっぱり個人開発するのにはNuxt.jsが何でも揃っていて楽かな、という感じがしています。

一度導入してしまえば特におかしくなるところもなくスムーズに使えますし、create-nuxt-app1で構築した環境だとHMRも効いていて快適です。

サーバーサイドレンダリング、PWA、Google Analytics等の解析等、欲しいけどいちいち開発したくないものが一通り揃っていたり、すぐ導入できたりするためとにかく楽でした。


サーバーが一つで楽

フルNode.jsでない場合、Nuxt.jsのサーバーを起動し、且つバックエンドのサーバーも管理という2重管理になるためなんとなく面倒な気がします。Nuxt.js+Expressであれば一つのサーバーを起動しておけば全部動きますし、フロントとバックエンドのバージョンがずれてて一瞬おかしな動きになる、みたいなこともなくシンプルで良いと思います。

また、nuxtServerInitでサーバーのログイン情報などを共有できるのも便利だと思います。(今回は使っていませんが)


補完が便利

やっぱりTypeScriptだとVisual Studioコードとの連携が素晴らしく、ヒント表示やメソッドの補完なども効いて楽ですし、importも自動で行ってくれるので適当にガガっと書いていけるので楽でした。(ちまたで言われている通りNuxt.jsまわりはちょっと怪しかったですが)


interfaceの共通化

サーバーサイドでEntityをJSONに変換してNuxt側で使う時などは、JSONの型をinterfaceで共通で利用できるのでちょっとした安心感がありました。

本当であればEntityのクラスを共通で使えれば良いのですが、そもそもEntityのカラムを全部フロント側に送るというのもありえないためどのみちJSON化する必要があり、逆にそのおかげでinterfaceで共通化できた、というメリットが出てきました。


面倒なところ

面倒なところもいくつかあります。正直Laravelのようななんでも揃っているフレームワークをバックエンドにしておくと開発が非常に楽なので、開発中恋しくなりました。


環境構築が辛い

やっぱりNode.jsはLaravelやRailsのように「とりあえずこれだけ入れときゃなんとかなる」という感じではなく、色々なパッケージを組み合わせて環境を構築していき、且つそれぞれが完璧ではなかったりうまい連動を完全に考慮しきれているわけではない部分もあり、慣れていないものを組み込む場合に環境構築でハマる部分が他よりも多いのではないかという気がします。

同じ理由で総合的なベストプラクティス的なものもなかなか見つからず、各々過去の自分の資産を参考にしたり、色々試して丁度良さそうな形を使っていたりと、動いているけどなんか不安…みたいなところがいつもあるような気がします。


ビルドが必要

当たり前の話ですが、ビルドが必要になります。超貧弱な本番サーバーでビルドしたりすると数分サーバーが止まったりします。まあこれは正直Node.jsだけの話ではないため、必要に応じてCIでデプロイしたり、インスタンスを切り替えたり等が必要となります。

業務上であればそれで問題ないと思うのですが、個人開発となると正直ちょっと面倒くさい部分ではあります。


OGPの作成

質問ページや回答ページをSNSでシェアすると下記のようなOGP画像が表示されます。

今回はNode.jsで使えるcanvasを使用しました。

Automattic/node-canvas: Node canvas is a Cairo backed Canvas implementation for NodeJS

以前 NodeでChromeを操作してTwitterシェア用画像を生成するサーバー作った のでそちらでHTMLとCSSでOGPを作っても良かったのですが、この方法だとOGPのためにサーバーを一つ用意しなければならないため、とりあえずMVPでサービスを作るのにはちょっと向いてないかなと思い直接アプリケーション内でcanvasを使って作成してしまうこの方法に決めました。

コード自体は下記のようにシンプルで、下記のimagecanvas.toBuffer()しただけのもので非常に簡単です。

  const question = await Question.findOneOrFail({

where: { uniqueId: req.params.id }
})
const image = await question.generateOgp()
res.type('png')
res.end(image)


サーバー

サーバーはGoogle Compute Engineを無料枠で使っています2。いくつもサービスを作ると数百円のVPSだとしてもだんだん馬鹿にならなくなってきますので。本心としてはGAEやHeroku、Nowなどでで簡単運用したいのですが、データベースが無いもしくは有料だったりするのと、やけにスペックが低すぎて怖いというのがあるのでなんだかんだでいつもどおりGCEに落ち着いてしまいました。(これはこれで低過ぎの部類に入ると思いますが)最近Cloud Runも出たため試そうと思ったのですが、リージョンが違うので諦めました。

DBはCloud SQLにしました。とりあえず1年間は無料クレジット内に収まると思いますし、できればその間にDBの料金を超える広告収入を得られるよう成長させていきたいところです。むしろ1年経って得られてない状態ならさすがに諦めて他のサービスを作ったほうが良いかな、と最近思い始めています。というのも1年しっかりやれば月千円以上にはなる可能性はそれほど低くは無いと思いますし、それだけやってそこまで行かないのはサービスの内容自体もしくは運用方法に色々問題があるような気がしますので、色々見直しの機会にもなると思います。

まあどちらにしろ、収入が得られなければCloud SQLをやめ、GCE内にMySQLサーバーをインストールして同居させれば無料になるので、わざわざ潰さなくても残しておけます。ということで、SQLサーバーはCloud SQLをガンガン使って作り始めようと最近は思っています。


TypeORM

長くなったので下記に雑感をまとめておきました。

TypeORMを使ってアプリケーションを作ってみての雑感 - Crieit

個人的には好きで、Sequelizeで作りかけになっているアプリケーションもTypeORMに置き換えていきたいなと思っています。

大まかにまとめると下記のような感じでした。


  • 他のフレームワークのORMと同様に直感的に使える

  • 軽い気持ちでEntityをimportして使えて良い

  • バージョンが低すぎて今後の不安とマニュアル不足はある


デザイン

Buefyを使っています。僕はブルマが大大大好きなのですが、やっぱ動きを自分で作るとなると面倒で、Buefyであれば動きも作られているので非常に楽に開発が行なえます。わざわざBuefyのコンポーネントを使わなくてもBulmaのCSSもそのまま使えますので、その都度丁度やりやすい形でUIを作っていけるためオススメです。

ちなみに色合いは一切変えず、あえてBulmaのデフォルトそのままにしています。普段開発を行っている人からすると見慣れたデザインになってしまって鼻で笑われてしまうかもしれませんが、開発界隈に関係ないSNSユーザーからするとシンプルで綺麗でとても良いデザインだと思うためです。


まとめ

全部Node.jsは大変な部分もありますが、非常に楽しいものでもありますし、唯一フロントとバックエンドの言語を統一して連携させることができるというメリットがあるものでもあります。今後大勢の人が簡単に開発できるような環境が整っていくといいなと思います。

何かもし参考になった部分などがあれば是非いいねをお願いします!

また、すでにリリース済みですのでぜひ実際に遊んでみてください。

100の質問メーカー

Qiitaユーザーへの質問も作ってみました!

Qiitaユーザーへの10の質問

どういう意図で作ったか、みたいなのは下記に書きました。

100の質問メーカーを作った時に思ったこととか - Crieit