demarches-simplifiees / demarches-simplifiees.fr

Dématérialiser et simplifier les démarches administratives
https://www.demarches-simplifiees.fr
GNU Affero General Public License v3.0
189 stars 89 forks source link

Stack JS #6849

Open mfo opened 2 years ago

mfo commented 2 years ago

Problème précis :

mfo commented 2 years ago

pour le sujet IE11 ; on peut instrumenter les comptes via une custom variable matomo afin d'en avoir le coeur net si vous le souhaitez. ex d'implem : https://github.com/betagouv/monstage/blob/staging/app/views/layouts/_analytics.html.erb#L9

kemenaran commented 2 years ago

Point de détail : je suis pas trop chaud pour intégrer le tag manager de Matomo :

Mais en revanche chaud pour une variable custom mise directement dans le code.

tchak commented 2 years ago

Pourquoi ?

L’arrivée prochaine du chantier des champs conditionnels avec son lot de dynamisme dans les interfaces nous a incités à porter le regard sur notre stack “frontend".

Turbo

La semaine dernière j’ai travaillé sur l’introduction de turbo dans le projet. Je vous fais ici un retour. Sous le nom turbo en réalité se cachent plusieurs technologies. Les plus importantes c’est turbo-drive, turbo-stream, turbo-frames et stimulus. Je vais vous en dire deux mots sur chacune :

L'existant

Le constat que je fais c’est qu’aujourd’hui nous avons beaucoup de manières différentes de coder des interactions dans DS. En introduisant turbo j’aimerai qu’on en réduise le nombre de techniques et pas qu’on ajoute juste une autre.

Aujourd’hui, nous avons plusieurs techniques en place :

“Le dogme DHH”

Comme je l'ai expliqué plus haut, turbo c'est un ensemble de techniques qui peuvent être utilisées de manières différentes. Il y a le dogme officiel DHH/Rails. Tel que je le comprends c'est :

Le premier soucie dans notre cas c'est l'existent

Il faut migrer ce que nous avons vers une des techniques de turbo.

Le plus direct c'est de migrer ujs + format :js vers turbo-drive + turbo-stream. J'ai un peu commencé. La principale difficulté est dans le fait que c'est risquer d'activer turbo-drive sur l'ensemble d'une vieille app comme la nôtre. Il faut donc activer turbo-drive au cas par cas en remplaçant data-remote et data-confirm par data-turbo et data-turbo-confirm. Ce n’est pas trivial, car la logique d'application déclarative n'est pas la même qu'avec ujs – ce n’est pas l'élément interactif qui doit porter data-turbo=“true”, mais un de ces parents. Donc relou, mais pas impossible.

Les interactions bindé sur ds:page:update doivent être supprimé, car turbo-stream ne sait pas emmètre d'événement à la suite de remplacement de DOM et incite à utiliser stimulus qui se base sur les MutationObserver pour ajouter de l'interactivité. L'approche par délégation continue de fonctionner aussi évidemment. C'est la raison pour laquelle nous avons migré l'instanciation des composants react vers stimulus.

L'approche par délégation pose le problème de maintenabilité – il est difficile de savoir quand un snippet n'est plus utilisée. Donc mon souhait sera de s'en éloigner de cette approche. Enfin les onclick via le namespace DS.* pose un soucie similaire même s’il est un peu plus facile de trouver les usages du code avec un grep.

Le deuxième soucie c'est l'alignement dans l'équipe

Mon expérience des discussions avec vous c’est que nous avons des sensibilités très différentes vis-à-vis de la manière la plus confortable de faire du frontend. Pour être honnête, ce problème existe aussi pour la partie backend, mais Rails (pour le meilleure et pour le pire) fait un meilleur job de proposer des solutions “clés en main” sur la partie backend. turbo est clairement une tentative par Basecamp de proposer une solution “clés en main”. Les retours que j'ai pour l’instant c'est que les nouveaux projets alignés sur le dogme DHH se passent raisonnablement bien. Mais dans notre cas on ne peut pas faire l'abstraction de l'existent et l'énergie disponible à mettre dans la migration est limité.

Nous avons besoin de nous aligner dans l’équipe sur ce vers quoi on veut y aller. Je veux bien faire du taff pour migrer, mais j'ai besoin de motivation de votre part. Si je devais faire la migration à la sauce "Tchak" ça ne ressemblerait pas au dogme DHH. Si vous voulez le dogme DHH il faut le dire clairement pour que je sache pourquoi je le fais. Peut-être que ce dogme est finalement la seule solution pour trouver un accord. Car ce que j'entends quand je demande "vous voulez quoi pour faire du frontend ?" on me répond "je veux le code le plus simple possible". Ça ne m'aide pas. Nous n’avons clairement pas la même définition de "simple". Mon "simple” à moi serait de migrer progressivement vers du React SSR. Ce n’est clairement pas celui de l’équipe 🤣 C'est normal. J'ai donc besoin de savoir si vous voulez qu'on essaye un tour de table pour arriver à un set de pratiques (autour de turbo) ou vous pensez qu'on n’arrivera pas à se mettre d'accord et qu'il faut juste appliquer le dogme DHH ?

Pour prendre un exemple – personnellement la partie qui me pose le plus de problèmes dans turbo c'est stimulus. Les <button data-controller="toggle" data-action="click->toggle#onClick" data-toggle-value="true" /> je trouve ça imbitable et inmaintenable. Qit à faire du turbo je préfère un button_to avec turbo-drive avec dans un controller un render turbo_stream: turbo_stream.toggle('.card') ce qui serait évidemment très controversé. Mais peut être que ce type d'interaction (interaction entre des éléments dans la page) peut être modélisée via les turbo-frame ?

mfo commented 2 years ago

en gros dsl mais je suis en boucle la dessus.

TLDR ; dans le fond : je pense que l'interactivité portée par le JS sur une page web est over rated (ok pour du FB ou des sites qui sont des apps genre, mobile. la on est sur une app metier. un cycle de vie complet client/server me semble être ce qui reste de plus productif/facile/maitrisable tout en étant acceptable par l'utilisateur).

concernant la substance de ma position et ton push :

  1. déjà bravo de mettre ça en place ; je pense que sur le conditionnel l'outil tombe a point.
  2. tant qu'a refactorer du JS (donc l'existant), mon avis c'est de voir avant avec Olivier si on ne peut pas simplifier l'interface (afin de virer des parties en JS). il y a plusieurs sujets autour de ça : je garderais les ilots react et le mix turbo (j'ai apprécié stimulus pour eviter les "soupes" de namespace globaux ou de delegation en vrac). le reste -> bye
  3. pour le choix des technos, si par react/SSR tu entends une simili SPA ; pas ma tasse de thé
tchak commented 2 years ago

Je vais apporter une précision. Quand je dis :

Mon "simple” à moi serait de migrer progressivement vers du React SSR

LeSim commented 2 years ago

Merci pour ce travail.

Concernant une spa

Dans mon lointain souvenir ou je faisais du js, on était obligé de modéliser le métier coté back et front, avec des points de frictions entre le 2.

Dans la mesure ou on garde le back en rails, on aura a nouveau ce pb. je suppose qu'il est plus coûteux que l'utilisation de la full stack rails DHH.

Concernant une intégration partielle

@tchak , je n'ai pas bien compris, tu proposes du remix pour une intégration partielle ou tu trouves cela pertinent uniquement pour une spa ?

tchak commented 2 years ago

@LeSim Je ne préconise pas une SPA. Tu à raison que s'il faut modéliser le métier deux fois c'est null. Je vous ai préparé une demo pour illustrer l'usage possible de remix avec rails. Oui, ça suppose qu'il y a un serveur node entre l'app rails et le navigateur.

Backend : https://github.com/tchak/rails-remix-demo/blob/b6bf791aa73979dff14ef48c943ddae73bffe42e/app/controllers/todos_controller.rb Frontend : https://github.com/tchak/rails-remix-demo/blob/b6bf791aa73979dff14ef48c943ddae73bffe42e/app/frontend/routes/index.tsx

Pour moi l'avantage de cette solution c'est que l'UI est complètement déclarative, dynamique, typée et fonctionne sans JavaScript en dernier recours. Toutes les interactions sont faites via les form et donc peuvent être envoyées directement vers rails. Il n'y a pas de “state management” coté JavaScript. La session est gérée par rails aussi. Le node ne fait que crasher du HTML et optimise les transitions (si le JavaScript est disponible). Mais les réponses de rails c’est du json et des redirects sans aucune “magie”. Ce que j'appelle "optimise les transitions" c'est que si le JavaScript est chargé sur la page les submit se font via fetch (comme avec turbo) et le serveur node intercepte les redirections et retourne une 204 avec un header spécial qui fait que le redirect devient un fetch en arrière-plan suivi d’un update de l'état de la page.

Et ce que vous pouvez voir aussi dans ma démo c'est le fait que les pages qui ne sont pas implémentées dans remix sont simplement servies depuis rails. C'est ça que j'appelle l'application "ombrelle". Donc il est possible de migrer page par page. En théorie la migration c'est de porter une page de haml vers tsx et de mettre les variables d'instance dans le controller dans un render json.

tchak commented 2 years ago

Je pense qu'il faut qu'on ferme cette parenthèse sur les SPA/remix. Quelle que soit ma conviction sur ce qui serait “le monde idéal”, il faut qu'on avance de manière pragmatique.

Je pense que l'usage des view_components sera un bon pas en avant. J'ai un plan pour faire en sorte que les view_components puissent utiliser React et Stimulus en fonction des besoins. Si déjà on arrive à ça en se débarrassant de tout le js ad hoc, ça va être top.