Skip to main content

Display loaders without requiring AJAX

Project description

Flask-Suspense

Display loaders without requiring AJAX. Use streaming templates to delay the rendering of parts of the template to the end of the response.

This is similar to React's Suspense and Next.js data loading mechanism.

Installation

pip install flask-suspense

Usage

Enable the Suspense extension. Decorate your long running data loader using @defer and pass it to the template. Render the template using flask_suspense.render_template.

from flask import Flask
from flask_suspense import Suspense, defer, render_template

app = Flask(__name__)
Suspense(app)

@app.route('/')
def index():

    @defer
    def data():
        time.sleep(2)  # Simulate a long-running process
        return "Loaded data"
    
    return render_template('index.html', data=data)

In your template, use the {% suspense %} block to defer rendering to the end of the template.

{% suspense %}
    {{ data }}
{% endsuspense %}

You can also display a loading message:

{% suspense %}
    {{ data }}
{% fallback %}
    <p>Loading...</p>
{% endsuspense %}

[!TIP] The {% suspense %} block does not require the use of @defer loaders. It will simply delay the rendering of its content to the end of the template.

[!TIP] Using Flask.render_template() will work as usual, suspense blocks will not be suspensed and rendered immediatly in place

[!TIP] flask_suspense.stream_template() is also available

Usage with Content Securiy Policy (CSP)

Using suspense blocks will use inline script tags. This may conflict with your content security policy.

A nonce can be provided to ensure the script tag is allowed. Set the nonce via g.suspense_nonce.

@app.before_request
def setup_nonce():
    g.suspense_nonce = "random string"

@app.after_request
def setup_csp(resp):
    resp.headers['Content-Security-Policy'] = f"script-src 'nonce-{g.suspense_once}';"
    return resp

About the loader

A loading div will be inserted in place of your suspense block. This div has a suspense-loader class. It will be replaced once the content is loaded.

How does it work ?

Streaming responses allow to start sending back to the response in multiple parts.

When rendering, {% suspense %} blocks are converted to macros and replaced by a loading div at the location they have been used.

The template is rendered in full first, without calling the suspense macros. It is sent back to the client. While the template is rendered, suspense blocks "register" themselves in the current rendering context.

"Registered" suspense macros are then called and their results are sent back wrapped in script tags that replace the loaders.

Registering macros allows us to catch the template they are defined in. This enables using suspense in includes as well.

@defer loaders ensures that the data loading will only start when the object is called as part of the macro, at the end of the stream.

Customizing how content is inserted

When a suspense block is sent to the client, it replaces the loader using a simple document.getElementById(suspenseId).outerHTML = suspenseBlockHtml.

This can be customized by providing a custom function window.__replace_suspense__ on the frontend.

<script>
    window.__replace_suspense__ = (id, html) => {
        console.log(`Received suspense block ${id}`)
        document.getElementById(id).outerHTML = html;
    };
</script>

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

flask_suspense-0.3.0.tar.gz (4.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

flask_suspense-0.3.0-py3-none-any.whl (5.2 kB view details)

Uploaded Python 3

File details

Details for the file flask_suspense-0.3.0.tar.gz.

File metadata

  • Download URL: flask_suspense-0.3.0.tar.gz
  • Upload date:
  • Size: 4.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.8.17

File hashes

Hashes for flask_suspense-0.3.0.tar.gz
Algorithm Hash digest
SHA256 98f4112eedc89045629c265f8438d12450f0d19a7df0cc0c261d8a7916db0c76
MD5 1d6ce4947ec094e96765588e0ea48834
BLAKE2b-256 51efa5079465d408c6459e895a2264f037b2a75c94a8e98f3cf81c94083fdc3f

See more details on using hashes here.

File details

Details for the file flask_suspense-0.3.0-py3-none-any.whl.

File metadata

File hashes

Hashes for flask_suspense-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 c676545a3ef7242e1326c71ca457f73fc648630a1291e2369d3450f94594d56c
MD5 75b9d816603a1bc338feac6558a99726
BLAKE2b-256 041a8cf369c9dacf799c8c093c9d7572fb42142781822bc1186d5036e92d09af

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page