Skip to content

Commit 4ad3334

Browse files
Stack update: Django 5.1, Tailwind/Webpack/Jest fixes, validation (#69)
## Summary Updates the boilerplate stack and fixes build/test validation for both backend and frontend. ## Backend - **Django** bumped to `^5.1` (pyproject.toml + poetry.lock). - Removed deprecated **`USE_L10N`** from `core/settings/base.py` (invalid in Django 5+). - Updated settings docstrings to current stable docs URLs. - Set **`DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"`** to clear `models.W042` warnings. ## Frontend - **Tailwind**: content paths now include `.tsx` and `lib/**/*.{js,jsx,ts,tsx}` so utilities used in React components are not purged. - **Webpack**: replaced `file-loader` with built-in `asset/resource` (output under `assets/[name][ext]`). - **Jest**: added `jest`, `ts-jest`, `jest-environment-jsdom`, `@types/jest` and `frontend/jest.config.js`; test script uses `--passWithNoTests` so CI passes when there are no tests yet. - **TypeScript**: fixed TS7011 in `lib/api/use-api.ts` by adding explicit return types to `.catch()` callbacks and `emptyPaginatedResponse` for the paginated error fallback. ## Docs - **`docs/STACK_ANALYSIS_AND_UPDATES.md`**: analysis of current vs latest versions (Django 6, React 19, Tailwind v4), deprecated/unnecessary deps, and notes on Tailwind as the default AI-friendly design system. ## README - Stack table updated to "Django 5.1+"; typo fix ("non-opinionated"). ## Validation - `poetry run python manage.py check` ✅ - `ruff check` ✅ - `TEST=1 poetry run python manage.py test` ✅ - `pnpm run test:static` ✅ - `pnpm run build` ✅ - `pnpm run test` ✅
2 parents e512919 + 1d25c9a commit 4ad3334

File tree

15 files changed

+8710
-5166
lines changed

15 files changed

+8710
-5166
lines changed

.github/workflows/build-and-test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ jobs:
5252
run: |
5353
python -m pip install --upgrade pip
5454
pip install poetry
55-
poetry install --no-dev
55+
poetry install --only main
5656
- name: Run Tests
5757
env:
5858
TEST: 1

.github/workflows/deploy-bare-metal.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ jobs:
5151
run: |
5252
python -m pip install --upgrade pip
5353
pip install poetry
54-
poetry install --no-dev
54+
poetry install --only main
5555
- name: Run Tests
5656
env:
5757
TEST: 1
@@ -123,7 +123,7 @@ jobs:
123123
cd app
124124
python3 -m pip install --upgrade pip
125125
pip install poetry
126-
poetry install --no-dev
126+
poetry install --only main
127127
echo -e "~~~~~~~~~~~~~~~~~~~~~~~~ Installed python requirements successfully ~~~~~~~~~~~~~~~~~~~~~~~~\n"
128128
129129
poetry run python3 manage.py migrate

.github/workflows/deploy-vm.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ jobs:
6060
run: |
6161
python -m pip install --upgrade pip
6262
pip install poetry
63-
poetry install --no-dev
63+
poetry install --only main
6464
- name: Run Tests
6565
env:
6666
TEST: 1
@@ -76,7 +76,7 @@ jobs:
7676
- uses: actions/checkout@v4
7777
- name: Run tests
7878
run: |
79-
docker build . --build-arg AUTH_TOKEN=${{ secrets.AUTH_KEY }}--build-arg ALLOWED_HOSTS=${{ secrets.ALLOWED_HOSTS }} --file Dockerfile
79+
docker build . --build-arg AUTH_TOKEN=${{ secrets.AUTH_KEY }} --build-arg ALLOWED_HOSTS=${{ secrets.ALLOWED_HOSTS }} --file Dockerfile
8080
8181
# Push image to GitHub Packages.
8282
# See also https://docs.docker.com/docker-hub/builds/

Dockerfile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ RUN cd frontend \
1212
&& pnpm run build
1313

1414
# Build backend
15-
FROM python:3.12-rc-slim-buster
15+
FROM python:3.12-slim-bookworm
1616
WORKDIR /usr/src/app
1717
ARG ALLOWED_HOSTS
1818
ENV ALLOWED_HOSTS $ALLOWED_HOSTS
@@ -26,4 +26,4 @@ RUN pip install --upgrade pip
2626
RUN pip install poetry
2727
COPY ./pyproject.toml /usr/src/app/pyproject.toml
2828
COPY ./poetry.lock /usr/src/app/poetry.lock
29-
RUN poetry install --no-dev
29+
RUN poetry install --only main

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
<img alt="django-react-typescript logo" src="assets/Logo.png" align="right" width="120" height="120" />
44

5-
This is an non-opinionated Django 5 + React 18 boilerplate built with great development experience and easy deployment in mind.
5+
This is a non-opinionated Django 5 + React 18 boilerplate built with great development experience and easy deployment in mind.
66

77
This template is ideal if you want to bootstrap a blog or a portfolio website quickly, or even a more complex application that requires a CMS, all while leveraging the best from React and Django.
88

@@ -90,7 +90,7 @@ Below you will find the stack used for each part of the application and the feat
9090
| Stack | Libraries and services | Features |
9191
| ---------- | ----------------------------------------------------------------- | -------------------------------- |
9292
| Frontend | React 18, React Router 6, Typescript 5, Webpack 5, Tailwind CSS 3 | Publication listing and search |
93-
| Backend | Django 5, Django Rest Framework | Publication CRUD, API Key CRUD |
93+
| Backend | Django 5.1+, Django Rest Framework | Publication CRUD, API Key CRUD |
9494
| Database | Postgres | - |
9595
| CDN | Cloudinary | - |
9696
| CI/CD | GitHub Actions | Multiple deploy workflow options |

core/settings/base.py

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,8 @@
11
"""
2-
Django settings for es project.
2+
Django settings for this project.
33
4-
Generated by 'django-admin startproject' using Django 3.0.7.
5-
6-
For more information on this file, see
7-
https://docs.djangoproject.com/en/3.0/topics/settings/
8-
9-
For the full list of settings and their values, see
10-
https://docs.djangoproject.com/en/3.0/ref/settings/
4+
See https://docs.djangoproject.com/en/stable/topics/settings/
5+
and https://docs.djangoproject.com/en/stable/ref/settings/
116
"""
127

138
import os
@@ -54,7 +49,7 @@
5449

5550

5651
# Quick-start development settings - unsuitable for production
57-
# See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/
52+
# See https://docs.djangoproject.com/en/stable/howto/deployment/checklist/
5853

5954
# SECURITY WARNING: keep the secret key used in production secret!
6055
SECRET_KEY = os.environ.get(
@@ -97,6 +92,8 @@
9792

9893
ROOT_URLCONF = "core.urls"
9994

95+
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
96+
10097
TEMPLATES = [
10198
{
10299
"BACKEND": "django.template.backends.django.DjangoTemplates",
@@ -117,7 +114,7 @@
117114

118115

119116
# Database
120-
# https://docs.djangoproject.com/en/3.0/ref/settings/#databases
117+
# https://docs.djangoproject.com/en/stable/ref/settings/#databases
121118

122119
if os.getenv("TEST"):
123120
DATABASES = {
@@ -140,7 +137,7 @@
140137

141138

142139
# Password validation
143-
# https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators
140+
# https://docs.djangoproject.com/en/stable/ref/settings/#auth-password-validators
144141

145142
AUTH_PASSWORD_VALIDATORS = [
146143
{
@@ -159,21 +156,19 @@
159156

160157

161158
# Internationalization
162-
# https://docs.djangoproject.com/en/3.0/topics/i18n/
159+
# https://docs.djangoproject.com/en/stable/topics/i18n/
163160

164161
LANGUAGE_CODE = "en"
165162

166163
TIME_ZONE = "America/New_York"
167164

168165
USE_I18N = True
169166

170-
USE_L10N = True
171-
172167
USE_TZ = True
173168

174169

175170
# Static files (CSS, JavaScript, Images)
176-
# https://docs.djangoproject.com/en/3.0/howto/static-files/
171+
# https://docs.djangoproject.com/en/stable/howto/static-files/
177172

178173
STATIC_URL = "/static/"
179174
STATIC_ROOT = os.path.join(BASE_DIR, "static/")
@@ -184,7 +179,7 @@
184179
config(cloud_name=CDN_NAME, api_key=CDN_API_KEY, api_secret=CDN_API_SECRET, secure=True)
185180

186181
# Email
187-
# https://docs.djangoproject.com/en/3.0/topics/email/
182+
# https://docs.djangoproject.com/en/stable/topics/email/
188183

189184
# Gmail SMTP requirements
190185
# https://support.google.com/a/answer/176600?hl=en

docs/STACK_ANALYSIS_AND_UPDATES.md

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
# Stack analysis and update recommendations
2+
3+
Analysis date: February 2025. See also the changes already applied in this branch (Django 5.1, USE_L10N removed, Tailwind content paths fixed, Webpack asset modules, Jest added). This document summarizes the current boilerplate stack, latest versions, and concrete steps to modernize and align with the “AI-friendly” reality (e.g. Tailwind-first, widely known tooling).
4+
5+
---
6+
7+
## 1. Django
8+
9+
### Current
10+
- **pyproject.toml**: `django = "^5.0.6"`
11+
- **Python**: `^3.12`
12+
- **Settings**: `core/settings/base.py` still references Django 3.0 in docstrings and uses **deprecated `USE_L10N`** (deprecated in 4.0, removed in 5.0 — has no effect; locale formatting is always on).
13+
14+
### Latest
15+
- **Django 6.0** is the current stable (e.g. 6.0.2 on PyPI). Requires Python ≥ 3.12.
16+
- **Django 5.1** is the latest 5.x LTS-friendly line.
17+
18+
### How to leverage the latest Django
19+
20+
1. **Upgrade version**
21+
- For latest features and Python 3.12+ only: `django = "^6.0"` (or `"^5.1"` for a conservative jump).
22+
- Run tests and `python manage.py check` after upgrading.
23+
24+
2. **Remove deprecated setting**
25+
- In `core/settings/base.py`, **remove** `USE_L10N = True` (no longer valid in Django 5+).
26+
27+
3. **Update settings docstrings**
28+
- Replace Django 3.0 references in `base.py` with the actual version (e.g. 5.0 / 6.0) and current docs URLs.
29+
30+
4. **Optional Django 5/6 features you can adopt**
31+
- **Database-computed defaults**: `Field.db_default` for DB-level defaults.
32+
- **GeneratedField**: DB-generated columns from expressions.
33+
- **Form field groups**: `{{ form.field.as_field_group }}` in templates.
34+
- **Async**: `async` views, `aget_object_or_404`, async auth helpers if you move to async views.
35+
36+
---
37+
38+
## 2. React and frontend build
39+
40+
### Current
41+
- **React**: `^18.3.1`
42+
- **Build**: Webpack 5, TypeScript 5, Babel for React.
43+
- **Frontend entry**: `index.tsx`; components are **`.tsx`** under `lib/`.
44+
45+
### Latest
46+
- **React 19** is current (e.g. 19.2.4). React 18 remains supported.
47+
48+
### Recommendations
49+
- **React 19**: Upgrade to `react@^19` and `react-dom@^19` when ready; update `@types/react` and `@types/react-dom` to versions that support React 19. Run the test suite and fix any type or behavior changes.
50+
- **Build**: Webpack 5 is still fine. Alternative for a future refresh: Vite (faster dev, simple config, very common and LLM-friendly).
51+
52+
---
53+
54+
## 3. Tailwind and “AI-friendly” design system
55+
56+
### Current
57+
- **Tailwind CSS**: `^3.4.4` (v3).
58+
- **Plugins**: `@tailwindcss/forms`, `@tailwindcss/typography`, **flowbite-react**.
59+
- **Config**: `frontend/tailwind.config.js`**content paths list only `*.js`**, but all React sources are **`.tsx`**. So Tailwind is **not** scanning your components; utility classes used only in TSX can be purged incorrectly. This is a **bug**.
60+
61+
### Does it come with Tailwind by default?
62+
**Yes.** The boilerplate is already Tailwind-based, which is a design system LLMs are highly proficient at. No change of design system is required for “AI reality.”
63+
64+
### Fixes and improvements
65+
66+
1. **Fix content paths (important)**
67+
- In `tailwind.config.js`, include TSX (and JS/JSX if any):
68+
- e.g. `"./lib/**/*.{js,jsx,ts,tsx}"`, `"./index.tsx"`, and keep `./templates/frontend/**/*.html` and `flowbite.content()`.
69+
70+
2. **Tailwind v4 (optional, larger change)**
71+
- Tailwind v4 is available (new engine, CSS-first config). Staying on v3 is fine for stability; v4 can be a follow-up migration.
72+
73+
3. **Flowbite**
74+
- Heavily used in this boilerplate (navbar, cards, buttons, inputs, spinner). Keep for now; if you want to reduce dependencies later, you could replace with headless components + Tailwind. Not required for “AI-friendly” — Tailwind itself is the main lever.
75+
76+
4. **Safelist**
77+
- The current safelist is broad. Once content paths include `.tsx`, you can often shrink the safelist and rely on Tailwind’s scan; only keep patterns that are truly dynamic (e.g. class names built in JS).
78+
79+
---
80+
81+
## 4. Dependencies: unnecessary or deprecated
82+
83+
### Backend (Python)
84+
- **django-better-admin-arrayfield**: Verify you still use array fields in the admin; if not, remove.
85+
- **twilio**: Only needed if you use Twilio (SMS/whatsapp). Remove if unused.
86+
- **cloudinary**: Only if you use it as CDN; keep or replace per your deployment.
87+
- **sentry-sdk**, **gunicorn**, **django-cors-headers**, **django-filter**, **djangorestframework**, **pillow**, **psycopg2-binary**, **python-dotenv**: All current and commonly used; keep.
88+
89+
### Frontend
90+
- **file-loader**: Webpack 5 prefers **Asset Modules** (e.g. `type: "asset/resource"`) instead of `file-loader`. Migrating avoids a deprecated loader.
91+
- **Jest**: The `test` script in `frontend/package.json` runs `jest`, but **Jest is not listed in devDependencies**; it only appears in the lockfile as a transitive dependency. Either add `jest`, `ts-jest`, and necessary types as devDependencies or remove/fix the test script.
92+
- **dayjs**, **query-string**, **react-router-dom**, **@heroicons/react**: All in common use; keep unless you intentionally replace them.
93+
94+
---
95+
96+
## 5. Summary: what to do first
97+
98+
| Priority | Action |
99+
|----------|--------|
100+
| High | Fix Tailwind **content** paths to include `**/*.tsx` (and relevant JS/JSX) so Tailwind scans all component files. |
101+
| High | Remove **USE_L10N** from `core/settings/base.py` (Django 5+). |
102+
| High | Update **Django** to `^5.1` or `^6.0` in `pyproject.toml` and refresh lockfile; update settings docstrings. |
103+
| Medium | Replace **file-loader** in Webpack with Asset Modules. |
104+
| Medium | Add **Jest** (and ts-jest/types) to frontend devDependencies or adjust test script. |
105+
| Medium | Upgrade to **React 19** and matching types when ready. |
106+
| Low | Consider **Tailwind v4** later; optional. |
107+
| Low | Drop **twilio** / **django-better-admin-arrayfield** / **cloudinary** if not used. |
108+
109+
---
110+
111+
## 6. Tailwind = default and AI-friendly
112+
113+
The boilerplate **already uses Tailwind by default**. That aligns well with the “AI reality”: LLMs are very good at generating and modifying Tailwind utility classes. No need to add Tailwind for that reason; the main fix is ensuring Tailwind actually sees your `.tsx` files via correct `content` paths.

frontend/jest.config.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/** @type {import('jest').Config} */
2+
module.exports = {
3+
preset: "ts-jest",
4+
testEnvironment: "jsdom",
5+
testMatch: ["**/__tests__/**/*.ts?(x)", "**/?(*.)+(spec|test).ts?(x)"],
6+
moduleNameMapper: {
7+
"^@/(.*)$": "<rootDir>/lib/$1",
8+
},
9+
collectCoverageFrom: ["lib/**/*.{ts,tsx}", "!**/__tests__/**"],
10+
};

frontend/lib/api/use-api.ts

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,19 @@ import {
66
getPaginatedFilteredPublicationsEndoint,
77
} from "./utils";
88
import { getSecrets } from "../config";
9-
import type { GetPaginatedPublicationsResponse, Publication } from "./types";
9+
import type {
10+
GetPaginatedPublicationsResponse,
11+
Publication,
12+
} from "./types";
13+
14+
const emptyPaginatedResponse: GetPaginatedPublicationsResponse = {
15+
count: 0,
16+
current_page: 1,
17+
total_pages: 0,
18+
next: null,
19+
previous: null,
20+
results: [],
21+
};
1022

1123
const { isProd, authToken } = getSecrets();
1224

@@ -52,7 +64,7 @@ export function useApi() {
5264
headers: getHeaders,
5365
})
5466
.then((response) => response.json())
55-
.catch((error) => {
67+
.catch((error): Publication[] => {
5668
console.error(error);
5769
return [];
5870
});
@@ -113,9 +125,9 @@ export function useApi() {
113125
headers: getHeaders,
114126
})
115127
.then((response) => response.json())
116-
.catch((error) => {
128+
.catch((error): GetPaginatedPublicationsResponse => {
117129
console.error(error);
118-
return [];
130+
return emptyPaginatedResponse;
119131
});
120132
}
121133

@@ -131,9 +143,9 @@ export function useApi() {
131143
}
132144
)
133145
.then((response) => response.json())
134-
.catch((error) => {
146+
.catch((error: unknown): never => {
135147
console.error(error);
136-
return [];
148+
throw error;
137149
});
138150
}
139151

frontend/package.json

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@
2020
"dev:css": "postcss ./tailwind.css -o ./lib/index.css --watch",
2121
"dev": "concurrently -n css,react \"pnpm run dev:css\" \"pnpm run dev:react\"",
2222
"test:static": "tsc -p tsconfig.json --noEmit",
23-
"test": "jest \"(/__tests__/.)*\\.tsx?$\" --coverage --colors --silent",
24-
"test:watch": "jest \"(/__tests__/.)*\\.tsx?$\" --coverage --colors --watch"
23+
"test": "jest \"(/__tests__/.)*\\.tsx?$\" --coverage --colors --silent --passWithNoTests",
24+
"test:watch": "jest \"(/__tests__/.)*\\.tsx?$\" --coverage --colors --watch --passWithNoTests"
2525
},
2626
"dependencies": {
2727
"@heroicons/react": "^2.1.4",
@@ -63,6 +63,10 @@
6363
"webpack-cli": "^5.1.4",
6464
"webpack-dev-server": "^5.0.4",
6565
"webpack-manifest-plugin": "^5.0.0",
66-
"workbox-webpack-plugin": "^7.1.0"
66+
"workbox-webpack-plugin": "^7.1.0",
67+
"jest": "^29.7.0",
68+
"jest-environment-jsdom": "^29.7.0",
69+
"ts-jest": "^29.2.5",
70+
"@types/jest": "^29.5.14"
6771
}
6872
}

0 commit comments

Comments
 (0)