Generate Static Html With Flask Frozen

October 19, 2020

Note

If you already have a Flask project which you want to convert to static html, Flask-Frozen is up to the task.

If you just want to generate static HTML, refer to Which Static Site Generator To Use.

The latest version is Version 0.15 (Jun 27, 2017), but it generally works well.

Another issues that it is pretty slow as it run in sequential (about 1 page per second) and hardly utilize a single CPU fully. It might be possible to hack the code to utilize multiple CPU.

Install & Setup

pip install Frozen-Flask

Create static.py

# import flask app from your existing application
from application import app

from flask_frozen import Freezer

# optional
# from flask_minify import minify
# minify(app=app, html=True, caching_limit=0) # , js=True, cssless=True

# default to application root directory (same level as "templates") named "build"
FREEZER_DESTINATION = '../build' 

# MimetypeMismatchWarning: Filename extension of u'new-york' (type application/octet-stream) does not match Content-Type: text/html; charset=utf-8
# If the urls are '/new-york', it will warn of MimetypeMismatchWarning
# You could either disable warning, or change path to '/new-york/', which generate 'new-york/index.html'
FREEZER_IGNORE_MIMETYPE_WARNINGS = True

# If run the static generation for 30 minutes and then it crashed, this will only generate files which are not generated yet (basically continue from last run)
# If you change the page code and the content is different, it will not regenerate the page
FREEZER_SKIP_EXISTING = True

# This is useful during development as you might want to remove certain @freezer.register_generator to speed up the process, but don't want those generated files to be deleted
FREEZER_REMOVE_EXTRA_FILES = False


# load the above FREEZER_ configurations
app.config.from_object(__name__)

freezer = Freezer(app, with_static_files=True, log_url_for=False, with_no_argument_rules=False)

@freezer.register_generator
def url_generator():
    yield '/'
    yield '/about'

@freezer.register_generator
def venues_generator():
    from application.models import Venue

    items = Venue.query(Venue.is_active == True)

    for _item in items:
      # yield f"/venues/{_item.url_name}"
      yield 'venue.show', {'url_name': _item.url_name}


if __name__ == '__main__':
    freezer.freeze()
python static.py

Flask Routing

If the route is @app.route('/about'), it will generate about file. If the route is @app.route('/about/'), it will generate about/index.html file.

If the route @app.route('/about/privacy'), you must change @app.route('/about') to @app.route('/about/'), as generated about must be a directory in order for privacy to be generated within it.

└── about
    ├── index.html
    └── privacy

NOTE: You can use @app.route('/about/', strict_slashes=False) for optional trailing slashes, and still generate about/index.html.

References:

This work is licensed under a
Creative Commons Attribution-NonCommercial 4.0 International License.