29

I've started learning Flask to develop web applications. What I am really missing is an automatic Browser refresh after any code change (including static files, templates, etc.). This seems to be a standard feature in almost any JavaScript framework. Frontend people have several terms for that: auto reload / refresh, hot reload / refresh (hotreload), live reload / refresh (livereload), ...

Here on Stackoverflow most similar questions are related to the auto-reload of the Flask server (--> https://stackoverflow.com/search?q=flask+auto+reload).

J just want a simple browser refresh.

I googled and tried several things - with no luck:

How can I have a smooth developing experience with Flask without having to hit the F5 key 1000 times a day in a browser just to see the results of my changes?

I think the answer is somewhere near to python-livereload from the link above. So I guess an alternative title of my question could be:

Does somebody have a working example of Flask + python-livereload?

I am to dumb to get it from their documentation :)

EDIT: for the sake of completeness here is the Flask app I am using.

# filename: main.py

from flask import Flask, render_template
from livereload import Server



app = Flask(__name__)

@app.route('/')
def index():
    return "INDEX"

@app.route('/bart')
def use_jinja():
    return render_template('basic.html')



if __name__ == '__main__':
    server = Server(app.wsgi_app)
    server.serve(port=5555)

I start the app with

python main.py
2
  • Notice, the accepted answer does not work anymore.
    – user1658543
    Commented Mar 23, 2023 at 11:32
  • do you know the working solution?
    – cikatomo
    Commented Jan 14 at 20:00

5 Answers 5

29

This is an interesting question you've raised so I built a quick and dirty Flask application which utilizes the livereload library. Listed below are the key steps for getting this to work:

  1. Download and install the livereload library:

    pip install livereload

  2. Within your main file which starts up your flask application, run.py in my particular case, wrap the flask application with the Server class provided by livereload.

For example, my run.py file looks like the following:

from app import app
from livereload import Server

if __name__ == '__main__':
    server = Server(app.wsgi_app)
    server.serve()
  1. Start your server again:

    python run.py

  2. Navigate to localhost in the browser and your code changes will be auto-refreshed. For me I took the default port of 5500 provided by livereload so my url looks like the following: http://localhost:5500/.

With those steps you should now be able to take advantage of auto-reloads for your python development, similar to what webpack provides for most frontend frameworks.

For completeness the codebase can be found here

Hopefully that helps!

17
  • 2
    Sounds good, I'll put my sample code on a public github so it will be easy to test for you
    – Nathan
    Commented Jul 10, 2019 at 17:10
  • 3
    This has solved all my frustrations with local flask development. Thank you! Commented Oct 22, 2020 at 11:06
  • 5
    The code doesn't work now
    – Ax M
    Commented Nov 13, 2021 at 15:08
  • 2
    everyone, please use version 2.5.1 of livereload, its not going to raise errors anymore, but the live reload is broken, sometimes its refreshes, sometimes it doesnt.
    – alexzander
    Commented Dec 3, 2021 at 23:44
  • 2
    I can confirm that downgrading (pip install livereload==2.5.1) does not show the error, but it also does not reload the page.
    – user1658543
    Commented Mar 23, 2023 at 11:31
2

I use Guard::LiveReload becose solution with python-livereload don't work correct with debug (for me).

In first terminal emulator:

$ cd my-flask-project
$ flask run
 * Serving Flask app 'webface' (lazy loading)
 * Environment: development
 * Debug mode: on
 * Running on http://127.0.0.1:54321/ (Press CTRL+C to quit)
 * Restarting with stat
 * Debugger is active!

In secondu terminal emulator:

$ cd my-flask-project
$ guard init livereload 

Now I edit Guardfile and add/edit watch. Like this:

  watch(%r{.+\.py})
  watch(%r{webface/.+\.(css|js|html(\.j2)?)})

again in second terminal emulator:

$ guard
17:29:25 - INFO - LiveReload is waiting for a browser to connect.
17:29:25 - INFO - Guard is now watching at '/home/marek/my-flask-project'
[1] guard(main)> 17:29:29 - INFO - Browser connected.
17:29:31 - INFO - Reloading browser: webface/templates/base.html.j2
17:45:41 - INFO - Reloading browser: webface/templates/base.html.j2
[1] guard(main)>

Maybe need to click livereload extention button in browser to connect browser to guard.

1

Tried this today, and it worked:

app.py:

# use livereload==2.5.1 only
from flask import Flask, render_template
from livereload import Server

app = Flask(__name__)
app.debug = True

@app.get("/")
def index():
    return render_template("index.html")

# don't use flask run, use python3 app.py
server = Server(app.wsgi_app)
server.watch("templates/*.*")  # or what have you
server.serve(port=5000) # if you want the standard Flask port

in templates/index.html, add the following script before </body>:

<script src="https://cdnjs.cloudflare.com/ajax/libs/livereload-js/3.1.0/livereload.min.js"></script>

Then:

python app.py

0

For those who want to avoid installing livereload, here's a simple solution from scratch:

livereload.js

from flask import Flask, Response
from textwrap import dedent

class LiveReload:
    def __init__(self, app: Flask = None):
        if app is not None:
            self.init_app(app)

    def init_app(self, app: Flask):
        app.after_request(self.after_request)

    def after_request(self, response: Response):
        if response.status_code != 200:
            return response

        mimetype = response.mimetype or ""
        if not mimetype.startswith("text/html"):
            return response

        if not isinstance(response.response, list):
            return response

        body = b"".join(response.response).decode()
        tag = self.make_tag()
        body = body.replace("</head>", f"{tag}\n</head>")
        response.response = [body.encode("utf8")]
        response.content_length = len(response.response[0])
        return response

    def make_tag(self):
        return dedent("""
            <script>
              document.write('<script src="http://' + (location.host || 'localhost').split(':')[0] +
              ':35729/livereload.js?snipver=1"></' + 'script>')
            </script>
        """).strip()

__init__.py

from flask import Flask
from livereload import LiveReload

app = Flask(__name__)
LiveReload(app)
2
  • Your opening statement and actual answer contradicts each other. You open saying to avoid loading livereload, but your example have "from liverload"…
    – Louis
    Commented Sep 6, 2024 at 7:31
  • Wait, how is it livereload.js (a javascript file), but clearly a python content?
    – Qwerty
    Commented Nov 11, 2024 at 20:07
-3

If on Windows:

set FLASK_ENV=development
1
  • 4
    this reloads the server but does NOT refresh the tab page in the browser
    – alexzander
    Commented Dec 3, 2021 at 22:42

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.