見出し画像

「保存したのに画面が変わらない」を卒業する — Flask のホットリロード完全ガイド

「<p>Hello, Flask!</p>」を「<p>こんにちは、Flask!</p>」に書き換えて、保存して、ブラウザに戻ってF5。また書き換えて、保存して、F5。

……この「F5」、いりません。

この記事では、ターミナルを2枚使って「コードを保存した瞬間にブラウザの表示が切り替わる」環境を作ります。hello.py のコードには一切手を加えません。全部コマンドラインだけで完結します。

想定読者は、Flask のチュートリアルで hello.py を書いたところの人。環境は Windows 11 / PowerShell / .venv、後半だけ Node.js を使います。

1. 今回のゴール

最終的にこうなります。

ブラウザ  ──►  browser-sync (:3000)  ──►  Flask 開発サーバー (:5000)
   ▲                  │                        │
   └── 自動リロード ───┘                        └── hello.py 保存で自動再起動
              (hello.py を監視)

ポイントは、「サーバーの再起動」と「ブラウザの更新」は別物だということ。この2つを別々に解決するのでターミナルが2枚必要になります。ここが分かると一気に腹落ちします。

2. 題材のコード

今回動かすのはこれだけです。

from flask import Flask

app = Flask(__name__)

@app.route("/")
def hello_world():
    return """<!doctype html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title>Hello Flask</title>
  </head>
  <body>
    <p>Hello, Flask!</p>
  </body>
</html>
"""
  • app = Flask(__name__) — アプリ本体を作ります。__name__ は「このファイルの名前」で、Flask はこれを手がかりに templates/ や static/ フォルダの場所を探します。今は「おまじない」で構いません

  • @app.route("/") — デコレータ。「http://localhost:5000/ にアクセスが来たら、下の関数を呼んでね」という登録です

  • return """...""" — 三重引用符の複数行文字列。関数が返した文字列が、そのままブラウザに届く HTML になります。Flask が自動で Content-Type: text/html の 200 レスポンスに包んでくれるので、難しいことを考える必要はありません

  • <meta charset="utf-8"> と lang="ja" があるので、日本語を書いても文字化けしません

3. app.run() が無いのに、どうして動くの?

多くの入門書には、ファイルの末尾にこう書いてあります。

if __name__ == "__main__":
    app.run(debug=True)

でも今回の hello.py にはこれがありません。python hello.py を実行しても、何も起きずに終了します(エラーも出ないので余計に混乱します)。

正解は、Flask 付属のコマンドを使うことです。

flask --app hello run

--app hello は「hello.py の中にある app という変数を使ってね」という指示。起動処理は Flask 側が持っているので、アプリ側に app.run() を書く必要がないのです。

最近の Flask 公式チュートリアルはこちらのスタイルです。app.run() を書く方式が間違いというわけではなく、「起動方法が2通りある」というだけ。混在した情報にぶつかっても慌てないでください。

4. ターミナル1 — サーバーを自動再起動させる

1枚目のターミナルでは Flask を起動します。

.venv\Scripts\activate

flask --app hello run --debug --port 5000

--debug が主役です。これを付けるとこう表示されます。

 * Debug mode: on
 * Running on http://127.0.0.1:5000
 * Restarting with stat
 * Debugger is active!

Restarting with stat は、Flask がファイルの更新時刻を見張っているという意味。hello.py を保存すると、

 * Detected change in '...hello.py', reloading

と出て、サーバーが自動で再起動します。もう Ctrl+C して起動し直す必要はありません。

--debug にはおまけもあって、エラーが起きたときブラウザに詳しいエラー画面が出ます。これが初心者には本当にありがたい。

なお 5000 番は Flask のデフォルトなので --port 5000 は省略可です。このターミナルは閉じずに、開いたまま放置します。

5. でも、まだF5を押している

ここで気付きます。サーバーは再起動しているのに、ブラウザの表示は古いまま

当然です。--debug が面倒を見ているのは Python のプロセスだけで、ブラウザには何も伝わっていません。ブラウザは「もう一回ページをちょうだい」と言われない限り、手元の表示を出し続けます。

つまり、ブラウザに「更新して」と伝える役目の人が、もう一人必要なんです。それがターミナル2の仕事です。

6. ターミナル2 — ブラウザまで自動更新する

ここで browser-sync というツールを使います。Node.js 製なので、node -v でバージョンが表示されることだけ先に確認してください。

2枚目のターミナルで、プロジェクトフォルダに移動して:

npx browser-sync start --proxy 127.0.0.1:5000 --port 3000 --files hello.py --reload-delay 1000 --no-notify

初回は「ダウンロードしていい?」と聞かれるので y。しばらくするとブラウザが自動で開きます。

開くのは http://localhost:3000 です。5000 番ではありません。 ここが最重要ポイント。

browser-sync は Flask の「前」に立って、こういう仕事をします。

  • ブラウザからのリクエストを 5000 番の Flask に中継する

  • Flask が返した HTML に、自動更新用の小さな JavaScript をこっそり差し込む

  • hello.py の変更を検知したら、その JavaScript に「リロードして」と命令する

2番目のおかげで、hello.py に自動更新用のコードを1行も書かずに済むわけです。

オプションの意味はこちら。

  • --proxy 127.0.0.1:5000 … Flask に中継し、HTML に自動更新スクリプトを注入する

  • --port 3000 … browser-sync 自身の待ち受けポート。ブラウザで開くのはこっち

  • --files hello.py … 監視対象のファイル。これが変わったらブラウザをリロード

  • --reload-delay 1000 … Flask の再起動完了を1秒待つ。これが無いと事故ります(後述)

  • --no-notify … 画面隅に出る通知バッジを消す。好みで外してOK

動作確認

hello.py の Hello, Flask! を書き換えて保存してください。F5 を押さずにブラウザの文字が変わったら成功です。

このとき2枚のターミナルにはそれぞれ:

ターミナル1 > Detected change in '...hello.py', reloading
ターミナル2 > [Browsersync] Reloading Browsers...

と出ます。この2行が並んで出るのを見ると、「2人で分担している」構図が実感できるはずです。

7. つまずきポイント3つ

① 5000番を開いてしまう

一番多いミスです。5000 番は Flask の直通なので、browser-sync のスクリプトが入らず自動更新は効きません。ブックマークを 3000 番に変えておきましょう。

② 起動順を逆にする

browser-sync を先に立ち上げると、中継先の Flask が居ないためエラーページが出ます。慌てず、Flask を起動してからブラウザを1回リロードすれば復帰します。順番は必ず「Flask → browser-sync」。

③ --reload-delay を付けない

保存直後、Flask はまだ再起動の途中です。そこに browser-sync が即座にリロードをかけると、まだ起きていないサーバーを叩いて接続エラー画面になることがあります。1秒待たせるだけで安定します。「たまに失敗する」の犯人はだいたいこれです。

8. まとめ

  • flask --app hello run なら、app.run() を書かなくてもアプリは起動する

  • --debug が面倒を見るのはサーバーの再起動まで。ブラウザは別問題

  • browser-sync をプロキシとして挟むと、アプリのコードを1行も変えずにブラウザの自動更新まで手に入る

  • ターミナル2枚は、この「役割が2つある」ことの素直な反映

環境を整える時間は、後で必ず回収できます。F5 を押していた3秒が、これから書く数百回の保存すべてから消えます。

いいなと思ったら応援しよう!