[PHP] Herokuへのデプロイでrequire-devの依存もインストールする
課題
Heroku標準のPHP buildpack を使ってPHPのプロジェクトをデプロイする際、実行されるビルドコマンドは
$ composer install --no-dev --prefer-dist --optimize-autoloader --no-interaction
となっています。(参考)
つまり、 require-dev で依存しているライブラリはインストールされません。
しかし、ステージング環境としてHerokuを使っている場合など、一時的にアプリのデバッグモードをONにするために require-dev の依存もインストールしたいことがあります。
例えばSymfonyなら、無造作にHerokuの環境変数で
APP_ENVをdevにしてしまうと、require-devで依存しているクラスが見つからずClassNotFoundErrorになってしまいます。
解決策
Herokuでは composer install コマンドの実行後に
composer compile --no-dev --no-interaction
という カスタムコマンド が実行される仕様(参考)なので、ここで改めて require-dev の依存をインストールするようにしてあげれば解決できます。
# composer.json
{
"scripts": {
"compile": [
"composer install --prefer-dist --optimize-autoloader --no-interaction",
]
},
}
ただし、これだと普段 APP_ENV=prod で運用しているときにも常に composer install が2回実行されることになり非効率なので、以下のように APP_ENV=dev の場合にのみ実行するようにしておくのがよいでしょう。
{
"scripts": {
"compile": [
"if [ $APP_ENV = 'dev' ]; then composer install --prefer-dist --optimize-autoloader --no-interaction; fi",
]
},
}
ちなみに、データベースのマイグレーションコマンドなんかもこの
compileカスタムコマンド内で実行するのがセオリーですね。{ "scripts": { "compile": [ "if [ $APP_ENV = 'dev' ]; then composer install --prefer-dist --optimize-autoloader --no-interaction; fi", "php bin/console doctrine:migrations:migrate -n --no-debug" ] }, }
app.json の scripts.postdeploy でもできる?
- app.json のスキーマ | Heroku Dev Center
#scripts - レビューアプリ (新しいバージョン) | Heroku Dev Center
#the-postdeploy-script
この辺を見る限り、composer.json の compile カスタムコマンドを使わずに app.json を
{
"scripts": {
"postdeploy": "composer install --prefer-dist --optimize-autoloader --no-interaction && php bin/console doctrine:migrations:migrate -n --no-debug"
}
}
みたいな内容で作っておくでも期待どおり動くのかもしれません。が、未確認ですごめんなさい🙏
ちなみに:Symfonyの場合の注意点
注意点1
なお、先に挙げたSymfonyを APP_ENV=dev で動かしたいというケースでは、たとえこの方法で require-dev の依存をインストールするとしても、デプロイの時点で APP_ENV=dev をセットしてしまっていると ClassNotFoundError になります。
なぜなら、1回目の composer install --no-dev の直後に post-install-cmd フックで bin/console cache:clear などを実行するためにSymfonyが起動されてしまうからです。
なので、あくまで普段は APP_ENV=prod にしておいて、いざデバッグしたいときに APP_ENV=dev に変更してアクセスする、というような使い方になります。
これを回避するには、post-install-cmd で @auto-scripts (cache:clear などを含む)を --no-dev オプションが付いていない場合のみ実行するようにすればよいです。
具体的には以下のように COMPOSER_DEV_MODE 環境変数が 0 でない(= --no-dev が付いていない)場合にのみ composer auto-scripts によって @auto-scripts を実行するようにします。
"post-install-cmd": [
- "@auto-scripts"
+ "if [ $COMPOSER_DEV_MODE -ne 0 ]; then composer auto-scripts; fi"
]
注意点2
ここまでの対応だと、Herokuで実際に画面を開いたときに
Mixed Content: The page at 'https://xxx.herokuapp.com' was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint 'http://xxx.herokuapp.com/_wdt/xxxxxx'. This request has been blocked; the content must be served over HTTPS.
といったエラーによりデバッグツールバーが表示されないかもしれません。
この場合、config/packages/framework.yaml に以下のような設定を追記することでエラーを解消できます。
信頼できるリバースプロキシに対してしかアプリケーションサーバーが応答しないように構成されていることが前提の設定です。Heroku以外の環境で同様の設定を行う場合は十分に注意してください。
when@dev:
framework:
trusted_proxies: REMOTE_ADDR
まとめ
- PHPプロジェクトをHerokuへデプロイする際にrequire-devの依存もインストールしたければ、
APP_ENV=devの場合にのみcompileカスタムスクリプト内で改めてcomposer installしてあげればよい

Discussion