Use libsass in flask

Example code on integrating libsass into flask

So my purpose is to build a tiny site with Flask, and want to use Sass for style sheet.

What I could found from (the first page of) google mostly goes to flask-scss packages. But this package is still in a version number of 0.5, which looks like still under development, and have been updated for 7 years (last commit in 2015). Some of them uses flask-assets, but still not looks like a stable solution.

Fortunately, libsass-python now having official support on this: Using with Flask.

So this article is for the experience on integrating libsass into flask. I'm writing this article based on Flask 2.0.2 and libsass 0.21.0.

Building Sass on request

libsass-python natively comes with the package sassutils. And I'm having a folder with following layout:

Folder layout

|- static
|  |- sass
|     |- main.scss
|- app.py

Sample app

Now add SassMiddleware the wsgi middleware to the site app:

import flask
import sassutils.wsgi
app = flask.Flask(__name__)
app.wsgi_app = sassutils.wsgi.SassMiddleware(
app.wsgi_app,
{
"app": {
"sass_path": "static/sass",
"css_path": "static/css",
"wsgi_path": "style",
"strip_extension": True,
}
},
)

Note it's using a strange layout to clearify the behavior. It comes with some pitfall, would be addressed below.

On official doc, it suggests a simpler format for manifest. But that one raises FutureWarning. So adding strip_extension to address this.

Mainfest

Here's the detail on each parameters in mainfest:

  • sass_path Path for the folder that contains source Sass/SCSS files

    This is the only required parameter.

  • css_path Path to store the generated output

    We don't need to create it first. During request, libsass compile the code from sass_path than put it to css_path. So we could see the output appears at static/css/main.css after any request.

    If we do not specific it, that the data would be saved to sass_path. I do not want to mix generated data with source code, so strongly recommand to use it.

  • wsgi_path Overriding prefix to get compiled data on routing

    By specificing this, we would be avaliable to get the compiled stylesheet with /style/main.css.

    If we do not specific it, it uses css_path. Then we should get it from /static/css/main.css.

  • strip_extension Remove original file extension or not

    When set to False (default value), libsass only append .css to original file name. So main.scss now become main.scss.css.

    And if we enabling this, they would remove the extension, so we could get main.css.

On using this config, it generates data to static/css and we could reach the output via:

curl http://localhost:5000/style/main.css

Template

A simple way could be directly specific the path:

<link href="/style/main.css" rel="stylesheet" type="text/css">

But be careful, it is not suggested to use SassMiddleware for production. You should compile it into static files and serving it with other server.

So using url_for might be better. But:

<link href="{{ url_for('static', filename='/style/main.css') }}" rel="stylesheet" type="text/css">
# above template code generates
<link href="/static/style/main.css" rel="stylesheet" type="text/css">

Flask prepends static/ prefix to the filename. So it is not feasible to use the provided config. We could solve this by removing wsgi_path parameters, or set it to a string with static/ prefix.

(Building for deployment)

Not trying yet. Not sure if I remember to fill this in the futrue.