How to use TailwindCSS in a Cookiecutter Django project
Tags: django, tailwindcss, tutorial, beginners
Published: 2021-02-17 08:52:14

### Motivation
[TailwindCSS](https://www.tailwind.css) has found a growing fan-base  among the developers who use Javascript frameworks such as React, GatsbyJS, Next.js.
But for the rest of us [Bootstrap](https://getbootstrap.com) has been a go to option for years. In fact [Cookiecutter Django](https://github.com/pydanny/cookiecutter-django)  configures Bootstrap out of the box for you.

Like many for a new project, I used Django Cookiecutter as my base, but this time I wanted to use those fancy styling from TailwindCSS in my project. After playing with the structure I managed to make it work the way I want it. As there was a lack of a proper tutorial on this, I felt this could be a  good subject to write about.

Below are the steps you should follow:

### 1. Generate your Django project with Cookiecutter
 
```
# install cookie-cutter
pip install "cookiecutter>=1.7.0"

# generate your project
cookiecutter https://github.com/pydanny/cookiecutter-django
```
You will be asked a few questions, you can find a good explanation of all in [Cookiecutter's docs](https://cookiecutter-django.readthedocs.io/en/latest/project-generation-options.html). If you don't know the answer, go with the provided default. ==Don't over analyze==.
 
### 2. Create a new folder structure for static files
In the root of your project create a folder called `frontend` and  under it, create the same subfolders as you see in your apps `static` folder like below:
```
frontend/
 css/
 fonts/
 images/
 js/
 scss/
```

From now on this will be the place in which you put your static files. You will see the reason for this shortly.

### 3. Upgrade your Node version
Tailwind works with `node` version `12` above. What worked for me without much problems was version `14`. Make sure you are upgrading your local version to `14` or if you are using Docker, change the version in the `compose/local/node/Dockerfile`. Your `Dockerfile` should look something like the following:
```
FROM node:14-stretch-slim

WORKDIR /app

COPY ./package.json /app

RUN npm install && npm cache clean --force

ENV PATH ./node_modules/.bin/:$PATH

```


==Still with me?==

### 4. Add the necessary dependencies to your `package.json` file
First add the following to `dependencies` in `package.json`. You don't need to use any dependency managers like `npm` or `yarn` at this stage. Just make sure you insert the following dependencies in the right version in the right place. To avoid conflicts, I suggested that you first start with the exact same dependencies mentioned below, make everything work and add other dependencies as you go:
```
  "dependencies": {
    "html-loader": "^1.3.2",
    "html-webpack-plugin": "^4.5.1",
  },
  "devDependencies": {
    "autoprefixer": "^10.2.4",
    "clean-webpack-plugin": "^3.0.0",
    "copy-webpack-plugin": "^7.0.0",
    "css-loader": "^5.0.2",
    "dotenv-webpack": "^6.0.0",
    "file-loader": "^6.2.0",
    "mini-css-extract-plugin": "^1.3.6",
    "node-sass": "^5.0.0",
    "postcss": "^8.2.6",
    "postcss-loader": "^5.0.0",
    "purgecss-webpack-plugin": "^4.0.0",
    "sass-loader": "^11.0.1",
    "tailwindcss": "^2.0.3",
    "webpack": "^5.19.0",
    "webpack-cli": "^4.4.0",
    "webpack-dev-server": "^3.11.2"
  }
```

NOTE 1: It is important to know that TailwindCSS relies on `PostCSS 8` and above. If are using packages different from the above, you need to make sure that there is no other dependency in your `package.json` that depends on `PostCSS` lower than version 8. To do the inspection use `npm list` or if you use yarn `yarn list`. 

NOTE 2: Make sure there is no packages in your `package.json` that is related to `Bootstrap`

**If you are already lost, just copy my config file from here: [package.json](https://gist.github.com/hossein761/0b2c3e366007f49980bd17e9ce20de8a) and jump to step 7.**


### 6.Replace Gulp with Webpack
As you saw in the previous step, we are introducing [Webpack](https://webpack.js.org) in the dependencies. This means that you need remove anything related to Gulp from your `package.json` file. Remove `gulp-*` dependencies and adjust the `scripts` section to look like below:
```
"scripts": {
    "start": "webpack serve --mode development",
    "build": "webpack --mode production"
}
```

==Don't fall sleep yet!==

### 7. Glue everything together with Webpack
As you saw we created a separate folder structure called `frontend` in which we are going to put our static files. 
Now you might ask isn't the default `static` folder for this? It is a legit question, it actually is, however instead of we manually put our `js`, `scss`, etc files in there, Webpack will do this for us.

It simply reads everything in the `frontend` folder, does whatever magic is needed on those files such as optimization, post-processing, etc and put the results in the static folder for us so that Django can use them.

For this we create a Webpack configuration file called `webpack.config.js`. We tell Webpack where to start `entry`, where to find our static files and what to do with each of them  based on their type `rules` and `plugins`. Explaining out Webpack works is outside the scope of this tutorial. You can copy my configurations directly from here: [webpack.config.js](https://gist.github.com/hossein761/0b2c3e366007f49980bd17e9ce20de8a)

### 8. Add static files to your `frontend` folder
Now you need to create the necessary files in your `frontend` subfolder.
First, in the `scss` subfolder, create a file called `app.scss` and include the following:
```
@tailwind base;
@tailwind components;
@tailwind utilities;
```
This will serve as the main file for the `styles`. Webpack does its magic on it and converts it to a proper css file called `app.css` which you need to include in your `base.html` Django template.

Next, in the `js` subfolder, create a file called `app.js` and include the following as the first line:
```
import '../scss/app.scss';
```
This file serves as the entry point for Webpack. If you see the `entry` in the `webpack.config.js` file you can see that it points to this file. Webpack reads this file and sees that it should process a `.scss` file and does its magic based on what you've configured in the config file.

Finally, don't leave the `fonts` and `images` folder empty. My Webpack configs are not optimized to handle empty folders.

### 9. Delete your existing static folder
Make sure you've moved whatever file you want to `frontend`. Then remove the `static` folder as it will be generated by Webpack upon build. As a bonus add this folder (`static`) to your `.gitignore` file.

### 10. Add PostCSS config file
As mentioned above, TailwindCSS needs PostCSS. You'll need to add a file called `postcss.config.js` with the following content to the root of your project:
```
module.exports = {
  plugins: {
    tailwindcss: {},
    autoprefixer: {},
  }
}
```

### 11. Add TailwindCSS config file
You can configure TailwindCSS the way you want it. However, to do this you need to create a file called `tailwind.config.js` in the root folder of your project and include the following:
```
// tailwind.config.js
module.exports = {
  purge: [],
  darkMode: false, // or 'media' or 'class'
  theme: {
    extend: {},
  },
  variants: {
    extend: {},
  },
  plugins: [],
}
```
You can read TailwindCSS documentation for more on this.

==Still Awake?!==

Now double check everything and if you use docker,first build the container using:
```
docker-compose -f local.yml build node
```
Then bring up the `node` container:
```
docker-compose -f local.yml up node
```


If everything is worked as planned, you should see the `static` folder generated for you include all the processed files from in your `frontend` folder. Now make sure you are using `app.css` and `app.js` in your `base.html` template file.

This article is originally posted on my [Boring Backend Newsletter](https://www.boringbackend.dev).

If you have any comments, or need help please do reach out to me on [Twitter](http://twitter.com/hossein761). And if this post helped you please don't forget to share it.