The Grug Stack is a Hypermedia-Driven Application development environment that enables full-stack developers to develop cutting-edge applications without the complexity of modern Single Page Application development.
It consists of:
- A web framework backend like Django
- HTMX
- _hyperscript
- TailwindCSS
Some people prefer to substitute Alpine.js for _hyperscript. While technically different, they both occupy the same place in the Grug Stack. I'll teach how to install both.
If you just want to try the whole stack out fast, install Django (or your choice of backend frameworks) and then make
a base.html
template that looks like this:
<!DOCTYPE html>
<html lang="en">
<head>
<title>The Grug Stack</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<!-- HTMX library -->
<script src="https://unpkg.com/[email protected]"
integrity="sha384-cZuAZ+ZbwkNRnrKi05G/fjBX+azI9DNOkNYysZ0I/X5ZFgsmMiBXgDZof30F5ofc"
crossorigin="anonymous"></script>
<!-- Choose _hyperscript or Alpine.js -->
<!-- _hyperscript library -->
<script src="https://unpkg.com/[email protected]"></script>
<!-- Alpine.js library -->
<script defer src="https://unpkg.com/[email protected]/dist/cdn.min.js"></script>
<!-- TailwindCSS styles -->
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body>
{% block content %} {% endblock %}
</body>
</html>
You are now ready to develop the latest Hypermedia-Driven Applications.
However, if you want to make an environment that you can later use in production, follow the rest of this tutorial.
For the busy developer:
- Install software
pip install ...
- Follow their install and configuration procedures.
- django-tailwind provides a
base.html
template. Add the _hyperscript or Alpine.js scripts to the head of the HTML.
Your base.html
file should look like this when you're finished:
{% load static tailwind_tags %}
{% load static %}
{% load django_htmx %}
<!DOCTYPE html>
<html lang="en">
<head>
<title>Django Tailwind</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
{% tailwind_css %}
<!-- Choose _hyperscript or Alpine.js -->
<!-- _hyperscript library -->
<script src="https://unpkg.com/[email protected]"></script>
<!-- Alpine.js library -->
<script defer src="https://unpkg.com/[email protected]/dist/cdn.min.js"></script>
<script src="{% static 'core/htmx.min.js' %}" defer></script>
</head>
<body class="bg-gray-50 font-serif leading-normal tracking-normal">
<div class="container mx-auto">
<section class="flex items-center justify-center h-screen">
<h1 class="text-5xl">Django + Tailwind = ❤️</h1>
</section>
</div>
</body>
</html>
After installing everything via pip
, continue with the following:
python manage.py startapp core
Make a directory called static
in the core
app directory.
Make a directory called core
in the static
app directory (yes, really).
We'll use this directory later. Still more setup to do.
Make a directory called templates
in the core
app.
Make a directory called core
in the templates
folder (stop asking questions, grug).
We'll use this directory later. Still more setup to do.
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
+ 'core',
+ 'django_htmx',
+ 'tailwind',
+ 'widget_tweaks',
+ 'render_block',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
...
'django.middleware.clickjacking.XFrameOptionsMiddleware',
+ 'django_htmx.middleware.HtmxMiddleware',
]
- Download HTMX here
- Put it in the
core
app's static directory (you will put it incore/static/core/htmx.min.js
)
We're done with HTMX for now.
Run django-tailwind initialization script.
python manage.py tailwind init
Follow instructions. Use default name theme
for app.
INSTALLED_APPS = [
...,
'core',
'django_htmx',
'tailwind',
'widget_tweaks',
'render_block',
+ 'theme',
+ 'django_browser_reload',
]
+ TAILWIND_APP_NAME = 'theme'
+ INTERNAL_IPS = [ '127.0.0.1' ]
MIDDLEWARE = [
...,
'django_htmx.middleware.HtmxMiddleware',
+ 'django_browser_reload.middleware.BrowserReloadMiddleware',
]
python manage.py tailwind install
## contact/contact/urls.py
# Add 'include' to imports
from django.urls import include, path
urlpatterns = [
path('admin/', admin.site.urls),
path("__reload__/", include("django_browser_reload.urls")),
]
When we created the theme
app with python manage.py tailwind init
,
django-tailwind
very kindly provided us a base.html
file in the theme/templates
folder.
Let's edit it.
The default base.html
file provided by django-tailwind
looks like this:
{% load static tailwind_tags %}
<!DOCTYPE html>
<html lang="en">
<head>
<title>Django Tailwind</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
{% tailwind_css %}
</head>
<body class="bg-gray-50 font-serif leading-normal tracking-normal">
<div class="container mx-auto">
<section class="flex items-center justify-center h-screen">
<h1 class="text-5xl">Django + Tailwind = ❤️</h1>
</section>
</div>
</body>
</html>
We need to add HTMX and _hyperscript (or Alpine.js) to this file. Under {% load static tailwind_tags %}
, add two more
lines:
{% load static %}
{% load django_htmx %}
Inside <head>
, under {% tailwind_css %}
, add:
<script src="https://unpkg.com/[email protected]"></script>
<script src="{% static 'htmx.min.js' %}" defer></script>
This is the only install step for _hyperscript (or Alpine.js).
Your base.html
file should look like this:
{% load static tailwind_tags %}
{% load static %}
{% load django_htmx %}
<!DOCTYPE html>
<html lang="en">
<head>
<title>Django Tailwind</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
{% tailwind_css %}
<!-- Choose _hyperscript or Alpine.js -->
<!-- _hyperscript library -->
<script src="https://unpkg.com/[email protected]"></script>
<!-- Alpine.js library -->
<script defer src="https://unpkg.com/[email protected]/dist/cdn.min.js"></script>
<script src="{% static 'core/htmx.min.js' %}" defer></script>
</head>
<body class="bg-gray-50 font-serif leading-normal tracking-normal">
<div class="container mx-auto">
<section class="flex items-center justify-center h-screen">
<h1 class="text-5xl">Django + Tailwind = ❤️</h1>
</section>
</div>
</body>
</html>
Phew! Setup complete, grug brother.
You are now ready to start building your next Hypermedia-Driven Application
We didn't touch on why we installed django-widget-tweaks
and django-render-block
.
In a future guide you will see a practical example of how these are used and why they are part of the Grug Stack development environment. To put it simply:
django-widget-tweaks
lets us style Django forms in the template, rather than in theforms.py
file. That allows us to follow the principle of Locality of Behavior. It also makes using Tailwind much easier.django-render-block
similarly lets us include template fragments inside main template files, again allowing us to follow the principle of Locality of Behavior.
Because much of the action in a Hypermedia-Driven Application is in the hypermedia (i.e. HTML), it's important to install these two Django extensions to make working in Django templates easier.