Skip to main content

Utility functions to help with the development of FastHTML applications.

Project description

FastHTML Developer Utils

Quick Start

Here’s how to use TailwindCSS v4 to style your FastHTML app, with a live-reload build step. For other fh-dev-utils features please refer to the following sections.

Install the fh-dev-utils package in your Python environment.

pip install fh-dev-utils

Clone the fh-dev-utils-examples repo and navigate to one of the example folders:

git clone https://github.com/ExploringML/fh-dev-utils-examples.git
cd fh-dev-utils-examples/tailwind-basic

Run the FastHTML app inside an example folder and view it in the browser with the url http://localhost:5001.

python main.py

Check out the other FastHTML examples in the fh-dev-utils-example repo.

Why fh-dev-utils?

Here’s a brief outline of the benefits of using fh-dev-utils.

  1. Super-easy to build Tailwind styles dynamically.
  2. Compatible with TailwindCSS v4.
  3. Cache buster to always load latest styles during development.
  4. Run a Jupyter notebook server alongside your FastHTML app.
  5. Database browser to easily view/manage your apps db tables and records.
  6. TailwindCSS intellisense for a great developer experience!

Tailwind officially advises to use a build step to compile styles rather than adding the static CSS file via a CDN. A huge benefit of a build step is enabling intellisense support.

Using intellisense to view inline color information at a glance, see a list of all available Tailwind classes, and hover over any Tailwind class to view compiled CSS, is a game-changer!

A complete list of the benefits of compiling TailwindCSS styles can be found here.

Introduction

The fh-dev-utils package helps during the devlopment of FastHTML applications by adding support for live TailwindCSS build, a Jupyter notebook server, and an SQLite viewer/manager via the serve_dev() function.

There is also a cache_buster() function available to help prevent caching of CSS styles during development.

See here for the full definition of serve_dev() and cache_buster() plus all available parameters.

Usage

Install the fh-dev-utils package from PyPi.

$ pip install fh-dev-utils

Then import the fh_dev_utils package inside your FastHTML application.

main.py

from fasthtml.common import *
from fh_dev_utils.serve import *

app,rt = fast_app(live=True)

@rt('/')
def get(): return Div(P('Hello World!'))

#serve()
serve_dev()

Replace the default serve() function with serve_dev(). This performs the same functionality as serve() but includes a few additional enhancements, which make developing FastHTML applications a little easier.

Currently serve_dev() offers three main features.

  1. TailwindCSS styles dynamic build process
  2. Jupyter notebook server
  3. SQLite database browser

Note: If you use serve_dev() without any options then it performs the exact same function as serve().

1. TailwindCSS Dynamic Build

Uses the TailwindCSS CLI to dynamically build styles as you edit your apps source code.

Benefits include:

  • Smaller CSS files size (only build what you have defined)
  • Recommended best practice from the authors of TailwindCSS:
    • The [Play] CDN is designed for development purposes only, and is not intended for production.

  • Use dynamic selectors such as mb-[34px]
  • TailwindCSS intellisense support
  • Custom configuration (e.g. plugins, and custom themes)
serve_dev(tw=True)

When you start a FastHTML app with the tw parameter enabled you’ll see an additional link to open Jupyter Lab. By default the source TailwindCSS file is assumed to be located in ./app.css and the output is saved to ./public/app.css. Both these paths can be configured by the tw_src and tw_dist parameters respectively.

$ python main.py
Watching for Tailwind class changes...
Link: http://localhost:5001
INFO:     Will watch for changes in these directories: ['/home/david/fh-dev-utils-test']
INFO:     Uvicorn running on http://0.0.0.0:5001 (Press CTRL+C to quit)
INFO:     Started reloader process [1951725] using WatchFiles
INFO:     Started server process [1951759]
INFO:     Waiting for application startup.
INFO:     Application startup complete.

TailwindCSS Setup

The serve_dev(tw=True) function runs the TailwindCSS CLI to watch for class name changes but you need to setup your FastHTML to be Tailwind ‘compatible’. This means adding a Tailwind source CSS file and a config file.

In the root of your FastTML project add an app.css file:

@import "tailwindcss";

This is for TailwindCSS v4. If you’re using an older version then use this format instead:

@tailwind base;
@tailwind components;
@tailwind utilities;

If your Tailwind CSS file is named something other then app.css or is in a different location then you can use the tw_src parameter in serve_dev() to change the name/path as required.

The last thing to do is add the generated Tailwind CSS file to the header of your FastHTML site.

app,rt,todos,ToDo = fast_app(
    pico=False,
    live=True,
    hdrs=(
        Link(rel="stylesheet", href=f"/public/app.css{cache_buster() if DEV_MODE else ""}", type="text/css"),
    ),
)

This will add the necessary styles and will also bypass the browser CSS cache via the fh-dev-utils cache_buster() function.

Tailwind Intellisense

One of the advantages to building TailwindCSS styles dynamically is that it enables support for auto-completion (intellisense) of Tailwind classes as you type.

To get this working you need to be using VS Code and install the Tailwind CSS IntelliSense extension.

You’ll also need to edit the TailwindCSS VS Code settings so that intellisense is auto-triggered as you edit your FastHTML app source code. These extra rules are needed so that Tailwind CSS classes can be detected in any part of your Python code.

Open the JSON user settings in VS Code and add the following settings to the existing ones:

 {
  "tailwindCSS.includeLanguages": {"python": "html"},
  "tailwindCSS.experimental.classRegex": ["['\"]([^'\"]*)['\"]"],
}

Once this is set up then you get full intellisense support.

Plus, all colors are highlighted inline too, and you can hover over the Tailwind class to see what the computed CSS will be when rendered!

Tailwind Class Reordering

There is a recommended order for Tailwind classes inside a string. The official solution is to use a Prettier plugin but you can also sort classes in VS Code if you have the Tailwind CSS Intellisense plugin installed.

Simply select a Tailwind class string that contains multiple classes and press CTRL+Shift+P (Windows) to open the command pallete. Start typing ‘Tailwind…’ until you see the ‘Tailwind CSS: Sort Selection’ command.

Select it and press Enter, or click on it. This will sort the selected Tailwind classes into the recommended order.

Troubleshooting

If you don’t see a little color swatch next to the Tailwind color classes then intellisense isn’t working. This is usually because the TailwindCSS CLI is not running, or you don’t have a tailwind.config.js added to the root of your FastHTML app.

Also, if you are using Linux under Windows (WSL) then make sure the Tailwind CSS Intellisense VS Code extension is enabled for WSL.

2. Jupyter Notebook Server

It is often really useful to add one or more notebooks to your FastHTML to enable quick exploration or research when developing you app. Use it to test things out or as a scratch pad to try out ideas. You can then transfer any code you want to incorporate into the FastHTML app.

The serve_dev() function makes this super-easy. Simply set the jupyter argument to True:

serve_dev(jupyter=True)

When you start a FastHTML app with the jupyter parameter enabled you’ll see an additional link to open Jupyter Lab. By default port 8036 will be used for the Jupyter lab server but this can be changed via the jupyter_port parameter.

$ python main.py
Jupyter Lab link: http://localhost:8036/lab
Link: http://localhost:5001
INFO:     Will watch for changes in these directories: ['/home/david/fh-dev-utils-test']
INFO:     Uvicorn running on http://0.0.0.0:5001 (Press CTRL+C to quit)
INFO:     Started reloader process [1951725] using WatchFiles
INFO:     Started server process [1951759]
INFO:     Waiting for application startup.
INFO:     Application startup complete.

This will give you access to a full Jupyter Lab server that runs along side your FastHTML app.

A particularly useful way to use a notebook to complement your FastHTML app is to view the schema for an SQLite database (only relevant if your app includes a database).

Note: The fastlite diagram() function requires graphviz to be installed.

3. SQLite Database Browser

When working with an SQLite database in your FastHTML app it is often useful to be able to easily view/edit database data. You can also do this manually via a Jupyter Lab notebook too but it is very convenient to have a dedicated app to be able to interect with your database.

We have included support for the sqlite-web browser which is written in Python.

serve_dev(db=True)

When you start a FastHTML app with the db parameter enabled you’ll see an additional link to open sqlite-web database browser. By default port 8035 will be used for the SQLite browser but this can be changed via the sqlite_port parameter. The database file can be configured via db_path. By default it is set to ./data/app.db.

$ python main.py
SQLite link: http://localhost:8035
Link: http://localhost:5001
INFO:     Will watch for changes in these directories: ['/home/david/fh-dev-utils-test']
INFO:     Uvicorn running on http://0.0.0.0:5001 (Press CTRL+C to quit)
INFO:     Started reloader process [1988346] using WatchFiles
INFO:     Started server process [1988418]
INFO:     Waiting for application startup.
INFO:     Application startup complete.

This will give you access to a full sqlite-web database server that runs along side your FastHTML app.

Enabling All Options

If you enable TailwindCSS file watching, Jupyter Lab server, and sqlite-web database browser altogether then the console output will look like this when you first start a FastHTML app.

$ python main.py
Watching for Tailwind class changes...
SQLite link: http://localhost:8035
Jupyter Lab link: http://localhost:8036/lab
Link: http://localhost:5001
INFO:     Will watch for changes in these directories: ['/home/david/fh-dev-utils-test']
INFO:     Uvicorn running on http://0.0.0.0:5001 (Press CTRL+C to quit)
INFO:     Started reloader process [1988346] using WatchFiles
INFO:     Started server process [1988418]
INFO:     Waiting for application startup.
INFO:     Application startup complete.

All links are placed next to each other for convenience making it easy to select which server (FastHTML, Jupyter, or sqlite-web) you want to open in the browser.

Example FastHTML Apps

Here are a couple of examples of full minimal FastHTML apps that implement the fh-dev-utils package to make development easier. This section is mainly to show the code. If you want to run the examples apps then take a look at the fh-dev-utils-examples repo for installation details.

In both the code examples below a DEV_MODE variable is used to easily switch between development and production. When DEV_MODE is enabled it uses CSS browser cache busting, and uses the serve_dev() function. Otherwise, in production, the CSS is cached and the FastHTML serve() function is used.

This first one is very simple and doesn’t include a database:

from fasthtml.common import *
from fh_dev_utils.serve import *

DEV_MODE=True

app,rt = fast_app(
    pico=False,
    live=True,
    hdrs=(
        Link(rel="stylesheet", href=f"/public/app.css{cache_buster() if DEV_MODE else ''}", type="text/css"),
    )
)

@rt('/')
def get():
    return Div(
        P('Hello World!', cls="text-[#bada55] bg-gradient-to-r from-blue-400 to-purple-600 p-4 rounded-lg shadow-lg"),
        P('Blue Background', cls="bg-blue-500 text-white p-2 round"),
        P('Gradient Text', cls="bg-gradient-to-r from-pink-500 to-yellow-500 text-transparent bg-clip-text p-6"),
        cls="m-[41px] space-y-4"
    )

if DEV_MODE: serve_dev(tw=True, jupyter=True)
else: serve()

And here’s one that includes an SQLite database.

from fasthtml.common import *
from fh_dev_utils.serve import *

DEV_MODE=True

app,rt,todos,ToDo = fast_app('data/todos.db', id=int, title=str, pk='id', pico=True, live=True)

if not todos(): # Seed database if empty
    todos.insert_all([
        {"title": "Buy groceries"},
        {"title": "Finish blog post"},
        {"title": "Reply to emails"},
        {"title": "Plan weekend trip"},
        {"title": "Read AI research paper"}
    ]
)

def TodoRow(todo): return Li(todo.title, href=f'/todos/{todo.id}', id=f'todo-{todo.id}')

def home():
    add = Form(
            Group(
                Input(name="title", placeholder="New Todo"),
                Button("Add")
            ), action="/", method='post'
        )
    card = Card(
                Ul(*map(TodoRow, todos()), id='todo-list', style="padding:20px;"),
                header=add,
                footer=Div(id='current-todo')
            )
    return Titled('Todo list', card)

@rt("/")
def get(): return home()

@rt("/")
def post(todo:ToDo):
    todos.insert(todo)
    return home()

if DEV_MODE: serve_dev(db=True, db_path='data/todos.db')
else: serve()

This is a very minimal database app just as an illustrative example of using serve_dev() to spin up a database browser. You can only add and view todo items. However, using sqlite-web you can browse the database and add/edit/remove items very easily!

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

fh_dev_utils-0.0.4.tar.gz (14.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

fh_dev_utils-0.0.4-py3-none-any.whl (12.9 kB view details)

Uploaded Python 3

File details

Details for the file fh_dev_utils-0.0.4.tar.gz.

File metadata

  • Download URL: fh_dev_utils-0.0.4.tar.gz
  • Upload date:
  • Size: 14.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.5

File hashes

Hashes for fh_dev_utils-0.0.4.tar.gz
Algorithm Hash digest
SHA256 a24b4200a2cf6c6f283d30748514ada56708cd4082a9fde189367ba446c8e1bf
MD5 cf7d6d6b176ee6a68f105b070cbb9a7f
BLAKE2b-256 f2cca5dd3b09eae7eea68d101569f3ea4dc1996904815f845b6ddd39bb4a71ee

See more details on using hashes here.

File details

Details for the file fh_dev_utils-0.0.4-py3-none-any.whl.

File metadata

  • Download URL: fh_dev_utils-0.0.4-py3-none-any.whl
  • Upload date:
  • Size: 12.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.5

File hashes

Hashes for fh_dev_utils-0.0.4-py3-none-any.whl
Algorithm Hash digest
SHA256 98a40d9289a6631991be02c1bc62ee895b64aab434469a24dc9971ec425f011a
MD5 919b25df9a464fae3a30ba5031d2810d
BLAKE2b-256 5688a50cf8eaa72dc65f7419fb7777f25a0a7009ef9e9f7c1cb730f2fec6731b

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page