PyJSTML — Python JavaScript Text Markup Language
Concept
PyJSTML est un moteur de lecture pur (READ ENGINE) qui transforme du contenu JSON structuré en pages HTML via des templates Jinja2, servi par WSGI natif derrière nginx.
Client → nginx → uwsgi → index.py
├── core/i18n.py → détection langue
├── core/router.py → résolution slug (whitelist)
├── core/loader.py → chargement JSON + cache
└── core/renderer.py → rendu Jinja2 → HTML brut
Pas de framework. Pas de base de données. Pas d'écriture.
| Propriété | Valeur |
|---|---|
| Moteur | WSGI natif Python |
| Dépendance unique | Jinja2 ≥ 3.1 |
| Python | 3.11+ |
| Langues | Multi (FR défaut, EN, extensible) |
| Framework | Aucun |
| Base de données | Aucune |
| Écriture | Aucune (lecture seule) |
SEO — HTML Brut & Indexabilité Native
PyJSTML génère du HTML statique brut rendu côté serveur (SSR) et servi immédiatement. Aucun JavaScript pour le rendu initial : le contenu est présent dans le HTML envoyé au navigateur et aux crawlers des moteurs de recherche.
Avantages SEO directs
- Crawlabilité maximale. Googlebot, Bingbot, et autres crawlers reçoivent immédiatement le HTML complet. Pas d'attente de rendu JavaScript client — zéro latence pour l'indexation.
- Contenu structuré en JSON. Les templates Jinja2 génèrent une sémantique HTML propre (headings, listes, tableaux, balises sémantiques). Pas de
divwrapper inutile : chaque élément a un sens. - Meta tags et Open Graph natifs. Le JSON contient
title,description,canonical,og:*. Jinja2 les injecte dans le<head>à la génération. Les crawlers voient les métadonnées immédiatement. - URLs propres et prévisibles. Routing whitelist stricte : seules les URLs déclarées existent. Pas de paramètres dynamiques cachés. Slugs regex-validés
[a-zA-Z0-9\-_/]→ URLs SEO-friendly. - Temps de chargement rapide. HTML statique : zéro parsing JavaScript, zéro appels API. Le document arrive immédiatement. Core Web Vitals optimisés par défaut (LCP, FID, CLS tous excellents).
- Multi-langue intégrée. Détection automatique par en-tête
Accept-Languageet URLs langagées. Les crawlers voient les versions localisées. Les hreflang canoniques peuvent être auto-générés dans les templates. - Pas de duplicate content. URLs strictes + multi-langue = chaque page existe une seule fois. Pas de fragments inutiles, pas de paramètres de session.
- Cache et CDN friendly. HTML statique peut être cachée en HTTP cache, servie par CDN, validée en ETag. Les crawlers profitent des headers optimisés.
Implémentation technique
Chaque page est générée une seule fois (ou au cache refresh) :
# Cycle de génération SEO
JSON (contenu + meta) → Jinja2 (rendu) → HTML brut
↓
Navigateur reçoit immédiatement le HTML complet
↓
Crawler indexe directement (pas d'attente JS)
↓
Meta tags, canonical, structured data visibles
Cas d'usage SEO parfaits
- Sites éditoriaux (blogs, news, documentation)
- Portfolios et CV (indexation instantanée)
- Landing pages et brochures web
- Sites multilingues (FR, EN, etc. avec hreflang natif)
- Catalogues statiques avec filtrage côté client (JS progressive enhancement)
Architecture
pyjstml-main/
├── index.py # WSGI entrypoint + dev server
├── requirements.txt # Jinja2>=3.1
├── wsgi.ini # Config uWSGI production
├── nginx.conf.example # Config nginx exemple
│
├── core/ # Modules moteur
│ ├── __init__.py
│ ├── i18n.py # Détection langue, URL switching
│ ├── router.py # Slug → Route (whitelist stricte)
│ ├── loader.py # Chargement JSON + cache mémoire
│ └── renderer.py # Jinja2 Environment + rendu
│
├── content/ # Contenu JSON par langue
│ ├── fr/
│ │ ├── _common.json # Nav, footer, labels partagés
│ │ └── home.json # Page d'accueil
│ └── en/
│ ├── _common.json
│ └── home.json
│
├── tpl/ # Templates Jinja2
│ ├── layout.html # Layout principal
│ ├── page.html # Template page générique
│ ├── 404.html # Erreur 404
│ └── components/
│ ├── hd.html # Header
│ ├── mn.html # Navigation
│ ├── ft.html # Footer
│ └── card.html # Composant carte
│
└── static/
├── css/style.css # Feuille de style
└── js/app.js # JavaScript client (optionnel)
Installation
# Cloner
git clone https://github.com/VOTRE_USER/pyjstml.git
cd pyjstml-main
# Environnement virtuel
python3 -m venv .venv
source .venv/bin/activate
# Dépendances
pip install -r requirements.txt
Développement
# Serveur de développement intégré (port 8080)
python index.py
# → http://localhost:8080
Production (nginx + uWSGI)
1. uWSGI
pip install uwsgi
uwsgi --ini wsgi.ini
2. nginx
# Copier et adapter la config
sudo cp nginx.conf.example /etc/nginx/sites-available/pyjstml
sudo ln -s /etc/nginx/sites-available/pyjstml /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
Ajouter une page
1. Contenu JSON
Créer content/fr/ma-page.json et content/en/ma-page.json :
{
"meta": {
"title": "Ma Page — Mon Site",
"description": "Description de la page.",
"canonical": "/ma-page"
},
"header": {
"title": "Titre de la page",
"tagline": "Sous-titre optionnel",
"compact": true
},
"sections": [
{
"id": "intro",
"title": "Section titre",
"lead": "Texte d'introduction en HTML inline.",
"content": "Paragraphe principal."
}
]
}
2. Route
Ajouter dans core/router.py :
ROUTE_MAP = {
# ...existant...
"ma-page": Route("ma-page", "page.html", "ma-page.json"),
}
3. Navigation
Ajouter dans content/{lang}/_common.json → nav.
Ajouter une langue
- Créer
content/{code}/avec_common.json+ fichiers de contenu - Ajouter le code dans
core/i18n.py→SUPPORTED_LANGS - Les templates gèrent automatiquement le switcher
Sécurité
- Slug sanitization : regex whitelist
[a-zA-Z0-9\-_/] - Path traversal :
os.path.realpath()vérifie le confinement danscontent/ - Route whitelist : seules les routes déclarées sont accessibles
- Autoescape Jinja2 : protection XSS native
- Headers sécurité :
X-Content-Type-Options,X-Frame-Options,Referrer-Policy,Permissions-Policy - Pas de framework = surface d'attaque minimale
Philosophie
PyJSTML suit la spécification 4S5R (4Strict & 5Royals) :
- Contenu = JSON structuré (données pures, pas de logique)
- Présentation = Jinja2 templates (HTML pur, pas de JS framework)
- Logique = Python WSGI natif (routing, i18n, rendu)
- JavaScript = Optionnel, côté client uniquement (progressive enhancement)
Le résultat : du HTML brut, rapide, indexable, accessible.
PyJSTML — © Jean‑Yves "JoYz" Cornet · Propriétaire