[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