Express.jsを勉強しなおしたログ（環境構築する上で、判断に困ったところなど）

この記事は、今更ながらExpress.jsを勉強しなおした時のログです。
具体的なやり方は、いろいろと優秀なドキュメントがありますゆえ、あまり書いていません。
一方で、判断に迷ったり困ったところをメモしています。
（似たようなパッケージがあって、どれを使えばいいのかの比較など）

とりあえずの環境構築までを書いています。

Express.jsを使っている方は、目次を適当に見て、気になったところだけ見ていただけると何か見つかるかもしれません。
Express.jsを勉強中という方は、ざっと読み通しておくと、なにか救われるかもしれません。

くらいの温度感で書いています。


## Express.jsって

Webアプリフレームワーク。
[StateOfJavaScript2021](https://2021.stateofjs.com/en-US/libraries/back-end-frameworks)を見た感じ、JavaScript系のWebフレームワークでは、一番使われているっぽい。


## なぜ学習するのか？

ウェブアプリを作るときに、[Laravel](https://laravel.com)を使うことが多かった。
ただ、ミニマムにAPI用のバックエンドサーバーを作りたいとき、Laravelはいくらか豪華すぎるように思えていた。
あと、使う言語をTypeScriptに統一できれば幸せだと感じていた。
そのため、Express.jsを習得することにした。

（今思えば、[Firebase](https://firebase.google.com/?hl=ja)をいじり倒す、でも良かったかもしれない）


## 学習する前の状態

- Express.jsは過去に仕事で何度か触ったことがあった
- フロントエンドエンジニアとしてNode.jsにはよくお世話になっている
- ただし、サーバーとしてのNode.jsはよくわからぬところも多い
- TypeScriptとかはよく書く
- ApacheやNginxでサーバーを立てたりもある

くらい。

MacBookPro M1Proチップ。
Node.jsのv16が入っている状況。
Express.jsを把握するのが目的なので、ひとまずDockerとかは使わずにいく。

## まず初めにしたこと

Express.js本家のサイトに目を通した。
https://expressjs.com/ja/

非常にシンプルなので、1時間あったら大体読める。
大枠を把握した。
オススメ。

あとは、ハンズオンNode.jsを並行して読んでいた。
https://www.oreilly.co.jp/books/9784873119236/

Node.jsを中心に、JavaScriptの歴史からEventEmitterとか基礎知識、Express.jsやサクッとNext.jsも登場していて、良書だった。
オススメ。

あとは、てきとうに作業フォルダを作った。
なんとなくどんなことができるか大枠は掴めた。


### 余談：それはNode.jsの機能かExpressの機能か

どこまでがNode.jsの機能で、どこからがExpress.jsが提供しているものか分かりにくいから難しい、と感じていた。
例）`path`モジュールはnode.jsに付随する機能なのか？

など、node.jsが提供しているものか、expressが提供しているものか、わかりにくいところが最初難しいと感じていた。

ここらへんの疑問は、ハンズオンNode.jsでだいたい解消されたのは助かった。
（Node.jsを知ったことで、Expressの担ってる役割が見えてきた）

あと、Node.jsとExpressのドキュメントに、モジュールがいろいろ載ってあるので、それをたぐってもいい。


## Expressのインストール、generatorに任せた

Expressの公式サイトより。
https://expressjs.com/ja/starter/installing.html

二つ方法があるようだ。
1. `npm init`した後で、パッケージとしてexpressを入れる
2. Expressジェネレーターを使う

2を使うと、いい感じに雛形を用意してくれるらしい。
どんな感じに書くのか知りたいので、Expressジェネレーターを使った。
（サクッといい感じに最低限必要なファイルを作ってくれるから助かった）

ちょっとハマったのだが、
`npm install express-generator -g`
でグローバルにインストールしようとしたら、**書き込み権限がない**みたいな感じに怒られた。

いろいろnpmのアップデートなど試して、
`sudo npm install express-generator -g`
なら通りそうだったが、別にグローバルにインストールしたいわけじゃない。

ちょっと考えて、
`npx express`
でジェネレーターを使った。

オプションをいろいろ試して、吐き出されるディレクトリ構成を見つつ、とりあえずAPI用のものをサクッと立てたければ、
`npx express --no-view --git`
でええんじゃないかと思った。


## Expressの基本的な機能、ルーティングとミドルウェアとテンプレートエンジンできてる？

なにができるかは公式ドキュメントの通りなので割愛。
ガイドを読みながら手を動かせば理解できた（使えるとは言っていない）。
https://expressjs.com/ja/guide/routing.html

キモとなるのは「**ルーティング**」と「**ミドルウェア**」の二つ、という感触を得た。

- ルーティングでPOSTやGETなどリクエストを捌く
- ミドルウェアで、任意のリクエストに対し、処理を実行したり返したりする

あとは、**テンプレートエンジン**も重要な要素だろう。
が、今回作りたいのはAPIサーバーなのでざっと読み通すだけにしておく。


### bin/wwwファイルとapp.jsはそれぞれ何をしている？

binディレクトリ内に、wwwというファイルがあった。
package.jsonのscriptsによると、まずはじめにnodeでwwwというファイルを読んでいるらしい。
中身を見ると、どうやら**サーバーを起動する処理**が集まっていた。

一方で、Expressにまつわる記述は、app.jsに集まっていた。
アプリケーション自体はapp.jsで構築して、wwwでそれを呼び出し、サーバーを組み立てているっぽいことを把握。

wwwを使うのは、慣習的なモノだろうか？（Laravelでも見かけたし）

あとはルーティングとかはroutesディレクトリに。
ビューはviewsディレクトリに。
静的に配信するファイル群は、publicディレクトリに。
ここら辺は見たままだ。


## デバッグについて、Express自身のログも出せるよ

`DEBUG=express:* node index.js`
でExpressのデバッグログも出せるらしい。
随時、活用していく。

余談だが、デバッグクライアントを起動できるインスペクタ`--inspect`スイッチが、node.jsについていることを知った。
https://nodejs.org/ja/docs/guides/debugging-getting-started/


## デプロイについて

デプロイ時にはプロセス・マネージャーを一緒に入れるといいらしい。
あとでしっかり調べる。
https://expressjs.com/ja/advanced/pm.html


## 開発しやすいよう、自動で再起動してくれるnodemonも入れておく

`node www`にて、サーバーを起動した後、コードを変更して保存しても**変更が適応されない**。
変更を反映するためには、**nodeサーバーの再起動**が必要なのだった。

それをええ感じにやってくれるのが`nodemon`というパッケージらしい。

`npm i -D nodemon`
でインストールした後、
package.jsonの`scripts`に
`”dev”: “nodemon www”`
を追加した。

開発の際は、`npm run dev`でサーバーを起動することにする。


## TypeScriptってExpress.jsで使えるの？

昔、Node.jsがTypeScriptに対応していないから、Denoを使いたい。
みたいな話を聞いたことがあった。

が、ExpressでTypeScriptを使う記事は検索すればいっぱい出てくる。
~~使えてるやないかーい笑~~
ここらへんの情報を収集し、整理した。

- 普通に@types/nodeとか@types/expressは存在する
- 昔2018年ごろ？はもっと面倒だったぽい
- CommonJSとESModuleらへんの面倒に巻き込まれてる？
- TypeScriptで書く場合はビルド時に変換されるのでESModuleでもよさげ？

今、Node.jsは頑張ってESModuleも使えるようにしているらしい。
（mjsという拡張子について調べるとよさげ）
あとは、requireは同期型ロード、importは非同期にロードされ実行されることを理解した。


## 改めて、TypeScriptをExpress.jsに入れる

これは検索すれば山ほど記事が出てくるので、ざっくりとだけ書いておく。

1. typescriptとか@types/nodeとか必要なパッケージをインストール
2. `tsc --init`でtsconfig.jsonを作成
3. 適当にtsconfig.jsonの設定を変えたり、package.jsonのscriptsを整理したり

途中、`tsc -p’オプションをよく見かけて、気になったから調べた。
使用するtsconfig.jsonを指定できるらしい。
tsconfig.production.jsonとか使ってやったり、複数のtsconfig.jsonが出てくるときに使うといいとのこと。

なお、tsconfigの推奨設定は、以下にまとまっていたし、そのまま使うのもありだろう。
https://github.com/tsconfig/bases


## TypeScriptをどうビルドして実行するか？ 本番環境、開発環境

`ts-node`というパッケージを使うと、JITで変換しながら実行してくれるらしい。
https://github.com/TypeStrong/ts-node
`--transpile-only`オプションをつけたら本番でもオーバーヘッドを気にせず使えるとのこと。

とはいえ、なんか気持ちが悪いので、本番環境では普通にビルドして実行したい。
（そして時間のあるときにオーバーヘッドを検証したい）

ググった結果、distに吐き出させて実行しているのが多い印象だった。
先人にならい、`tsc src/index.ts`で、`dist`ディレクトリにビルドしたものを出力してもらうようにした。
なお、どこにビルドを出力するかは、tsconfig.jsonの`outDir`で設定できる。
https://www.typescriptlang.org/tsconfig

この際、ディレクトリ構成を変換し、`app.ts`をはじめ`.ts`ファイルは、`src`ディレクトリの中に置くようにした。

また、distディレクトリは`rimraf`パッケージを使い、ビルド時にクリーンするようにした。


## TypeScriptでの開発中のサーバー再起動をどうするか？

nodemonでやっていたように、TypeScriptでもファイルを編集した際に、サーバーを再起動するようにしたい。

方法は大きく分けて二つあるようだった。

1. nodemonの起動でts-nodeを起動させる方法
    1. nodemon.jsonの設定ファイルを使う
    2. コマンドで起動させる
2. ts-node-devのパッケージを使用する
    1. 例`ts-node-dev --respawn index.ts`

どちらも同じくらい使われていそうだった。
実行が簡単そうな、`ts-node-dev`パッケージを使うことに。


## jsファイルをtsファイルに置き換えていく

jsファイルと共存させる場合は、tsconfig.jsonの`allowJs`を`true`にしておくこと。
（なぜか`ts-node`で動かしてるときは動いた。ビルドしたら無視された読み込まれず怒られた（´・ω・｀））

また、`require`を全て`import`に置き換えた。

例えば、
`hoge.ts`の`module.exports = hoge;`
は、
`import hogeru from ‘./hoge’`
などでいけるっぽい。
（module.exportsとかの変換がざっくり理解なのそのうち解決する）

付随して、ESModuleのimportにおいて、たまに`tsconfig.ts`の`esModuleInterop`の設定でハマる人がいるらしいとメモしておく。

また「型がありません」などと怒られるたびに、大人しくtypesを検索して入れた。
だいたい、先人が作ってくださっているおかげで助かった。

あとは、`get`メソッド等の引数reqやresなどに型をつけていく。
`var`も`const`を使うようにした。


### 現在のpackage.jsonのscripts

大体こんな感じになった。

```json
{
  "clean": "rimraf dist",
  "dev": "ts-node-dev --respawn src/app.ts",
  "start": "npm run clean && tsc && node dist/app.js",
  "build": "npm run clean && tsc"
}
```

なお`npm-run-all`というパッケージで、複数のnpm-scriptsの実行を簡単に記述できるようになる。
が、そこまで複雑じゃないのでそのまま書いた。


## Expressのlistenでサーバーを立つらしいが、GeneratorのwwwファイルではcreateServerで立てているのどういうこと？

```js
const app = express();

app.listen(3000, () => {
  console.log("Server started on port 3000");
});
```
としてサーバーを待機させている記事が多かった。

が、express-generatorが生成したwwwファイルでは、
```js
var app = require('../app');
var http = require('http');
var server = http.createServer(app);
server.listen(port);
```
というふうに起動していた。

どう違うのか気になって調べたところ、どうも`app.listen`の中身は、`http.createServer`などなどで、ええ感じに実行してくれているらしい。

ということで、`app.listen`を使っていくことにする。


## 取り急ぎのセキュリティ

npm helmetで検索すると、helmetつけましょうね、というのがわかる。
HTTPのheadersをええ感じにしてくれるとのこと。

helmetをミドルウェアとして組み込んでおく。

---

というところで、最低限セットアップできた感があるので、ここで一度休憩する。
あとはMySQLとかとくっつけながら触り倒していく。

お疲れ様でした。