Herokuにアプリをデプロイするぞ！【Node.js】【 Express】【 ejs】【 PostgreSQL】【Heroku Postgres】

__Node.js__を使って、__Heroku__にアプリをデプロイします！
また__Heroku Postgres__も利用して、DB接続もします！

デプロイできるまでめちゃくちゃ大変だったので、ナレッジとして手順を残しておきます。
※独学で調べながらやったので、正確ではないかもしれません。アドバイスあればコメントいただきたいです！

#環境もろもろ
PC : Mac Book Pro : "BigSur"
editor : VScode

* Node.js : "v12.22.5"
 * npm : "6.14.14"
 * Express : "4.17.1"
 * ejs : "3.1.6"
 * dotenv : "10.0.0"
 * pg : "8.7.1"

* Homebrew : "3.2.5"
* nodebrew : "1.1.0"


* Heroku
* Heroku Postgres

#まずは完成形
「絶賛うまくいってないんですが、」って人いると思うので、まずは完成形を書いとこうと思います。
コード見比べて解決できれば一番手っ取り早い。

###ディレクトリ
```
heroku-app
 L node_modules
   public
      L css
          L index.css
   views
      L index.ejs
   .env
   .gitignore
   app.js
   package-lock.json
   package-json
```

###各種ファイル
```index.html
[index.ejs]
  :
<body>
  <ul class="table-body">
    <% items.forEach((item) => { %>
      <li>
        <div class="item-data">
          <span class="id-column"><%= item.id %></span>
          <span class="name-column"><%= item.name %></span>
        </div>
      </li>
    <% }) %>
  </ul>
</body>
   :
```

```app.js
const express = require('express');
const app = express();

app.use(express.static('public'));

// -----------------------------------------------
//      Routing
// -----------------------------------------------
app.get('/', (req, res) => {
  connection.query(
    'SELECT * FROM testTable',
    (error,result) => {
      if(error) throw err;
      res.render('index.ejs',{items:result.rows});
    }
  );
});

// -----------------------------------------------
//      postgresql設定
// -----------------------------------------------
const { Client } = require('pg');
require('dotenv').config({debug:true});

// --------  接続情報  -----------
const connection = new Client({
  //DB接続先情報を環境変数DATABASE_URLで設定
  connectionString: process.env.DATABASE_URL,
  //SSLを設定
  ssl: {
    sslmode:'require',
    rejectUnauthorized:false
  }
});

// --------  接続  -----------
connection.connect((err) => {
  //エラー時の処理
  if(err){
      console.log('error connecting:' + err.stack);
      return;
  }
  //接続成功時の処理
  console.log('success');
});


// -----------------------------------------------
//      port
// -----------------------------------------------
//LocalとHeroku接続先によってPORTを切り替える
let port = process.env.PORT;
if (port == null || port == "") {
  port = 3000;
}
app.listen(port);
```

```..env
//Heroku Postgresに接続するためのDB情報
DATABASE_URL = 'postgres://[User]:[Password]@[Host]:[Port]/[Database]'
```

```..gitignore
//gitにコミットしたくないファイルを記述
.env
```

```package.json
{
  "name": "heroku-app",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "node app.js",  //Herokuで実行するときに、これ必須
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "dotenv": "^10.0.0",
    "ejs": "^3.1.6",
    "express": "^4.17.1",
    "nodemon": "^2.0.12",
    "pg": "^8.7.1"
  }
}
```

#環境構築
まずは開発環境を整えていきます。

###1.Homebrewインストール
ターミナルからHomebrewをインストールします。
HomebrewはmacOSまたはLinux用のパッケージマネージャーです。
詳しくはググってくださいｍｍ

```
$ brew -v	
	#Homebrewが入っているか確認、バージョンが表示されればOK
	
$ brew update	
	＃Homebrewがインストール済みの場合は、最新バージョンにしておく
	
$ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"	
	＃Homebrewがインストールされてない場合は、これでインストール	
```

###2.nodebrewのインストール
nodebrewはNode.jsのバージョン管理システムで、Homebrewでインストールすることができます。
nodebrewはnodeをインストールするために使います。
すみません詳しくはググってくださいｍｍ

```
$ brew ls	
	# homebrewでnodeがインストールされているか確認
	
$ brew uninstall --force node	
	# homebrewでnodeをインストールして使っていた場合、homebrewで使用していたnodeを削除
	
$ brew install nodebrew	
	#nodebrewのインストール
	
$ nodebrew -v	
	#Nodebrewのバージョン確認
```

###3.Node.jsのインストール
ようやくホンちゃんです。
インストールするバージョンですが、`v12.22.5`にします。
理由としては、サポートされているのが`8.x`​ `​10.x`​および `​12.x`​とのことだからです。
参照：[Heroku の Node.js サポート](https://devcenter.heroku.com/ja/articles/nodejs-support#specifying-a-node-js-version)

```
$ nodebrew ls-remote	
	#インストール可能なNode.jsのバージョン一覧表示
	
$ nodebrew install v12.22.5	
	#「v12.22.5」→「stable」とすることで、Node.jsを安定バージョンでインストールできる
	#「v12.22.5」→「latest」にすることで、最新バージョンのインストールとすることができる
	
$ nodebrew ls	
	#インストール済みのNode.jsのバージョンを確認
	
$ nodebrew use v14.4.0	
	#初めて使用する場合は[＄ nodebrew ls]バージョン確認時に、「current: none」と表示されるので、使用するバージョンを指定する
	
$ export PATH=$HOME/.nodebrew/current/bin:$PATH	
$ ~/.bash_profile	
	#パスを通す
	
$ nodebrew setup	
	#パスが通っているか確認
```

###4.npmのインストール
npmとは、Node Package Managerの略で、Node.jsのパッケージを管理するものです。
Node.jsをインストールした時点でnpmも一緒にインストールされています。
「nodebrew v12.22.5」をインストールしたので、「6.14.14」となるはずです。

```
$ npm -v	
	#バージョンが表示されればOK
```

###5.開発フォルダの作成
cd コマンドで、任意の場所に移動し、開発フォルダを作成します。

```
$ mkdir heroku-app
	#フォルダ作成

$ cd ./heroku-app
	#作成したフォルダに移動
```

###6.Express、ejsをインストール
まずは、npmの設定ファイルである`package.json`を生成します。
package.jsonには、npmパッケージの設定情報などが書き込まれていきます。
`npm init --yes`を実行することで生成することができます。

その後、`Express` `ejs` `dotenv` `pg` をインストールしていきます

```
$ npm init --yes
	#package.json生成

$ npm install express ejs dotenv pg
	#各種インストール
``` 

以上で環境構築の完了です！


#モジュール
今回導入するモジュールについて簡単に

###Express
ExpressはNode.jsで利用できるWebアプリケーションフレームワークです。

###ejs
JavaScript用のテンプレートエンジンです。

詳しくはこちらの記事が参考となると思います。
[Expressにおけるejsの使い方](https://qiita.com/kamihork/items/1b13d2157979d1837849)

###dotenv
dotenvを導入することにより、環境変数を使用できるようになります。
「process.env.〜」で使用することができます。
環境変数は「.env」ファイルで設定します（ルートディレクトリ配下に作成）

詳しくはこちら
[環境変数の代わりに .env ファイルを使用する (dotenv)](https://maku77.github.io/nodejs/env/dotenv.html)

###pg
Node.jsからPostgreSQLを扱うためのモジュールです。

#1.ローカルにテストページ作成
まずはローカルで、お決まりの「Hello World！」が表示されるようにしましょう！

####1-1.各種ディレクトリ、ファイル作成
以下のようになるように、ディレクトリ、ファイルを作成してください。

```
heroku-app
 L node_modules
   public
      L css
          L index.css
   views
      L index.ejs
   app.js
   package-lock.json
   package-json
```

####1-2.「app.js」記述
app.jsに以下のように記述します

```app.js
//この２行はお決まりのやつ
const express = require('express');
const app = express();

//***********************************
//    ルーティング
//***********************************
//「http://localhost:3000/」を指定したときに、「index.ejs」を表示する
app.get('/', (req, res) => {
  res.render('index.ejs');
});

//localhostのポートを3000に指定
app.listen(3000);
```

####1-3.「index.ejs」記述
index.ejsを記述

```index.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>Hello World!</h1>
</body>
</html>
```

####1-4.「Hello World！」表示
ターミナルで以下コマンドを実行！（heroku-appディレクトリ内）
アプリを起動します。

```
$ node app.js
```

ブラウザで「http://localhost:3000/ 」に接続！
「Hello World!」と表示されれば成功です！

#2.Herokuにデプロイ
では作成したアプリをHerokuにデプロイしてみましょう！
デプロイできるように`app.js` `package.jason`を編集する必要があるので、手順にそって編集、デプロイしてください。

####2-1. app.js と packge.jason を編集
app.jsのport設定を変更します。
今まではローカルの3000に接続するように設定していましたが、HerokuのWebサーバーに接続できるように設定します。
Herokuのポートは動的に変わるので、環境変数__process.env.PORT__で指定してあげます。

`app.listen(3000);`　→ `app.listen(process.env.PORT);`

ただ、ローカルとデプロイでいちいち`app.listen(3000);`と`app.listen(process.env.PORT);`を変更するのも面倒なので、以下で自動で切り替えてくれるようにしておきましょう。

```app.js
//この２行はお決まりのやつ
const express = require('express');
const app = express();

//ルーティング
//「http://localhost:3000/」を指定したときに、「index.ejs」を表示する
app.get('/', (req, res) => {
  res.render('index.ejs');
});

// -----------------------------------------------
//      port
// -----------------------------------------------
//LocalとHeroku接続先によってPORTを切り替える
let port = process.env.PORT;
if (port == null || port == "") {
  port = 3000;
}
app.listen(port);
```

次に__package.json__内に、__start script__を追加します。
これが無いとデプロイ後にアプリを起動しても、 `npm ERR! missing script: start `とエラーが発生してしまいす。
`"start": "node app.js"`を追記してください。

```package.json
{
  "name": "heroku-app",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "node app.js",  //ここに追記
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "dotenv": "^10.0.0",
    "ejs": "^3.1.6",
    "express": "^4.17.1",
    "nodemon": "^2.0.12",
    "pg": "^8.7.1"
  }
}
```


####2-2.Herokuアカウント作成
それではデプロイ作業に入っていいきますが、まずはHerokuアカウントを作成してください。
作成手順は以下参考に↓
[超初心者がherokuにPHPアプリを公開してみた！～アカウント作成編～](https://qiita.com/youth_case/items/f053e6542a8b65ad21aa)

####2-3.Heroku CLI インストール
次に__Heroku CLI__をインストールします
__Heroku CLI__はHerokuをコマンドライン上から操作するためのツールです。
デプロイ作業には、こちらのツールが必要となります。

```
$ brew tap heroku/brew && brew install heroku
	#インストール

$ heroku --version
	#バージョン確認
``` 

####2-4.Herokuにログイン
「2-2.Herokuアカウント作成」で作成したアカウントでHerokuにログインします。

```
$ heroku login -i
  heroku: Enter your login credentials
  Email: メールアドレス
  Password: パスワード

  Logged in as メールアドレス
```

####2-5.デプロイ！
以下コマンドを実施して、Herokuに__Heroku-app__をデプロイします。
デプロイはgitを使用して、Herokuのリモートリポジトリにソースをコミットします。
※コマンド実施の際には、デプロイするアプリのディレクトリ（今回だとHeroku-app）に移動しておいてください。

デプロイ手順はHerokuの「マイページ」-「Deploy」からでも確認できますが、うまくいかなかったので、自分がうまく行った時の手順を記載しておきます。

```
$ git init
	#アプリをgitの管理下に置く

$ git add .
	#全てのフォルダやファイルを管理対象にすることを明示する

$ git commit -m "コメント"
	#現在の状態をコメント付きで保存する

$ git remote add heroku http://git.heroku.com/[アプリ名].git
	#リモートリポジトリの追加

$ git push heroku master
	#Herokuにpushする
```


###2-6.ブラウザでデプロイを確認！
先ほど__localhost:300__で開いた「Hello World!」ページが、__https://[アプリ名].herokuapp.com/__で開けたら成功です！
また以下コマンドで、ターミナルからもWebページを開くことができます。

```
$ heroku open
	#アプリを起動する
```




#3.PostgreSQLでDB接続（local）
さてさて、Herokuにデプロイできたとのことで、そしたら次にPostgreSQLでDB接続できるようにしていきましょう！
※詳しいDB操作に関しては、すみませんがここでは割愛しますｍｍ

####3-1. PostgreSQLインストール
まずはローカルの開発環境を整えていきます。
ターミナルでHomeBrewからPostgreSQLをインストールしましょう。

Heroku Postgresでは以下をサポートしてるとのことです。
デフォルトが11とのことなので、インストールするポスグレのバージョンも11に合わせるのが良いと思います。

　　・11 (デフォルト)
　　・10
　　・9.6
　　・9.5
　　・9.4 - 非推奨
参照：[Heroku Postgres](https://devcenter.heroku.com/ja/articles/heroku-postgresql#sharing-heroku-postgres-between-applications)

ただ自分は最新バージョンで行いました。（13.4）
推奨バージョンに関しては、さっき知ったんです。笑
特にこれによる不具合等はないはずなので、気分で良いかと思います。（無責任）

```
$ brew install postgresql
	#最新バージョンインストール

$ brew install postgresql@11
	#バージョン指定（ver.11)

$ postgres --version
	#バージョン確認

$ brew upgrade postgres
	#アップデート
```

####3-2.PostgreSQLへ接続
以下コマンドでPostgreSQLへ接続します。
使用するDBはデフォルトで作成されている`postgres`を使用します。
本当は`postgres`を使用するのではなく、新たに作った方が良いとどっかでみた気がしますが、気になる方はググってください。

```
$ psql -d postgres
```

`psql -h [ホスト名] -p [ポート番号] -U [ユーザー] -d [データベース名]`
　　・d : データベースを指定（未指定でログインユーザー名のデータベース）
　　・U : ユーザーを指定（未指定だとログインユーザー）
　　・h : ホスト名（未指定だとlocalhost)

####3-3.テーブル作成
接続したDB内（今回だとpostgres）にテーブルを作成します。
今回は以下のようにしました。

テーブル名：　test-tb　

| id | name |
|:---|:-----|
| 1  | Sato |
| 2  | Kato |
| 3  | Ito  |

```
create table test-tb(
  id integer generated always as identity,
  name varchar(30)
);

insert into test-tb( name ) values ('Sato');
insert into test-tb( name ) values ('Kato');
insert into test-tb( name ) values ('Ito');
```

####3-4.pgのインストール
Node.jsからPostgreSQLに接続できるように、pgモジュールをインストールします。
既にインストール済みであれば不要です。
ターミナルで以下を実行します

```
$ npm install pg
```

####3-5.Node.jsからPostgreSQLに接続できるように設定
PostgreSQLに接続できるように、「app.js」に追記します。

```app.js
  :
// -----------------------------------------------
//      Routing
// -----------------------------------------------
app.get('/', (req, res) => {
　　//PostreSQL接続
  connection.query(
    'SELECT * FROM testTable', //発行するクエリ
    (error,result) => {
      if(error) throw err;
      res.render('index.ejs',{items:result.rows}); //クエリ結果をitemsとしてindex.ejsに渡す
    }
  );
});

// -----------------------------------------------
//      postgresql設定
// -----------------------------------------------
const { Client } = require('pg');

// --------  接続情報  -----------
const connection = new Client({
  //接続先DB情報を記述
  host: 'localhost',
  user: 'Macのユーザーアカウント名',
  password: 'ユーザーのパスワード',
  database: 'postgres'
});

// --------  接続  -----------
connection.connect((err) => {
  //接続できなかったとき、エラーをコンソールに表示させる
  if(err){
      console.log('error connecting:' + err.stack);
      return;
  }
  //今回はわかりやすいように、接続に成功したらコンソールに「success」と表示されるようにします
  console.log('success');
});
  :
```

####3-6.取得したDB情報を表示できるようにする
`index.ejs`でDBから取得したテーブル情報を表示できるようにしましょう。

````index.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
  <h1>Hello World!</h1>
  <!-- ↓↓↓↓↓　ここから　↓↓↓↓↓↓ -->
  <ul class="table-body">
    <% items.forEach((item) => { %>
      <li>
        <div class="item-data">
          <span class="id-column"><%= item.id %></span>
          <span class="name-column"><%= item.name %></span>
        </div>
      </li>
    <% }) %>
  <!-- ↑↑↑↑↑　ここまで　↑↑↑↑↑ -->
  </ul>
</body>
</html>
````

####3-7.アプリを起動して確認！
設定ができたので、`localhost:3000`に接続して、テーブル情報を取得、表示できてるか確認しましょう

ターミナルでアプリを起動して

```
$ node app.js
```

ブラウザで`localhost:3000`を指定して、以下のようにテーブル情報が表示されれは成功です！！！
※cssは割愛しております。

```
Hello World !

-------------
| 1  | Sato |
| 2  | Kato |
| 3  | Ito  |
-------------
```

#4.Heroku Postgres に接続だ！
それでは、__Heroku Postgres__に接続していきましょう！

####4-1.まずはHeroku Postgresを利用できるようにする
まずは、Heroku Postgresを利用できるようにしましょう！
Herokuマイページの「Resources」-「Add-ons」から、__Heroku Postgres__を追加することで利用できるようにすることができます。
 
詳しい追加手順は以下を参考にしてください。
参照：[[Heroku Postgres] Herokuを使って無料でデータベースを利用する](https://qiita.com/fukke0906/items/07f3883742a8b6cd3c88)

###4-2.Heroku Postgresにテーブル情報を追加
Heroku Postgersが利用できるようになったら、ローカルに追加のと同じテーブルを、HerokuのDBにも追加します。

以下コマンドでHerokuデータベースにログインして

```
$ heroku pg:psql
```

ローカルと同じく下記テーブルを作成してください

テーブル名：　test-tb　

| id | name |
|:---|:-----|
| 1  | Sato |
| 2  | Kato |
| 3  | Ito  |

```
create table test-tb(
  id integer generated always as identity,
  name varchar(30)
);

insert into test-tb( name ) values ('Sato');
insert into test-tb( name ) values ('Kato');
insert into test-tb( name ) values ('Ito');
```

####4-3.dotenvのインストール
dotenvモジュールをインストールして、環境変数を使用できるようにします。
DB情報をそのまま記述してでも接続可能ですが、gitにそのままDB情報をあげると知らん人もいじれるようになっちゃうので、環境変数を設定しましょう。

ターミナルで以下コマンドを実行します。

```
$ npm install --save dotenv
```

####4-4.「.env」ファイルの作成
カレントディレクトリ配下に「.env」ファイルを作成します。
「.env」ファイルには、利用する環境変数を設定します。
`dotenv`をインストールすることで、 process.env 経由で参照できるようになります。

```
heroku-app
 L node_modules
   public
   views
      L index.ejs
   app.js
   .env  //作成する
   package-lock.json
   package-json
```

作成した「.env」ファイルに、Heroku Postgresの情報を記述します。
こちらは、HerokuのWebページ「Heroku Postgres」-「Settings」の__URI__に記載してあります。

```..env
DATABASE_URL = 'postgres://[User]:[Password]@[Host]:[Port]/[Database]'
```

これにより、`process.env.DATABASE_URL`で、DB情報を呼び出すことができます。

####4-5.dotenevを利用できるようにする
`dotenv`を利用できるように設定します。
`app.js`に以下を追記してください。

`require('dotenv').config();`

また`dotenv.config()` のオプションで debug フラグを true に設定しておくと、dotenv の処理内容が表示されるようになります。 これにより、「.env」ファイルの記述方法のミスなどを発見できます。

```app.js
  :
// -----------------------------------------------
//      postgresql設定
// -----------------------------------------------
const { Client } = require('pg');
require('dotenv').config({debug:true});  //ここに追加

const connection = new Client({
  connectionString: process.env.DATABASE_URL  //DB情報を環境変数DATABASE_URLに変更
});
  :
```

####4-6.「.gitignore」ファイルを作成する
「.env」ファイルは、ユーザ固有の設定や、Web API 接続用のキーなどの設定を行うために使用されます。
なのでgitなどのバージョン管理システムには、「.env」ファイルをコミットしないようにしなければなりません。

「.gitignore」ファイルを作成し、そこにファイル名を記述することで、Gitの管理化から外すことができます（git status などでコミット候補として表示されなくなります）

```
heroku-app
 L node_modules
   public
   views
      L index.ejs
   app.js
   .env
   .gitignore  //作成する
   package-lock.json
   package-json
```

```..gitignore
.env
```

####4-7.SSL通信の設定
Heroku Postgresに接続するためには、SSL通信にする必要があります。
いろいろ調べたのですが、以下のようにすれば問題なく接続ができるはずです。
ローカル、Herokuデプロイ後も共にこの設定で大丈夫です！

```app.js
  :
// -----------------------------------------------
//      postgresql設定
// -----------------------------------------------
const { Client } = require('pg');
require('dotenv').config({debug:true});

const connection = new Client({
  connectionString: process.env.DATABASE_URL,
  //SSLを設定
  ssl: {
    sslmode:'require',
    rejectUnauthorized:false
  }
});
  :
```

####4-8.さぁpushだ！
これで準備は完了です！
Herokuに変更した内容をpushしましょう！

```
$ git add .
	#全てのフォルダやファイルを管理対象にすることを明示する

$ git commit -m "コメント"
	#現在の状態をコメント付きで保存する

$ git push heroku master
	#Herokuにpushする

$ heroku open
	#アプリを起動する
```

エラーなくWebページを開くことができたでしょうか？！

#5.おわりに
先人の方々の記事を参考にさせていただけたので、なんとかデプロイすることができました。
ただ十人十色で、それぞれコードが違ってて、「どれが正解なの？」ととても混乱しました。またそれぞれの段階での記事はあったのですが、一気通貫で環境構築からHerokuにデプロイ、DB接続をする記事は見つけることができませんでした。

Herokuは無料なので、自分と同じくHerokuを利用してアプリのデプロイしてみたいという人が、特に初心者の方は多いと思うので、一つの参考にしていただけたらと思います。

記憶が曖昧ながら書いたところもあるので、記事の通りにやったけどうまくいかないということがあればコメントいただければと思います。
自分が抜け漏れ間違いしてるかもしれませんｍｍ

それではお互い今後も頑張っていきましょう！！