Flask + TailwindCSS + Flask Assets
Tags: python, flask, tailwindcss
Published: 2021-07-10 12:53:42

Continuing from the previous article "Getting Started with Flask", creating a website always requires assets, such as CSS and javascript files. To manage those files within a Flask application is easy… you just need to use Flask-Assets package. Wanna know how to do it? Let's roll.
As always, this article is made based on assumption that you create your project using PyCharm.

## Installation

### Installing Flask-Assets

First, you need to install Flask-Assets in your virtual environment with the syntax below. That's it!
```bat
pip install Flask-Assets
```

### Installing TailwindCSS

Next, we're going to install TailwindCSS:
```bat
npm install tailwindcss postcss postcss-cli autoprefixer @fullhuman/postcss-purgecss
```
In order to set up Tailwind within our project, we need to create a file `tailwind.config.js` by running this inside terminal.
```bat
npx tailwind init
```
Next, you need to add `postcss.config.js` and insert this code below:
```javascript
// postcss.config.js

const path = require('path');

module.exports = (ctx) => ({
  plugins: [
    require('tailwindcss')(path.resolve(__dirname, 'tailwind.config.js')),
    require('autoprefixer'),
    process.env.FLASK_PROD === 'production' && require('@fullhuman/postcss-purgecss')({
      content: [
        path.resolve(__dirname, 'templates/**/*.html')
      ],
      defaultExtractor: content => content.match(/[A-Za-z0-9-_:/]+/g) || []
    })
  ],
});
```
Then, add the following code into `static/src/main.css`:
```css
/* static/src/main.css */

@tailwind base;
@tailwind components;
@tailwind utilities;
```
Here, we defined all base, components, and utilities classes from Tailwind CSS. PostCSS will build all the classes into the target location, `static/dist/main.css`. You don’t need to create the file `static/dist/main.css` since this file will be automatically generated when you run the application.

The next thing to do is to import flask-assets into app.py and use Bundle and Environment constructor to bundle and register all css/js files. You can see the implementation below.
```python
# app.py

from flask import Flask
from flask_assets import Bundle, Environment

app = Flask(__name__)

# Bundling src/main.css files into dist/main.css'
css = Bundle('src/main.css', output='dist/main.css', filters='postcss')

assets = Environment(app)
assets.register('main_css', css)
css.build()
```

Finally, you can run the app to see whether `static/dist/main.css` is generated properly. If not and if you get an error like this:
```bat
Program file not found: postcss
``` 
then try installing PostCSS globally: 
```bat
npm install --global postcss postcss-cli
```

## Using TailwindCSS within HTML

Since everything has been done properly, now it’s time to use Tailwind inside our template files. Let’s create a new template file called base.html and inside that file we put:
```jinja
<!-- templates/base.html -->

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    {% assets 'main_css' %}
      <link rel="stylesheet" href="{{ ASSET_URL }}">
    {% endassets %}

    <title>Flask + TailwindCSS + Flask-Assets</title>
  </head>
  <body class="bg-blue-100">
    {% block content %}
    {% endblock content %}
  </body>
</html>
```
There are several new codes that is different from before which is:
```jinja
{% assets 'main_css' %}
  <link rel="stylesheet" href="{{ ASSET_URL }}">
{% endassets %}
```

In this code, main_css is the name of the CSS bundle that has been registered using flask-assets. That’s all that we need to pay attention to. The rest of the syntax can be left as default.

After that, all CSS classes own by Tailwind can be used inside the HTML file like this one:
```jinja
<body class="bg-green-100">
    <div>About Page</div>
</body>
```
## What About Any JS Files?

The same principles can used for JS… you just need to bundle them up, register it as assets, and then call it inside the HTML page.

Have fun trying…