Minify HTML output from Flask application with Jinja2 templates
Asked Answered
B

8

25

Is there a Flask or Jinja2 configuration flag / extension to automatically minify the HTML output after rendering the template?

Benson answered 27/11, 2012 at 15:31 Comment(2)
Have you seen github.com/mitsuhiko/jinja2-htmlcompressHi
@SeanVieira it removed lots of useful whitespaces actually.. so it's breaking your HTML..Peso
U
10

Have a look here https://github.com/cobrateam/django-htmlmin#using-the-html_minify-function

I realise it is mainly used for django but the example shows how to use this projects code to do what you want with a flask view, i think.

Unexampled answered 27/11, 2012 at 15:57 Comment(3)
Unfortunatelly, its setup.py file still requires Django.Dachshund
Not anymore, after this.Calkins
Is there a "deploy-time" solution, similar to how a lot of js projects do it? There is no reason to minify most templates and static data each time and on each request. Would be nice if it was possible to minify everything that's possible during, say, setup.py.Paraffinic
B
31

Found a better way to do this. You can minify all your pages with this method:

from flask import Flask
from htmlmin.main import minify

app = Flask(__name__)


@app.after_request
def response_minify(response):
    """
    minify html response to decrease site traffic
    """
    if response.content_type == u'text/html; charset=utf-8':
        response.set_data(
            minify(response.get_data(as_text=True))
        )

        return response
    return response
Bombay answered 1/10, 2014 at 10:53 Comment(3)
works perfectly as expected on python2.7, but behaves strangely on python2.6. Throws an "ValueError: zero length field name in format" exception.Indian
Thanks for that great code snippet. I've adapted it to beautify, not to minify the output: https://mcmap.net/q/538103/-is-there-a-way-to-clean-up-the-html-that-jinja2-producesCabe
Doesn't that minify the output at EVERY request? Couldn't it alter the cache version of the template (or minify it before it saves the cache)?Goddess
U
10

Have a look here https://github.com/cobrateam/django-htmlmin#using-the-html_minify-function

I realise it is mainly used for django but the example shows how to use this projects code to do what you want with a flask view, i think.

Unexampled answered 27/11, 2012 at 15:57 Comment(3)
Unfortunatelly, its setup.py file still requires Django.Dachshund
Not anymore, after this.Calkins
Is there a "deploy-time" solution, similar to how a lot of js projects do it? There is no reason to minify most templates and static data each time and on each request. Would be nice if it was possible to minify everything that's possible during, say, setup.py.Paraffinic
E
8

I use the following decorators

import bs4
import functools
import htmlmin


def prettify(route_function):
    @functools.wraps(route_function)
    def wrapped(*args, **kwargs):
        yielded_html = route_function(*args, **kwargs)
        soup = bs4.BeautifulSoup(yielded_html, 'html.parser')
        return soup.prettify()

    return wrapped

def uglify(route_function):
    @functools.wraps(route_function)
    def wrapped(*args, **kwargs):
        yielded_html = route_function(*args, **kwargs)
        minified_html = htmlmin.minify(yielded_html)
        return minified_html

    return wrapped

And simply wrapped the default render_template function like so

if app.debug:
    flask.render_template = prettify(flask.render_template)
else:
    flask.render_template = uglify(flask.render_template)

This has the added benefit of being auto added to the cache, since we don't actually touch app.route

Exotic answered 23/8, 2016 at 4:7 Comment(4)
Sadly you still need to apply to each of your view files importing it… I had hoped you could have just changed the engine and all output accross all my files would have been minified.Goddess
Why do you use your own decorator and not the one that already exists in htmlmin?Preoccupied
@Preoccupied To be honest, I wrote this answer 6 years ago when I was just starting college. I have to assume I just didn't see it in their docs or was feeling clever or something similar. I don't think the answer I gave is horribly bad though.Exotic
Also @jeromej, 5 years too late but this answer does affect the the entire engine since it replaces flask.render_template.Exotic
B
6

I've written a flask extension to achieve that purpose. You can install it using pip install flask-htmlmin and the source is available at https://github.com/hamidfzm/Flask-HTMLmin . Hope it will be useful.

Bombay answered 14/2, 2015 at 20:11 Comment(1)
From a thought of "I wonder how to easily minify HTML in flask" to "of course someone else had that question on SO" to "ah, naturally there is a library" and finally arrive at this answer with "the fabulous hamidfzm has a written a flask plugin that does it all in 2 lines" 🖤Palpate
F
5

Use the decorator.

from htmlmin.decorator import htmlmin

@htmlmin
def home():
...

Or you can just use:

re.sub(r'>\s+<', '><', '<tag>   </tag>') # results '<tag></tag>'
Finney answered 22/10, 2014 at 15:33 Comment(5)
Can you provide some reference link?Pentheas
Be careful with that regex, it might break your HTML in a visible way. Minifying the string a <b>big</b> <i>fat</i> <s>edit</s> here results in the output a <b>big</b><i>fat</i><s>edit</s> here -- the spaces have been clobbered.Padlock
White space between characters are omitted by the standards. One of the reasons why for example in Django there is a {% spaceless %} tag and htmlmin has minify method.Finney
Would that work with the cache or only Ethan McCue's answer would? (I've yet to investigate further but maybe you know the answer already_)Goddess
Of course it will. Ethan's method is a ridiculous overkill just cause of bs4.Finney
D
3

To extend the usefulness of the answer from @olly_uk and the comment by @Alexander, it appears that the django-htmlmin extension is now designed to be used with frameworks other than Django.

From the docs here, you can manually use the html_minify function in Flask views, like so:

from flask import Flask
from htmlmin.minify import html_minify

app = Flask(__name__)

@app.route('/')
def home():
    rendered_html = render_template('home.html')
    return html_minify(rendered_html)
Dinesen answered 26/5, 2014 at 12:20 Comment(4)
Does this work at template run-time or at compile time?Cheder
@llamawithabowlcut, html_minify is called after the template has been rendered at runtime. If the concern behind the question is performance, where possible I also couple this to a Flask cache (Flask-cacheify in my instance). If that's not possible, then yes it might be relatively expensive to call html_minify for each serving of a view.Dinesen
I can do this with the re module: return sub(r'\s{2,}|[\r\n]', '', render_template('blah.html'))... What makes minify special?Assume
@Sasili Syrakis - For the OP's use case I'm not sure there is anything that would constitute 'special', but it is comment-aware - allowing you to include or exclude comments from the minified HTML. It also comes with a convenience decorator, has a command line version for static html files and allows you to include or exclude files by path. *I haven't tried these features with Flask.Dinesen
A
1

Modifying @Bletch answer for the latest version of htmlmin.

from flask import Flask
import htmlmin

app = Flask(__name__)

@app.route('/')
def home():
    rendered_html = render_template('home.html')
    return htmlmin.minify(rendered_html)

https://htmlmin.readthedocs.io/en/latest/quickstart.html

The minified html will still have some spaces between the tags. If we want to remove that, then remove_empty_space =True attribute needs to be added while the template is rendered.

return htmlmin.minify(rendered_html, remove_empty_space =True)

https://htmlmin.readthedocs.io/en/latest/reference.html

Accusal answered 21/1, 2019 at 14:35 Comment(0)
R
0

In 2022, I have found better success using the minify-html package: https://github.com/wilsonzlin/minify-html

minify_html.minify(
    """
    html here
    """,
    minify_js=True, 
    minify_css=True,
    remove_processing_instructions=True,
)
Rightism answered 11/9, 2022 at 23:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.