【初学者】Herokuデプロイ時に詰まったこと【Webアプリ開発の道~その2~】

# はじめに
こんにちは。「塵も積もれば山となる」精神で日々学習しながら、Webアプリ開発に取り組んでいます。

# 何を書いたか
今回はローカル環境で作成したRails6アプリ（Hello,Worldの出力）をHerokuにデプロイする際に詰まったことについて書きます。Railsチュートリアル（第6版）では1章と3章前半部分の内容です。

# なぜ書いたか
RailsチュートリアルどおりにAWSのCloud9を開発環境として、Herokuにデプロイしたときにはすんなり上手くいったのですが、ローカル環境からHerokuにデプロイしようとすると、まぁまぁ大量のエラーが発生しました笑

前回の[ローカル環境構築](https://qiita.com/kosukein38/items/aff73fda16a1447e6db3) に続き、こちらも一日がかりでデバッグして、ようやくデプロイ成功したので、エラーデバッグ方法を備忘録として記事にしました。同じような境遇になった方の参考になれば幸いです。

エラーのデバッグが経験値を上げると信じて、できるだけエラーの意味を解釈しながら進めていったつもりです。しかし、どうしてもフォローアップできていない部分もあるため、理解できたら随時記事は更新していこうと思います。というのも、Herokuにデプロイできるようにするのはアプリ開発の過程で大切ですが、Herokuの使い方の学習を深めても、そこまで意味がないかなと判断したので、そこまで深入りせずに要点だけおさえるように気をつけながらデバックしました。

# 本題
やりたいことは"Hello,world!!"をブラウザに出力するだけの処理です。GitHubとHerokuの設定はRailsチュートリアルに沿って実施しました。

routes.rbにルーティングを設定して、application_controller.rbにhelloアクションを定義。

```ruby:config/routes.rb
Rails.application.routes.draw do
  root 'application#hello'
end
```

```ruby:app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  def hello
    render html: "hello, world!"
  end
end
```
これだけ。
まずは rails serverを立ち上げ、http://localhost:3000 にアクセスしてローカル環境で問題ないかチェック。問題なさそう。
よし、Githubにプッシュした後、Herokuにデプロイすると。
エラーがぞくぞく

### デバッグ1 platform x86_64-linuxをGemfile.lockに指定
以下のエラーメッセージが表示された。

```bash
Your bundle only supports platforms ["x86_64-darwin-20"] but your local platform is x86_64-linux. 
Add the current platform to the lockfile with `bundle lock --add-platform x86_64-linux` and try again.
```

Heroku環境(local platform)がLinuxだからx86_64-linuxも使われることをGemfile.lockに指定しろということのようです。
いわれたとおりに、以下のコマンドを実行してみる。

```bash
$ bundle lock –add-platform x86_64-linux
```

### デバッグ2　ローカルとHerokuのNode.js, npm, yarnのバージョン合わせ

上の問題は解決されるも、次は以下のエラーメッセージが表示された。

```
# 以下 "heroku logs --tail" 実行結果

#(略)
2022-02-13T13:45:01.785862+00:00 heroku[web.1]: Starting process with command `npm start`
2022-02-13T13:45:06.958136+00:00 app[web.1]: npm ERR! Missing script: "start"
2022-02-13T13:45:06.958371+00:00 app[web.1]: npm ERR!
#(略)
```

npm周りのエラーが続出している。ログをたどると、どうやらローカル環境のnpmのバージョンとHerokuで使うnpmのバージョンが異なっているよう。

```bash
#以下、Herokuデプロイ時の実行ログ
#(略)
emote: -----> Installing binaries
remote:        engines.node (package.json):  unspecified
remote:        engines.npm (package.json):   unspecified (use default)
remote:        engines.yarn (package.json):  unspecified (use default)
remote:        
remote:        Resolving node version 16.x...
remote:        Downloading and installing node 16.14.0...
remote:        Using default npm version: 8.3.1
remote:        Resolving yarn version 1.22.x...
remote:        Downloading and installing yarn (1.22.17)
remote:        Installed yarn 1.22.17
#(略)

$ node --version
#=> v16.14.0
$ npm --version
#=> 8.5.0
$ yarn --version
#=> 1.22.17
```

Herokuで使用するNode.js,npm,yarnのバージョンはPackage.jsonファイルで指定できるそうなので、以下のようにPackage.jsonファイルに追加して保存してみた。

```json:Package.json
{
  #(略)

  "engines": {
    "node": "14.19.0",
    "npm": "8.5.0",
    "yarn": "1.22.17"
  },
}
```

再度デプロイすると、ログから、指定したバージョンでNode.js,npm,yarnを使えてそう。

```bash
remote: -----> Installing binaries
remote:        engines.node (package.json):  14.19.0
remote:        engines.npm (package.json):   8.5.0
remote:        engines.yarn (package.json):  1.22.17
remote:        
remote:        Resolving node version 14.19.0...
remote:        Downloading and installing node 14.19.0...
remote:        Bootstrapping npm 8.5.0 (replacing 6.14.16)...
remote:        npm 8.5.0 installed
remote:        Resolving yarn version 1.22.17...
remote:        Downloading and installing yarn (1.22.17)
remote:        Installed yarn 1.22.17
```

しかし、この後再度同じエラーに。次の手を考えてみる。

### デバック3 Heroku側のビルドパックの設定

HerokuはソースコードからRubyアプリであることを自動検知して、一連のビルドプロセスのまとまり(ビルドパック)を使ってアプリを自動ビルドしてくれているとのこと。
これを設定してあげないと、アプリを自動で検知してくれない可能性があるので、設定しておく。

[Herokuの公式](https://devcenter.heroku.com/articles/using-multiple-buildpacks-for-an-app#adding-a-buildpack) を参考に。

```bash
$ heroku buildpacks:add --index 1 heroku/nodejs
$ heroku buildpacks:add --index 2 heroku/ruby
```
indexをこの順番で指定してしておくのがよさそう
というのも[Herokuの公式](https://devcenter.heroku.com/articles/using-multiple-buildpacks-for-an-app#adding-a-buildpack)によると

>The buildpack for the primary language of your app should always be the last buildpack in the list. This ensures that defaults for that primary language are applied instead of those for another language, and allows Heroku to correctly detect the primary language of your app.

つまり、アプリの第一言語​の buildpack は、常にリストの最後の​ buildpack にする必要があるとのこと。これにより、別の言語のデフォルト値でなく、その第一言語のデフォルト値が必ず適用されるようになり、Heroku でアプリの第一言語を正しく検出できるみたい。今回の場合rubyベースのアプリなので、最後にrubyのビルドパックを設定しておけばよさそう。
また、YarnからWebpackerを入れているので、Node.js のビルドパックも指定しておく必要がありそう。

### デバッグ4　Procfileの作成
まだnpm errorは解決しない。HerokuではWebアプリを動かす際にProcfileを読みにいくとのことなので、作ってみることに。
ProcfileとはHerokuのプラットフォーム上にあるWebアプリがどのようなコマンドで実行されるのかを記述するファイルのことで、Webアプリを動かす指示書みたいなもので、[Herokuの公式](https://devcenter.heroku.com/articles/procfile#the-web-process-type) から、アプリにWebサーバが含まれる場合は、その Web サーバーをアプリの web​ プロセスとして宣言する必要があるとのこと。

Procfile では、個々の行で、<process type>: <command>を使用してプロセスタイプを宣言します。

（Railsチュートリアルの教科書ではpumaをwebサーバーとして使うときに作成していました。Herokuのデフォルトでは、Rubyだけで実装されたWEBrickというWebサーバーを使っていて、指定がないデフォルトの場合ProcfileがなくてもWEBrickが走ると思っていたのですが、今回はエラーの要因になっているかもしれないため作成しました。）

```bash[Procfile]
web: bundle exec rails server -p $PORT
```
このProcfile(ファイルの拡張子なし)をルートディレクトリ（Gemfileと同じディレクトリ）に置いておく。これで再度実行するも、デプロイできず…。やはり関係なかった可能性大。

### デバック5 Node.jsのバージョン変更

エラーログをよくみると最後の方に以下のような記述があった。

```bash
gyp ERR! cwd /Users/user/projects/Appname/node_modules/node-sass
```
ググると同じような境遇の方を見つけました。私のNode.jsもバージョンを16系を使用していたため、こちらの回答を参考に14系にバージョンを下げてみることにしました。

```bash
# インストール可能なNode.jsバージョン確認
$ nodebrew ls-remote
# インストールしたいバージョンを指定してインストール（今回はv14.19.0）
$ nodebrew install v14.19.0
# インストールされているNode.jsのバージョンを確認
$ nodebrew ls
#=>
v14.19.0
v16.14.0
# 指定したバージョンの Node.js を有効にする
$ nodebrew use v14.19.0
# 有効になった Node.js のバージョン確認
$ node -v
#=>
v14.19.0
```
これで、Nodejsのダウングレードは完了。ここで再度デプロイしてみるも、webpackerのあたりでエラーが出る。
おそらく、Node.jsをダウングレードしたことにより、再度yarnやwebpackerのインストールが必要になるものと考えられます。（Node.js, npm, yarn, webpackerあたりがごちゃごちゃしているので、どこかで知識をまとめておきたい…。）
まず、webpackerのインストールを試みてみた。

````
$ rails webpacker:install
Calling `DidYouMean::SPELL_CHECKERS.merge!(error_name => spell_checker)' has been deprecated. Please call `DidYouMean.correct_error(error_name, spell_checker)' instead.
Calling `DidYouMean::SPELL_CHECKERS.merge!(error_name => spell_checker)' has been deprecated. Please call `DidYouMean.correct_error(error_name, spell_checker)' instead.
warning Integrity check: System parameters don't match                                              
error Integrity check failed                                                                        
error Found 1 errors.                                                                               


========================================
  Your Yarn packages are out of date!
  Please run `yarn install --check-files` to update.
========================================


To disable this check, please change `check_yarn_integrity`
to `false` in your webpacker config file (config/webpacker.yml).


yarn check v1.22.17
info Visit https://yarnpkg.com/en/docs/cli/check for documentation about this command.
````
やはりyarnのアップデートも必要みたい。いわれた通りにコマンドを実行してみる。

```bash
$ yarn install --check-files
bash: /Users/****/.nodebrew/current/bin/yarn: No such file or directory
```
失敗。おそらく、Node.jsをダウングレードしたことにより、yarnのアップデートではなく、yarnの再インストールが必要になるようだ。
https://teratail.com/questions/370151 を参考にコマンドを実行してみる。
（最初の環境構築ではhomebrewを使ってyarnを入れたのだが、Node.jsを入れる際に入ってくるnpmを使ってyarnをインストールした方が、もろもろの依存関係的に良いとのことなので、そうしてみた。[Yarnの公式](https://classic.yarnpkg.com/en/docs/install#mac-stable) でもnpmを使ったインストール方法が記載してあった。）

```bash
# npmを使ってyarnをインストール（グローバルオプションをつける）
$ npm install -g yarn
# インストールされたyarnの確認
$ yarn -v
#=>
1.22.17
```
これでyarnの再インストールは完了。
再度webpackerのインストールにトライ。

```bash
$ rails webpacker:install
#=>
#（略）
error Found 1 errors.                                                                               


========================================
  Your Yarn packages are out of date!
  Please run `yarn install --check-files` to update.
========================================


To disable this check, please change `check_yarn_integrity`
to `false` in your webpacker config file (config/webpacker.yml).


yarn check v1.22.17
#（略）
```
再び同じアップデート促すエラーが表示されたので、実行してみる。

```bash
$ yarn install --check-files
yarn install v1.22.17
[1/5] 🔍  Validating package.json...
[2/5] 🔍  Resolving packages...
[3/5] 🚚  Fetching packages...
[4/5] 🔗  Linking dependencies...
warning " > webpack-dev-server@4.7.4" has unmet peer dependency "webpack@^4.37.0 || ^5.0.0".
warning "webpack-dev-server > webpack-dev-middleware@5.3.1" has unmet peer dependency "webpack@^4.0.0 || ^5.0.0".
[5/5] 🔨  Building fresh packages...
✨  Done in 2.84s.
```
今度はうまくいったので、再度webpackerのインストールコマンドを実行。

```bash
$ rails webpacker:install
```
イストール成功しました。このあとHerokuにデプロイすると、ようやく "hello, world!"がルートの画面に表示されるようになりました！


# 最後に
最後まで読んでいただきありがとうございます！
先輩エンジニアのみなさまで、もしご覧になっていただけた方がいらっしゃれば、この操作は不要だったとか、こうすれば一発で解決したとかご指摘ありましたら、どんどん教えていただけると幸いです。