jtremesay / jssg

GNU Affero General Public License v3.0
1 stars 0 forks source link

(soft) fork or upstream contribs? #21

Closed lebouquetin closed 5 months ago

lebouquetin commented 5 months ago

Hello @jtremesay

We talk a bit a few months ago about JSSG and its usage for my company algoo. I did test some things with it and decided to start working with jssg as the core of our future websites. We need some changes and a student join us for a few weeks to help me implementing these changes.

I open the current issue in order to ask if you are interested in upstream contributions or if its better to work on our fork.

Here are the changes we plan to do:

What do you think?

Let me know.

jtremesay-sereema commented 5 months ago

Hi there!

My position hasn't changed since last time. JSSG is a project made for my personal needs, so I'm not really looking for external contributions. I think the best thing is for you to make a (soft) fork so that you can work in peace on your ideas and needs :)

However, I'd really appreciate it if the fork were public so that others could benefit from it.

FYI, the version of JSSG integrated into my blog is probably a bit more up to date.

lebouquetin commented 5 months ago

However, I'd really appreciate it if the fork were public so that others could benefit from it.

It will. The repo is there: https://github.com/algoo/jssg (do not look at it for now, this is a dirty work-in-progress amount of patchs and draft etc;)

Thanks for the update on your blog repo; we'll upgrade our source code in order to get last commits :+1:

jtremesay-sereema commented 5 months ago

tant que je te tiens, vous comptez l'utiliser comment exactement ?

À la base, mon cahier des charges était :

Ce qui a donné ce truc bizarre à base de django.

Maintenant, mon besoin à un peu changé. Pour jouer avec certains trucs (genre les websocket ou ASGI), je commence à avoir l'envie d'avoir un backend. Mais j'aime bien aussi l'idée d'avoir tout d'intégré dans un même projet django plutot que d'avoir un front static géré par JSSG d'un côté et d'un backend REST géré par flask ou django de l'autre. Mais comme 99% du site n'aura pas besoin du backend, j'aimerai bien garder un max de trucs en static.

Du coup, j'ai un peu commencé à réfléchir au futur. Déjà, plutot que de fournir JSSG sous forme de projet django, je vais voir à le transformer en app django pour plus facilement l'intégrer dans des projets existants. Mais je ne sais pas encore trop comment gérer les pages static sur la prod. J'hésite entre plusieurs trucs :

y'a des trucs qui vous interesseraient plus que d'autres ? ou c'est vraiment le côté générateur de site static tellement minimaliste que c'est facile de le hacker pour l'adapter à ses besoins qui vous plait ?

Sinon, concernant le système de template. En vrai, je préfère jinja à celui de django. mais comme celui de django me suffit dans 90% des cas, et que j'ai jamais vraiment eu de probblèmes bloquants, j'ai jamais pris le temps de regarder comment on fait l'intégration de jinja dans django. Mais si quelqu'un fait le taf à ma place et que si c'est pas trop chiant de migrer mon contenu existant… Il est fort possible que je cherry-pick le commit :)

lebouquetin commented 5 months ago

tant que je te tiens, vous comptez l'utiliser comment exactement ?

Je vais essayer de répondre à l'ensemble des points de ton long message. N'hésite pas à me relancer si j'ai loupé des trucs ;)

Aujourd'hui on exploite 3 sites web :

Les 3 sites implémentent des problématiques communes et des concepts de structuration commune :

Ces sites ont tout intérêt :

En complément, plusieurs points sont importants pour nous :

L'intérêt de JSSG pour cela :

Je vais réagir ci-dessous aux points que tu évoques :

À la base, mon cahier des charges était :

  • j'veux pouvoir écrire mon contenu depuis le comfort de mon IDE plutôt que depuis un WYSIWYG

Moi aussi. Je veux construire nos sites en éditant des fichiers textes de différents types (markdow, html, autre)

  • j'veux pas écrire de HTML si je peux faire autrement

Je sais que l'on va devoir faire du HTML. Je veux pouvoir le factoriser dans des widget réutilisables. Exemple : un widget "texte à gauche et image à droite" que j'instantie dans ma page avec une série de paramètre : titre de la section, contenu textuel à gauche, url de l'image à droite, titre de l'image, etc, etc.

Si on n'a pas besoin de HTML (exemple : un article de blog), alors le markdown est parfait. Mais si je veux structurer des widgets HTML complexes, je dois mettre de l'indentation et le markdown ne sera pas approprié car il interprète les indentations.

Exemple de contenu d'une page (la manière dont je veux pouvoir construire mes pages) :

{{ WIDGET__SECTION__TESTIMONIAL_LOGOS((
  { "name": "oslandia", "logo_url":"https://www.galae.net/assets/img/references/oslandia.png" },
  { "name": "NARM-PC", "logo_url":"https://www.galae.net/assets/img/references/narm-pc.svg" },
  { "name": "Domeo conseils", "logo_url": "https://www.galae.net/assets/img/references/domeo-conseils.png" },
  { "name": "Ethicsys", "logo_url": "https://www.galae.net/assets/img/references/ethicsys.png" },
  { "name": "pix'n'graph", "logo_url":"https://www.galae.net/assets/img/references/pixngraph.png" }
)}}

<section class="showcase">
    <div class="container-fluid p-0">
        {{ WIDGET__PAGE_BLOCK__H2_WITH_UL__IMAGE_ON_RIGHT(
            TITLE="
                Des e-mails <span class='galae-color'>délivrés</span>,
                conformes aux <span class='galae-color'>standards</span>
            ",
            IMAGE_URL="https://www.galae.net/assets/img/undraw_futuristic_interface_re_0cm6.svg",
            CONTENT_ITEMS=[
                "Notre plateforme supporte nativement DKIM, SPF et DMARC.",
                "Vous interagissez avec vos e-mails, carnets d'adresses et agendas via les protocoles standards IMAP, POP3, CalDAV et CardDAV.",
                "Nous proposons des filtres SIEVE, des alias, une gestion fine des quotas.",
                "Nous sommes attentifs à la délivérabilité de vos e-mails."
            ],
            CTA_LABEL="Découvrir les tarifs",
            CTA_URL="#pricing",
        )}}
    </div>
</section>
  • j'dois pouvoir utiliser le templating dans le markdown parce que j'ai parfois (souvent) besoin de faire des trucs débiles (cf la génération d'une table markdown à partir d'un csv parce que ça me fait chier de gérer la table à la main quand je peux automatiser)

C'est un bon exemple de cas où les templates sont intéressants, effectivement

  • j'préfère avoir le contenu dans git histoire d'avoir un versionnage facile

Idem

  • quitte à bosser dans l'ide et avoir git; autant avoir une CD pour publier le nouveau contenu

Sur galae (100% statique), on déploie les mises à jour en 1 clic. Mais actuellement c'est 100% statique et à composer c'est la mort. Avec JSSG retravaillé, on aura un outil super efficace pour produire le contenu et un déploiement en 2 commandes :

  1. génération via la commande jssg
  2. déploiement via le workflow qu'on a
  • j'ai pas besoin d'un backend, du coup c'est pas mal si le site peut être totalement static

Nous on a besoin d'un backend pour les formulaires : prise de contact, inscription, achat. Le plan est soit de faire un moteur dédié (j'ai un embryon de truc, ça marche + ou moins et ça demande juste à être finalisé) soit d'utiliser Grist qui a l'air de bien répondre au sujet.

Pour galae par exemple, on a un moteur de tunnel de vente qui gère juste ça : 1 formulaire de choix + coordonnées + renvoie vers Stripe pour le paiement et vers notre Dolibarr pour le suivi (commande, facturation)

  • l'itération précédente de jssq m'avait montré que c'est quand même cool d'avoir un serveur de dev local plutôt que d'avoir un système de build

C'est top pour ça JSSG, je te confirme.

Ce qui a donné ce truc bizarre à base de django.

Maintenant, mon besoin à un peu changé. Pour jouer avec certains trucs (genre les websocket ou ASGI), je commence à avoir l'envie d'avoir un backend. Mais j'aime bien aussi l'idée d'avoir tout d'intégré dans un même projet django plutot que d'avoir un front static géré par JSSG d'un côté et d'un backend REST géré par flask ou django de l'autre. Mais comme 99% du site n'aura pas besoin du backend, j'aimerai bien garder un max de trucs en static.

C'est un truc que j'ai envisagé quand j'ai commencé à creuser JSSG. Je m'étais dit "ah mais on pourrait faire un truc qui génère les pages statiques et qui génère à côté un petit site dynamique pour les pages qui le nécessitent". Ou alors qui s'auto-déploie. Mais la complexité du truc fait que ça couple beaucoup les choses et je pense que faire des apps distinctes est + facile faire évoluer dans la durée.

Du coup, j'ai un peu commencé à réfléchir au futur. Déjà, plutot que de fournir JSSG sous forme de projet django, je vais voir à le transformer en app django pour plus facilement l'intégrer dans des projets existants. Mais je ne sais pas encore trop comment gérer les pages static sur la prod. J'hésite entre plusieurs trucs :

  • les pages statics sont mises dans nginx à côté et le reverse proxy s'occupe de router entre nginx et django selon qu'on est sur du static ou du dynamique. J'aime pas trop parce que ça rajoute des services et que quitte à devoir mettre un service django, autant que ça soit lui serve tout. Mais ça reste l'option qui offre les meilleurs perfs. surtout qu'il est possible de mettre les statics dans un CDN S3 (meme si personnellement je ne l'implementerai pas parce que tout tourne sur mon kimsufi)

L'idée me semble bien de tout servir en 100% django. En performance c'est pas idéal, mais rien n'empêche ton nginx/apache frontal de service directement les parties statiques (et que derrière django soit, lui aussi, capable de les servir)

Le CDN pour moi c'est un nogo. Je veux être autonome ; et on ne cible pas des sites avec des millions de vues.

  • servir les pages statiques via le système de statics de django. J'ai jamais joué avec le système de static de django, je ne sais pas si ça serait chiant à implémenter. Mais ça serait pour moi l'idéal parce que j'aurais tout d'intégré dans un seul service tout en ayant un max de truc static, tout en ayant la possibilité d'utiliser du middleware django pour faire de l'analytics / profilage de requete (ça fait un moment que j'ai envie de faire mon analytics qui fournit des stats de base sans faire de la collecte de données personnelles ou du profilage)
  • précompiler les mardowns en templates django, et gérer ça comme des vues classiques. Ça permet d'avoir facilement des pages dynamiques, tout en ayant la possibilité de profiter du système de cache de django pour ne pas trop nuire au perfs. J'en ai pas encore le besoin, mais je sens que ça va finir par poindre du coup je laisse l'option sur la table.

J'avais envisagé ce genre de chose initialement (avant de trouver JSSG) mais au final, on garde les problématiques de déployer un truc dynamique, les aspects sécurité, le besoin de faire des tests à chaque upgrade, etc, etc. Des fichiers HTML, Webp et CSS c'est ultra-robuste.

y'a des trucs qui vous interesseraient plus que d'autres ? ou c'est vraiment le côté générateur de site static tellement minimaliste que c'est facile de le hacker pour l'adapter à ses besoins qui vous plait ?

Le côté "hackable" est intéressant, mais c'est surtout la philosophie de ce que tu as mis dans JSSG qui est exactement la première étape de ce que je cherchais à faire ... du coup autant repartir de ce que tu as fait, surtout que tu exploites des trucs assez malins que j'aurais plus fait "en mode bourrin" :)

Sinon, concernant le système de template. En vrai, je préfère jinja à celui de django. mais comme celui de django me suffit dans 90% des cas, et que j'ai jamais vraiment eu de probblèmes bloquants, j'ai jamais pris le temps de regarder comment on fait l'intégration de jinja dans django. Mais si quelqu'un fait le taf à ma place et que si c'est pas trop chiant de migrer mon contenu existant… Il est fort possible que je cherry-pick le commit :)

Pour moi ce sujet, c'est simplement du confort d'édition des pages. Cf l'exemple de contenu de page que j'ai mis au dessus : on ne peut pas faire ça avec Django.

Si tu regardes https://raw.githubusercontent.com/algoo/jssg/main/content/pages/index.md?token=GHSAT0AAAAAACHE2PK6CBOK4A63LSBS26O2ZTLKXHQ, tu vas voir que j'ai implémenté un mécanisme de traitement des pages {{{TO-1-LINE et TO-1-LINE}}} pour permettre d'écrire les include des templates django sur plusieurs lignes. Au moment de la génération ça "inline" tout ce qui se trouve entre les deux balises (remplace les retours à la ligne par un espace). Techniquement c'est nase, ça ne sert à rien, c'est juste pour pouvoir construire des pages lisibles et maintenables humainement. Avec des macros Jinja, ça devient immédiat, sans bidouilles : les macros peuvent être écrites sur plusieurs lignes.

lebouquetin commented 5 months ago

L'idée derrière ça, c'est pas tant de "bidouiller JSSG" mais de le faire évoluer pour devenir un "moteur de site statiques multiples" avec :

  1. un moteur générique de traitement et génération (jssg),
  2. une bibliothèque de composants de page, assets, etc prêts à être utilisés / réutilisés pour tous les sites qu'on gère
  3. une arborescence "données" qui contiendra le contenu proprement dit (pages, articles de blog, assets de contenu tels que les images d'illustration des articles, etc)

Dans ma tête c'est clair ... je ne sais pas si c'est bien retranscrit ;) N'hésite pas si tu veux des clarifications.

jtremesay-sereema commented 5 months ago

nan, c'est clair :)

là, commencé à faire un poc.

branch de travail https://github.com/jtremesay/jssg/tree/dynamik intégration corespondante https://github.com/jtremesay/jtremesay.org/tree/dynamik

là, jssg est une simple app django installable via pip.

Tu l'ajoute à INSTALLED_APPS dans ton settings.py:

INSTALLED_APPS = [
    # ...
    "jssg",
    "myapp"
]

et tu configures JSSG_CONTENT_DIR = BASE_DIR / "myapp" / "content" pour que ça pointe sur ton contenu (cf),

tu modifies ton myapp/urls.py pour déclarer tes pages statiques (cf) qui utilises tes templates et tes assets

from django_distill import distill_path

from jssg import views
from jssg.urls import get_pages, get_posts

urlpatterns = [
    distill_path(
        "",
        views.IndexView.as_view(template_name="myapp/page.html"),
        name="index",
        distill_file="index.html",
    ),
    distill_path("atom.xml", views.PostFeedsView(), name="atom_feed"),
    distill_path(
        "pages/<slug:slug>.html",
        views.PageView.as_view(template_name="myapp/page.html"),
        name="page",
        distill_func=get_pages,
    ),
    distill_path(
        "posts/<slug:slug>.html",
        views.PostView.as_view(template_name="myapp/post.html"),
        name="post",
        distill_func=get_posts,
    ),
]

(todo: améliorer l'api pour simplifier la déclaration)

Là, j'ai le ./manage.py runserver qui marche sur la plus part de mes pages. J'ai pas testé, mais je suppose que la commande de génération statique marche ou presque.

À partir de là, tu peux utiliser jssg comme tu veux :

et en terme d'organisation des projets, c'est assez flex.

Tu peux faire un repo par site. ou alors un repo qui contient tes trois sites avec chacun leur settings.py ou un usage très créatif des possibilisé multisite de django pour quand meme pouvoir générer les sites indépendamemt en prod mais avoir les trois en dev. ou n'importe quoi d'autre. C'est flex django !

enfin bon, j'ai encore un peu de taf pour tout réparer :)