How to build an offline web app using Flask?
Question: I'm prototyping an idea for a website that will use the HTML5 offline
application cache for certain purposes. The website will be built with Python
and Flask and that's where my main problem comes from: I'm working with those
two for the first time, so I'm having a hard time getting the manifest file to
work as expected.

The issue is that I'm getting 404's from the static files included in the
manifest file. The manifest itself seems to be downloaded correctly, but the
files that it points to are not. This is what is spit out in the console when
loading the page:

    
    
    Creating Application Cache with manifest http://127.0.0.1:5000/static/manifest.appcache offline-app:1
    
    Application Cache Checking event offline-app:1
    
    Application Cache Downloading event offline-app:1
    
    Application Cache Progress event (0 of 2) http://127.0.0.1:5000/style.css offline-app:1
    
    Application Cache Error event: Resource fetch failed (404) http://127.0.0.1:5000/style.css
    

The error is in the last line.

When the appcache fails even once, it stops the process completely and the
offline cache doesn't work.

This is how my files are structured:

  * sandbox 
    * offline-app 
      * offline-app.py
      * static 
        * manifest.appcache
        * script.js
        * style.css
      * templates 
        * offline-app.html

This is the content of **offline-app.py** :

    
    
    from flask import Flask, render_template
    app = Flask(__name__)
    
    @app.route('/offline-app')
    def offline_app():
        return render_template('offline-app.html')
    
    if __name__ == '__main__':
        app.run(host='0.0.0.0', debug=True)
    

This is what I have in **offline-app.html** :

    
    
    <!DOCTYPE html>
    <html manifest="{{ url_for('static', filename='manifest.appcache') }}">
    <head>
        <title>Offline App Sandbox - main page</title>
    </head>
    <body>
    <h1>Welcome to the main page for the Offline App Sandbox!</h1>
    <p>Some placeholder text</p>
    </body>
    </html>
    

This is my **manifest.appcache** file:

    
    
    CACHE MANIFEST
    /style.css
    /script.js
    

I've tried having the manifest file in all different ways I could think of:

    
    
    CACHE MANIFEST
    /static/style.css
    /static/script.js
    

or

    
    
    CACHE MANIFEST
    /offline-app/static/style.css
    /offline-app/static/script.js
    

None of these worked. The same error was returned every time.

I'm certain the issue here is how the server is serving up the files listed in
the manifest. Those files are probably being looked up in the wrong place, I
guess. I either should place them somewhere else or I need something different
in the cache manifest, but I have no idea what. I couldn't find anything
online about having HTML5 offline applications with Flask.

Is anyone able to help me out?


Answer: I would have thought this one would work:

    
    
    CACHE MANIFEST
    /static/style.css
    /static/script.js
    

But in any case, you should not hardcode the URLs for your static files. It's
best to serve the manifest as a template (moved to the "templates" folder) so
that you can use `url_for` to generate the path to the static files, something
like this:

    
    
    CACHE MANIFEST
    {{ url_for('static', filename='style.css') }}
    {{ url_for('static', filename='script.js') }}
    

Then in your HTML template you would have a reference to a route instead of a
static file:

    
    
    <html manifest="{{ url_for('manifest') }}">
    

And finally, you would add a new view function that returns the manifest:

    
    
    from flask import make_response
    
    @app.route('/manifest')
    def manifest():
        res = make_response(render_template('manifest.appcache'), 200)
        res.headers["Content-Type"] = "text/cache-manifest"
        return res
    

