<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/">
  <channel>
    <title><![CDATA[Anthony Pena]]></title>
    <description><![CDATA[Libriste mais pas extrémiste.]]></description>
    <link>https://anthonypena.fr</link>
    <generator>Anthony Pena's blog v1.0.0</generator>
    <lastBuildDate>Sun, 10 May 2026 10:42:26 GMT</lastBuildDate>
    <ttl>60</ttl>
    <image>
      <url>https://anthonypena.fr/favicon.png</url>
      <title>Anthony Pena</title>
      <link>https://anthonypena.fr</link>
    </image>
    <atom:link href="https://anthonypena.fr/feed.xml" rel="self" type="application/rss+xml"/>
    <item>
      <title><![CDATA[Revue de presse - Mai 2026]]></title>
      <guid isPermaLink="false">2026/05/05/revue-de-presse-mai</guid>
      <description><![CDATA[]]></description>
      <link>https://anthonypena.fr/2026/05/05/revue-de-presse-mai/index.html</link>
      <category><![CDATA[Revue de presse]]></category>
      <pubDate>Tue, 05 May 2026 07:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<h2 id="article-frontend">Frontend<a href="#article-frontend" class="anchor" aria-label="permalink">🔗</a></h2>
<h2 id="article-ng-baguette-conf-2026httpswwwhelloassocomassociationsangularnexusevenementsngbaguetteconf2026"><a href="https://www.helloasso.com/associations/angular-nexus/evenements/ng-baguette-conf-2026">NG Baguette Conf 2026</a><a href="#article-ng-baguette-conf-2026httpswwwhelloassocomassociationsangularnexusevenementsngbaguetteconf2026" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Je continue (avec toute l&#39;équipe) à travailler sur <a href="https://ngbaguette.angulardevs.fr/fr/">NG Baguette Conf 2026</a> et je profite de cette revue de presse pour vous dire qu&#39;on a lancé un code promo pour le dernier mois, avec le code &quot;LASTMONTH&quot; vous aurez -15% sur votre billet.</p>
<p>Au passage j&#39;ai travaillé sur le badge que les participants, et je l&#39;ai fait via du HTML/CSS avec les éléments de print qui sont prévues dans HTML/CSS, et comme j&#39;hésite depuis bien 2 ans à faire un article sur le sujet, j&#39;évoque le truc et si certains me font savoir que ça les intéresse j&#39;en parlerai !</p>
<h3 id="article-featcore-introduce-service-decorator-by-crisbeto--pull-request-68195--angularangular--githubhttpsgithubcomangularangularpull68195"><a href="https://github.com/angular/angular/pull/68195">feat(core): introduce @Service decorator by crisbeto · Pull Request #68195 · angular/angular · GitHub</a><a href="#article-featcore-introduce-service-decorator-by-crisbeto--pull-request-68195--angularangular--githubhttpsgithubcomangularangularpull68195" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#Angular #Frontend #TypeScript</p>
<p>Je cite directement le contenu de la description de la pull request :</p>
<blockquote>
<p>These changes introduce the new @Service decorator which is a more ergonomic alternative to @Injectable. The reason we&#39;re adding a new decorator is that @Injectable has been around since the beginning of Angular and it has a lot of baggage that adds unnecessary overhead for users that generally want to define a singleton service, available in their entire app. The key differences between @Service and @Injectable are:</p>
<ol>
<li>@Service is providedIn: &#39;root&#39; by default. You can opt into providing the service yourself by setting autoProvided: false on it.</li>
<li>@Service doesn&#39;t allow constructor-based injection, only the inject function.</li>
<li>@Service doesn&#39;t support the complex type signature of @Injectable (useClass, useValue etc.). Instead it supports a single factory function.</li>
</ol>
<p>Example:</p>
<pre><code class="hljs language-TypeScript"><span class="hljs-keyword">import</span> {<span class="hljs-title class_">Service</span>} <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;@angular/core&#x27;</span>;
<span class="hljs-keyword">import</span> {<span class="hljs-title class_">HttpClient</span>} <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;@angular/common/http&#x27;</span>;
<span class="hljs-keyword">import</span> {<span class="hljs-title class_">AuthService</span>} <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;./auth&#x27;</span>;

<span class="hljs-meta">@Service</span>()
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">PostService</span> {
 <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> httpClient = <span class="hljs-title function_">inject</span>(<span class="hljs-title class_">HttpClient</span>);
 <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> authService = <span class="hljs-title function_">inject</span>(<span class="hljs-title class_">AuthService</span>);

 <span class="hljs-title function_">getUserPosts</span>(<span class="hljs-params"></span>) {
   <span class="hljs-keyword">return</span> <span class="hljs-variable language_">this</span>.<span class="hljs-property">httpClient</span>.<span class="hljs-title function_">get</span>(<span class="hljs-string">&#x27;/api/posts/&#x27;</span> + <span class="hljs-variable language_">this</span>.<span class="hljs-property">authService</span>.<span class="hljs-property">userId</span>);
 }
}<div aria-hidden="true" class="language-tag">TypeScript</div>
</code></pre></blockquote>
<p>Simplification qui ne va pas changer fondamentalement Angular mais va rendre plus explicite et plus clair pour les nouveaux développeurs Angular tout en donnant plus d&#39;intention. Personnellement j&#39;aime beaucoup ce changement. </p>
<p>En plus ça va obliger les collègues à utiliser <code>inject()</code> 😂 </p>
<h3 id="article-features-everyone-should-steal-from-npmx--andrew-nesbitthttpsnesbittio20260416featureseveryoneshouldstealfromnpmxhtml"><a href="https://nesbitt.io/2026/04/16/features-everyone-should-steal-from-npmx.html">Features everyone should steal from npmx | Andrew Nesbitt</a><a href="#article-features-everyone-should-steal-from-npmx--andrew-nesbitthttpsnesbittio20260416featureseveryoneshouldstealfromnpmxhtml" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#NPM #Frontend</p>
<p>L&#39;article évoque la stratégie de npmx.dev pour combler les manques de npmjs.com : refaire un frontend qui ne casse aucune URL (sauf le domaine) pour minimiser l&#39;effort de basculer un lien de npmjs.com en npmx.dev avec toutes les features qu&#39;énormément de gens demandent depuis plus de 5 ans mais qui n&#39;ont jamais été implémenté et qui s&#39;entasse dans le backlog depuis le rachat de npm par Github. </p>
<p>Résultat : beaucoup de gens ont migrés au quotidien sur npmx.dev (j&#39;en fais partie) et ça a poussé npmjs.com à commencer à ajouter des choses (le light/dark le mois dernier). Est-ce que ça ira plus loin ? Peut-être. En attendant : on a déjà un super outil, rien n&#39;a changé dans nos habitudes au sens propre </p>
<h2 id="article-ia">IA<a href="#article-ia" class="anchor" aria-label="permalink">🔗</a></h2>
<h3 id="article-ai-agents-can-now-cost-more-than-the-humans-they-were-supposed-to-replace--startup-fortunehttpsstartupfortunecomaiagentscannowcostmorethanthehumanstheyweresupposedtoreplace"><a href="https://startupfortune.com/ai-agents-can-now-cost-more-than-the-humans-they-were-supposed-to-replace/">AI agents can now cost more than the humans they were supposed to replace – Startup Fortune</a><a href="#article-ai-agents-can-now-cost-more-than-the-humans-they-were-supposed-to-replace--startup-fortunehttpsstartupfortunecomaiagentscannowcostmorethanthehumanstheyweresupposedtoreplace" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#IA</p>
<p>En résumé : si vous remplacez du travail humain qui était globalement du retravaillé de texte (genre du support client / utilisateur de premier niveau qui va reformuler la doc ou RTFM) c&#39;est hyper efficace financièrement, même si ça peut questionner sur la relation humaine. Par contre pour remplacer un flux de travail complexe, voir assez complexe pour demander un contrôle humain, coûte aussi cher voir plus cher que le faire uniquement par un humain.</p>
<p>Et c&#39;est logique : l&#39;IA (en tout cas en l&#39;état actuel des choses) ne peut pas raisonner, donc ne peut pas remplacer un raisonnement humain, et donc il faut à peu près autant d&#39;humain qu&#39;avant mais en plus payer l&#39;IA. Si le gain en temps est très bon ça peut être intéressant (mais ça se discute pour plein de raison : charge mentale sur les humains en question, humain qui ne voit plus toute la tâche et n&#39;est plus aussi pertinent, augmentation de la fatigue humaine et donc augmentation des erreurs, etc.). Si le gain de temps ne permet pas de dégager plus de business c&#39;est une perte sèche </p>
<p>Dans le même temps : on fait ce constat alors qu&#39;on ne paie pas le vrai prix de l&#39;IA, environ 1/100eme du prix, alors imaginez demain quand il faudra payer le prix fort pour l&#39;IA et que les humains ne sauront plus travailler sans ladite IA à cause de la réorientation de capacité cognitive ? 😇 </p>
<h2 id="article-securite">Sécurité<a href="#article-securite" class="anchor" aria-label="permalink">🔗</a></h2>
<h3 id="article-bruteforce-de-cartes-bancaireshttpskorbeninfocartebancairebruteforcehtml"><a href="https://korben.info/carte-bancaire-brute-force.html">Bruteforce de cartes bancaires</a><a href="#article-bruteforce-de-cartes-bancaireshttpskorbeninfocartebancairebruteforcehtml" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#Paiement #Sécurité #Carte-bancaire #Banque</p>
<p>Un chercheur en sécurité se rend compte que c&#39;est hyper facile de bruteforce un numéro de carte bancaire (quand on a le ticket de carte où il manque juste une partie des chiffres) en environ une nuit </p>
<p>Comment ça marche sa technique ? Facile ! On tente toutes les combinaisons en tapant les formulaires de paiement de différents sites marchants jusqu&#39;à ce que ça passe. Certains sites marchants vont carrément jusqu&#39;à indiquer que la carte est expirée, qu&#39;il y a une erreur de 3 chiffres ou que c&#39;est juste le CVV qui est faux… Des infos qui aident encore plus le bruteforce… </p>
<p>Et une fois les numéros obtenus, il suffit de passer par un site qui ne demande pas le 3DS et c&#39;est bon on peut vider le compte 🥶 (et pas besoin de chercher loin pour un site sans 3DS, Amazon n&#39;a pas de 3DS la plupart du temps) </p>
<p>En résumé : si quelqu&#39;un a le script et trouve un ticket de carte, en une nuit il peut récupérer le numéro complet et vider votre compte. Et le plus &quot;drôle&quot;? C&#39;est les sites sans 3DS qui auront servi à vider votre compte qui seront considérés comme responsable 😅 </p>
<p>Je crois que je vais arrêter complètement de prendre des tickets de cartes moi… </p>
<h2 id="article-divers">Divers<a href="#article-divers" class="anchor" aria-label="permalink">🔗</a></h2>
<h3 id="article-git-fixup-is-magic-and-magit-is-toohttpsarialdomartinigithubiogitfixup"><a href="https://arialdomartini.github.io/git-fixup">Git fixup is magic (and Magit is too)</a><a href="#article-git-fixup-is-magic-and-magit-is-toohttpsarialdomartinigithubiogitfixup" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#Git</p>
<blockquote>
<p>Add this alias to your <code>.gitconfig</code>:</p>
<pre><code>[alias]
  fixup = &quot;!f() { TARGET=$(git rev-parse $1); git commit --fixup=$TARGET ${@:2} &amp;&amp; GIT_SEQUENCE_EDITOR=true git rebase -i --autostash --autosquash $TARGET^; }; f&quot;
</code></pre><p>Then, use it as follows:</p>
<ul>
<li>Make a change.</li>
<li>Stage files with git add .</li>
<li>Fix up the desider commit (git fixup <SHA-1>).</li>
<li>Profit.</li>
</ul>
</blockquote>
<p>Alias sympa pour git qui me fait découvrir qu&#39;on peut faire un commit qui fait directement un fixup d&#39;un autre sans passer par un rebase explicite dans un second temps 😮 </p>
<h3 id="article-podman-avec-des-quadlets--gitops-avec-materiahttpsunetassedecafeblogpodlet"><a href="https://une-tasse-de.cafe/blog/podlet/">Podman avec des Quadlets + GitOps avec Materia</a><a href="#article-podman-avec-des-quadlets--gitops-avec-materiahttpsunetassedecafeblogpodlet" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#Docker #GitOps #OS #Git #SystemD #DevOps</p>
<p>Franchement super intéressant ça ! </p>
<p>Docker ça veut généralement dire qu&#39;on est en root, avec un daemon qui tourne, et on se coupe de l&#39;OS pour la partie gestion. Mais Docker c&#39;est pas fou pour orchestrer des conteneurs (qui sont des processus comme les autres au fond).</p>
<p>Podman c&#39;est une alternative à Docker. Quadlets vient remplacer Docker Compose mais pas en faisant la même chose : il vient juste donner la petite couche qui manque pour facilement gérer nos services conteneurisés via SystemD (je sais, je sais, beaucoup n&#39;aiment pas, je m&#39;en fiche c&#39;est pas le sujet du jour, et SystemD ça marche quand même bien et globalement partout). Plus besoin de daemon vu que c&#39;est SystemD qui gère tout.</p>
<p>Et du coup on récupère tout le système de timer, d&#39;ordonancement, d&#39;orchestration, de log, etc. de SystemD ! 😮 </p>
<p>L&#39;auteur propose aussi de passer par Materia pour faire du GitOps : on décrit dans un repo git nos services, materia se charge de mettre à jour nos définitions de services sur notre serveur ! </p>
<p>Je serais vraiment curieux de voir la consommation RAM et CPU ! </p>
<h3 id="article-oui-votre-assureur-axa-pourrait-bloquer-vos-remboursements-sur-ordre-de-washingtonhttpswwwclubiccomdossier608725axamshinternationalcesentreprisesfrancaisesquimangentdanslamaindetrumphtml"><a href="https://www.clubic.com/dossier-608725-axa-msh-international-ces-entreprises-francaises-qui-mangent-dans-la-main-de-trump.html">Oui, votre assureur Axa pourrait bloquer vos remboursements sur ordre de Washington</a><a href="#article-oui-votre-assureur-axa-pourrait-bloquer-vos-remboursements-sur-ordre-de-washingtonhttpswwwclubiccomdossier608725axamshinternationalcesentreprisesfrancaisesquimangentdanslamaindetrumphtml" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#Europe #Politique #USA #Tech</p>
<p>Nicolas Guillou, magistrat français à la Cour pénale internationale (CPI), décrit pourquoi il n&#39;a plus de remboursement de sa mutuelle Axa depuis qu&#39;il a été ajouté sur la liste OFAC (qui ne contient globalement que des terroristes ou coupable de crime contre le droit humain) pour avoir signé un mandat d&#39;arrêt contre Benyamin Nétanyahou. Axa n&#39;a aucune contrainte légale à appliquer ici des sanctions liées à la liste OFAC quand Guillou va la pharmacie de son quartier ou chez son médecin, mais dans le doute de représaille américaine, ils choisissent volontairement de ne plus rendre le service pour lequel Guillou paie. </p>
<p>Du fait que les entreprises choisissent majoritairement des boîtes américaines pour héberger services et données entraînent une dépendance aux USA, quand bien même la localisation physique est en Europe. Du fait que des entreprises aient une part non négligeable de leur business aux USA entraînent une dépendance aux USA. </p>
<p>Là où je ne suis pas d&#39;accord : on a le choix de travailler ou pas avec des acteurs américains, et s&#39;il manque une offre sur un service, on a des acteurs en Europe pour la construire avec eux plutôt que payer pour l&#39;amélioration de la version américaine dudit service. </p>
<p>Là on cite Axa mais c&#39;est vrai pour toutes les boîtes qui ont une dépendance avec les USA. Et pour moi toutes ces boîtes sont en risques à cause de ça. </p>
<p>La technologie c&#39;est politique. Le business c&#39;est politique. Tout est politique. Et si on veut garder une certaine latitude de liberté, il faut choisir avec qui on bosse. </p>
<h3 id="article-lemergence-dun-librofascisme--denis-szalkowskihttpswwwdsfcnetosslemergencedunlibrofascisme"><a href="https://www.dsfc.net/oss/l-emergence-d-un-librofascisme/">L’émergence d’un librofascisme — Denis Szalkowski</a><a href="#article-lemergence-dun-librofascisme--denis-szalkowskihttpswwwdsfcnetosslemergencedunlibrofascisme" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#DINUM #Open-source #Open-Source #Souveraineté #France #Linux #KDE #OS</p>
<p>Je ne connais pas l&#39;auteur personnellement mais ça fait une grosse dizaine d&#39;années que je le lis et donc je commence à connaître le personnage public : un en titinet troll, avec des astuces techniques qui viennent de l&#39;expérience, des raisonnements qui tiennent la route mais souvent des conclusions avec lesquels je suis rarement d&#39;accord, accompagné de position assez tranché et qui se basent parfois sur du doigt mouillé. Mais lire des avis divergeant est plutôt saint à mon sens pour questionner sa propre réflexion. </p>
<p>Je cite le premier paragraphe :</p>
<blockquote>
<p>J’ai toujours été dans une démarche d’éducation populaire en ce qui concerne Linux et le logiciel libre. Je n’ai jamais eu de chapelle, d’approche identitaire, contrairement à une grande majorité de libristes. Cette vision identitaire, je l’ai ressentie d’abord avec les debianœuds, puis avec des stagiaires ayant jeté leur dévolu sur Gentoo au milieu des années 2000. Debian n’était pas assez compliqué pour eux. Il leur fallait être des hommes, des vrais. En entendant parler de NixOS, là, je suis tombé des nues quand j’ai vu la complexité non feinte du gestionnaire de paquets. J’ai cru revenir 20 ans en arrière, voire plus.</p>
</blockquote>
<p>Je ne vais pas mentir, je fais partie des libristes qui défendent une vision &quot;identitaire&quot; du logiciel libre : je crois au libre pas par pragmatisme mais par conviction que c&#39;est par le logiciel libre qu&#39;on rendra les gens maîtres de leur usage, de là à parler d&#39; &quot;identité&quot; je ne sais pas par contre mais passons.</p>
<p>Vous vous en doutez je n&#39;ai pas non plus connu ses stagiaires qui ont préféré Gentoo à Debian début 2000, mais il y a sûrement de bonne raison de choisir Gentoo, et quand bien même c&#39;était pour sa complexité (je maîtrise peu Gentoo mais de mémoire c&#39;est une distribution avec un gestionnaire de paquet qui compile votre système, du Kernel aux outils graphiques) ils ont dû apprendre énormément de chose à l&#39;utiliser. </p>
<p>Parler d&#39;un retour 20 ans en arrière au sujet de NixOS est pour moi une très très grosse blague par contre 🤣 (mais je vous explique plus loin en quoi c&#39;est risible)</p>
<p>Je cite le paragraphe suivant :</p>
<blockquote>
<p>Je me suis restreint désormais à deux distributions Linux : Fedora et Debian Testing. Elles disposent toutes deux d’un installeur graphique offrant cette possibilité au plus grand nombre d’utiliser Linux. Une fois installées, leur gestionnaire de paquets s’interface très simplement avec Discover sous KDE. Un vrai bonheur pour l’utilisateur ou pour l’informaticien qui n’a pas envie de se casser la tête sur sa machine personnelle après sa journée de turbin !</p>
</blockquote>
<p>Monsieur Szalkowski nous expose qu&#39;il se limite à Fedora (au vu de ses publications et de son discours, on parle de la version de base, pas des variantes CoreOS ou Atomic) et Debian Testing. Et que c&#39;est beaucoup mieux du fait de l&#39;installateur graphique et Que ça demande beaucoup moins d&#39;effort à maintenir le soir après le travail quand on est un particulier. </p>
<p>Ok très bien mais ce n&#39;est pas vraiment la cible de Securix (distribution durçi) et Bureautix (distribution agent) <a href="https://www.clubic.com/dossier-609418-securix-et-bureautix-voici-a-quoi-ressemble-vraiment-le-linux-qui-va-remplacer-windows-en-france.html">les distributions Linux basés sur NixOS proposés par la DINUM</a>. La première vise à priori les ministères et personnels manipulant des données de niveau secret ou supérieur, la seconde le reste des agents de l&#39;Etat de la secrétaire de mairie aux ministres. Mais à aucun moment il n&#39;est prévu de leur demander d&#39;installer ou administrer leur machine individuellement.</p>
<p>NixOS c&#39;est quoi ? C&#39;est une distribution qui se base que le gestionnaire de paquet <code>nix</code> qui vise à rendre le plus atomique possible et le plus replicable possible les mises à jours et installations de paquet. L&#39;idée (en très grosse maille, y&#39;a beaucoup à en dire) c&#39;est que tout ce qui est installé le sera dans un volume read only, chaque paquet individuellement, puis <code>nix</code> va créer une sorte d&#39;image de votre nouveau système en jouant que des liens et des variables d&#39;environnements avant de basculer sur cette image, la précédente restant en présente sur la machine permettant de revenir sur une version précédente au besoin. Pour garantir la réplicabilité, <code>nix</code> impose de tout déclarer dans des fichiers de configuration plutôt que de multiplier les appels à lignes de commandes. </p>
<p>Pourquoi c&#39;est parfaitement adapté ici ? L&#39;équipe informatique d&#39;un ministère pourra déployer / maintenir / administrer tout le parc sous sa responsabilité simplement en poussant dans un dépôt git la nouvelle version de la configuration NixOS avant de la pousser sur les différents postes automatiquement, <code>nix</code> va garantir l&#39;application de la mise à jour. De plus si une erreur survient un retour arrière est garantie pour ne pas bloquer les agents.</p>
<p>C&#39;est complètement la logique DevOps qu&#39;on retrouve là. Celle qui est née à la suite du raz le bol de toute la filière de gérer en clic-clic ou en configuration individuelle chaque serveur dont on avait besoin. Vouloir gérer tout le parc des machines des agents de l&#39;Etat via une logique as-code et uniforme est purement pragmatique à mon sens : c&#39;est moins coûteux en temps, en effort et en argent. </p>
<p>Troisième paragraphe :</p>
<blockquote>
<p>A l’occasion de la publication de mes billets et vidéos sur tout le mal que je pensais du choix de NixOS fait par la DINUM, j’ai à nouveau pu me frotter à des rageux et des haters identitaires. Je les ai bananés des commentaires. De simples commentateurs vautrés dans un anonymat de pacotille qui, souvent, se déclarent contributeurs, incapables de partager par vidéo ou par blog interposés leurs compétences de manière didactique et d’agir dans une démarche d’éducation populaire ! Ce qu’ils recherchent, c’est la complexité. Ils veulent se rendre indispensables, recherchant la technique pour la technique. Leur jeunesse les prive de la mémoire et des raisons de l’émergence de la micro-informatique au milieu des années 80. Ce sont aujourd’hui les mêmes causes qui poussent les entreprises à adopter Azure ou AWS. Les collectivités, les entreprises ne veulent plus d’informaticiens qui se complaisent et se vautrent dans la complexité. Continuez ainsi, chères et chers amis, et vous finirez par perdre votre boulot, tant le discours que vous portez est antinomique avec les besoins des entreprises.</p>
</blockquote>
<p>Autant je condamne le harcèlement en ligne et les haters, autant je n&#39;ai pas vu les commentaires, donc je ne me permettrais pas de dire s&#39;il s&#39;agit bien de haters ou d&#39;un Denis qui prend mal qu&#39;on ne soit pas d&#39;accord avec lui avec un discours qui manque de recul 🤷‍♂️ (même si je suis enclain à le croire quand il parle de harcèlement)</p>
<p>En tout cas, je suis en désaccord total avec &quot;Ce qu’ils recherchent, c’est la complexité.&quot; (qui fait écho au premier paragraphe et ses stagiaires sous Gentoo comme si les équipes de la DINUM étaient constitués d&#39;étudiants de 20 piges). Comme expliqué juste avant : on est pour moi à un choix qui se justifie techniquement et qui comme le choix de partir vers un cloud comme Azure ou AWS implique une phase de migration coûteuse et un peu complexe (on va pas se mentir : migrer le parc de machine de Windows à NixOS ne va pas se faire d&#39;un claquement de doigts), pour gagner en fiabilité et simplicité dans un second temps. On peut critiquer les choix qui ont été faits, mais je vois un vrai pragmatisme ici. Quand bien même on est face à une distribution avec un installateur en ligne de commande (qu&#39;on ne verra de toutes façons sûrement jamais vu qu&#39;on passera par un outil d&#39;installation automatisé, comme on fait avec les postes Windows sur lesquels on déploie des images de l&#39;OS prêt à l&#39;emploi et pré-configuré). </p>
<p>Je saute le paragraphe 4 qui n&#39;apporte rien de plus qu&#39;une répétition du postulat : le choix du logiciel libre c&#39;est pour l&#39;argent et &quot;Les éléments de langage autour de cette distribution à l’approche qualifiée de déclarative et reproductible, s’apparentant fortement à du nudge, semblent avoir marqué les esprits. […] Jeunes gens, tâchez d’exprimer une pensée autonome.&quot; (encore une fois, la DINUM qui n&#39;est composé que d&#39;une armée d&#39;étudiants-stagiaire sans expérience) </p>
<p>Ensuite sur le paragaphe 5 :</p>
<blockquote>
<p>Sur Fedora, j’ai pu lire de bien curieux commentaires frisant avec un syllogisme de bas étage. Fedora, c’est Red Hat. Red Hat, c’est IBM. IBM, c’est les États-Unis. Et donc Fedora ne peut pas s’inscrire dans le choix d’une distribution souveraine. Transposons. NixOS est hollandaise. La Hollande fait partie de l’OTAN. L’OTAN est dirigé par les États-Unis. Donc NixOS ne peut pas être une distribution souveraine. Avouez que les deux raisonnements sont tout autant stupides l’un que l’autre. Dois-je encore consommer de la sauce hollandaise si je veux rester souverain dans ma cuisine ? J’y réfléchis très sérieusement. ;+)</p>
</blockquote>
<p>Je passe la blague sur la cuisine en fin de paragraphe qui est hors propos (c&#39;est pas mon humour mais chacun son humour c&#39;est pas le sujer et je n&#39;ai pas de critique / réponse ici). Par contre je suis ici d&#39;accord avec Denis : que Fedora soit supportée par une entreprise américaine n&#39;est pas un sujet. C&#39;est une distribution open source, quand bien même on viendrait à être coupé des USA, un fork de Fedora verrait le jour en Europe et il suffirait de migrer. Particulièrement vrai si au lieu de NixOS c&#39;est Fedora Silverblue (ou une autre variante Atomic) de Fedora qui avait été choisie : rpm-ostree et flatpak comme socle au lieu de yum/dnf pour obtenir des garanties d&#39;atomicité et reproductibilité du même genre que NixOS mais avec une approche différente techniquement parlant. Mais à priori les équipes de Fedora aussi possèdent une armée d&#39;étudiant-stagiaire qui cherchent la complexité 🤷‍♂️</p>
<p>Le dernier paragraphe :</p>
<blockquote>
<p>Ni les Russes, ni les Chinois, ni les Brésiliens ne se sont embarrassés de savoir si Fedora – la distribution de Monsieur et Madame Torvalds – ou Debian étaient deux représentants du soft power américain, au même titre que pouvaient l’être Maryline Monroe et Elvis Presley. A quel titre, ces populations « indigènes » des contrées lointaines auraient-elles fait le choix de la confidentialité pour se priver du travail de centaines, de milliers d’ingénieurs, d’universitaires et de quelques geeks en sandalettes, en s’agrégeant aux projets… américains ? Sous quels brevets sont fabriqués nos processeurs ? Le choix de NixOS est, selon moi, purement identitaire et donc idéologique. Et je ne vois pas bien ce que l’idéologie a à voir avec le logiciel libre. J’y sens, pour ma part, à tort ou à raison, le relent de l’émergence d’un librofascisme auquel nous devons opposer de toutes nos forces les pratiques d’éducation populaire et de mise à disposition de Linux et des logiciels libres au plus grand nombre.</p>
</blockquote>
<p>L&#39;origine de la distribution n&#39;est pas un sujet comme j&#39;ai dit (quoi que, j&#39;aurais peut-être à y redire si ça venait d&#39;une boîte comme Palantir ou de la CIA, ou autre organisme d&#39;espionage / surveillance mais passons), que Fedora soit la distribution préférée de Linus Torvald (le créateur de Linux) non plus. Au passage Linus utilise un vieux fork patché d&#39;une version allégé d&#39;Emacs, donc on devrait peut-être l&#39;immiter aveuglément ? 🤔 (non, Linus dit lui-même qu&#39;il fait ça purement par habitude pas par pragmatisme et de pas faire comme lui) </p>
<p>Je ne vais pas me répéter : arguer l&#39;idéologie ici c&#39;est au mieux de l&#39;ignorance au pire d&#39;une volonté de désinformation ici. </p>
<p>Je ne pensais pas forcément parler de Securix ou Bureautix, en tout cas pas avant de voir émerger le plan de déploiement (perso c&#39;est plutôt ça qui m&#39;intéresse face au choix de la distribution). Ça ne va pas m&#39;empêcher de continuer à lire les billets de monsieur Denis Szalkowski, car j&#39;y vois un intérêt technique. Par contre ça me conforte dans mon idée qu&#39;on serait rarement d&#39;accord au quotidien que ce soit au travail ou en termes de vision, et c&#39;est pas bien grave, on a chacun notre vie, notre vécu et nos convictions, tout ce qu&#39;on se doit c&#39;est du respect à mon avis. </p>
<h3 id="article-odf-est-lavenir-ooxml-le-passe--linuxfrorghttpslinuxfrorgnewsodfestlavenirooxmllepasse"><a href="https://linuxfr.org/news/odf-est-l-avenir-ooxml-le-passe">ODF est l’avenir, OOXML le passé - LinuxFr.org</a><a href="#article-odf-est-lavenir-ooxml-le-passe--linuxfrorghttpslinuxfrorgnewsodfestlavenirooxmllepasse" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#Microsoft</p>
<p>Je cite un bout sur OOXML :</p>
<blockquote>
<p>Le format OOXML, ou Office Open XML, n’a pas été conçu dans un souci d’interopérabilité, mais pour répondre à un objectif très précis : encoder les formats binaires de Microsoft Office en XML de manière à permettre à Microsoft de prétendre respecter la norme sans pour autant renoncer à son emprise sur les utilisateurs par le biais d’un verrouillage technologique.</p>
<p>Cette genèse n’est pas de l’histoire ancienne, mais remonte à la période comprise entre 2006 ‒ par pure coïncidence, l’année où le format ODF a été approuvé par l’ISO ‒ et 2008, année de l’événement grotesque connu sous le nom de « Ballot Resolution Meeting » (réunion de résolution des votes), qui a conduit à l’approbation d’OOXML par l’ISO et qui est consignée dans toutes les versions de la spécification.</p>
<p>OOXML Transitional, la variante que presque tous les documents Microsoft Office utilisent en pratique, et la seule disponible aujourd’hui, est explicitement définie comme une couche de compatibilité avec les anciens formats binaires (les, désormais oubliés, DOC, XLS et PPT, qui n’étaient rien d’autre que l’enregistrement de la mémoire de travail sur le disque), et contient des milliers d’éléments non documentés, d’exceptions spécifiques au format et de références à des systèmes Microsoft hérités qu’aucun tiers ne peut reproduire intégralement.</p>
<p>La spécification elle-même reconnaît que les fichiers Transitional peuvent contenir des éléments dont le comportement est « hérité » et dont l’affichage correct nécessite une connaissance des systèmes propriétaires de Microsoft. En bref, pour implémenter correctement OOXML Transitional, il faut décoder trente ans d’histoire de Microsoft Office, ce que personne, à l’exception de Microsoft, ne peut faire, et que personne ne pourra jamais faire.</p>
<p>En ce sens, choisir OOXML n’est pas un pari mais un choix rétrograde, parce que le format n’est ouvert qu’en apparence ‒ mais il suffit de très peu, d’un peu de bonne volonté, pour se rendre compte qu’il est complètement fermé ‒ et a été conçu pour être un mécanisme de verrouillage.</p>
</blockquote>
<p>Je crois que tout est dit ! Je savais que OOXML (docx, xlsx, pptx, etc.) c&#39;était de la camelote, mais je savais pas quel point… Clairement faut arrêter d&#39;utiliser ces machins… Et il me semble que même la suite MS Office peut utiliser les formats ODF donc pourquoi on continue de s&#39;infliger des saletés pareilles ? Certains aiment vraiment tendre le bâton pour se faire battre 😬 </p>
<p>Crédit photo : Générée via Mistral AI avec le prompt suivant : </p>
<blockquote>
<p>Une scène chaleureuse et immersive, inspirée par l’esthétique poétique de Studio Ghibli, représentant un bureau de travail en bois clair et vieilli, baigné d’une lumière dorée et tamisée, comme un après-midi d’automne. Au centre, une silhouette stylisée (style anime Ghibli : traits doux, visage non détaillé, vêtements amples et confortables) est assise en tailleur sur un tapis épais, absorbée par la lecture d’un journal tech futuriste. Le journal est ouvert, ses pages légèrement froissées, avec des titres en en-tête calligraphiés à la main : &quot;Frontend&quot;, &quot;Backend&quot;, &quot;IA&quot;, &quot;Sécurité&quot;, et &quot;Vie privée&quot;. Les pages brillent d’un halo bleu pâle, évoquant des lignes de code et des schémas techniques qui s’animent discrètement, comme par magie.
Autour d’elle, des piles de magazines et de carnets s’empilent de manière désordonnée mais harmonieuse. Certains sont ouverts, révélant des extraits d’articles, des croquis de frameworks (représentés par des icônes génériques : un crochet pour le frontend, un engrenage pour le backend, un cerveau pour l’IA, un cadenas pour la sécurité, et un masque pour la vie privée), ou des diagrammes de réseaux de neurones dessinés à la main. Un écran transparent et flottant (style holographique, mais avec un cadre en bois sculpté) affiche des flux d’informations en temps réel : des graphiques de données, des alertes de sécurité, et des extraits de code, le tout dans un style doux et organique, comme intégré à la scène.
En arrière-plan, une grande fenêtre donne sur un paysage urbain nocturne style Ghibli : des bâtiments aux formes arrondies, des lanternes suspendues, et des néons bleutés qui reflètent des motifs de code binaire sur les murs. Une tasse de thé fumant et un petit robot de bureau (inspiré des créatures de Ghibli, comme un mélange entre un Totoro miniature et un assistant tech) observent la scène avec curiosité.
À droite, un panda roux (ton animal préféré) est lové sur un coussin, les yeux mi-clos, comme s’il écoutait attentivement. Il ne doit pas dépasser le tiers de la hauteur de l’image et est positionné en bas à droite, légèrement tourné vers le centre, avec une queue soyeuse enroulée autour de lui.
L’ambiance est à la fois cosy, onirique et high-tech : les couleurs sont douces (beiges, bleus pâles, oranges chauds), avec des contrastes subtils pour mettre en valeur les éléments tech. Les détails sont soignés, avec des textures visibles (grain du bois, tissu du tapis, pelage du panda), et une lumière qui crée des jeux d’ombres chaleureuses. Le tout respire la sérénité et l’inspiration, comme un moment suspendu entre la magie et la technologie.</p>
</blockquote>
]]></content:encoded>
      <dc:creator><![CDATA[Anthony Pena]]></dc:creator>
      <media:content medium="image" url="https://anthonypena.fr/img/cover.min.jpg"/>
    </item>
    <item>
      <title><![CDATA[Un VPN ça ne sert à rien]]></title>
      <guid isPermaLink="false">2026/04/28/un-vpn-ca-ne-sert-a-rien</guid>
      <description><![CDATA[<p>On voit beaucoup d&#39;influenceur vous vendre des VPNs depuis des années pour &quot;votre sécurité&quot; ou pour …</p>
]]></description>
      <link>https://anthonypena.fr/2026/04/28/un-vpn-ca-ne-sert-a-rien/index.html</link>
      <category><![CDATA[Internet]]></category>
      <category><![CDATA[Sécurité]]></category>
      <category><![CDATA[Avis]]></category>
      <pubDate>Tue, 28 Apr 2026 07:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>On voit beaucoup d&#39;influenceur vous vendre des VPNs depuis des années pour &quot;votre sécurité&quot; ou pour tricher sur votre géo-localisation pour payer des trucs moins chers. En vrai, c&#39;est pas forcément toujours le bon plan voir même pas souhaitable, je vous explique.</p>
<blockquote>
<p>Note : je vais dans cet article dans une direction qui va à l&#39;opposé de ce que la plupart des gens vous diront, mais je sais que je ne suis pas le seul à avoir ce point de vue. Par exemple on retrouve une vidéo de <a href="%5Bhttps://youtu.be/ckZGQ5cLIfs">MiCode</a> qui parle aussi du sujet.</p>
</blockquote>
<h2 id="article-vpn--kezako-">VPN ? Kézako ?<a href="#article-vpn--kezako-" class="anchor" aria-label="permalink">🔗</a></h2>
<p>On parle partout de VPN avec plein de promesse, mais concrètement c&#39;est quoi ?</p>
<p>Si on reste assez haut niveau : VPN = Virtual Private Network ou Réseau Privé Virtuel. Donc l&#39;idée c&#39;est de simuler le fait d&#39;avoir plusieurs machines dans le même réseau privé (comprendre = comme si vous étiez chez vous / à votre entreprise, avec toutes les machines branchées sur le même routeur), pour garantir un certain niveau de confidentialité.</p>
<p>Et techniquement, ça fonctionne comment ? C&#39;est assez simple en fait : une brique logicielle prend chaque paquet réseau qui devrait sortir de votre machine (par exemple : votre laptop alors que vous êtes dans un hôtel), chiffre ce paquet, l&#39;envoie à une autre machine ailleurs sur Internet (par exemple : votre Freebox qui est chez vous (oui les Freebox fournissent un VPN gratuitement)) et cette machine va ensuite déchiffrer le paquet réseau, l&#39;envoyer elle sur Internet (en changeant ce qu&#39;il faut dans le paquet pour faire comme si c&#39;était cette machine qui voulait envoyer le paquet réseau), puis une fois la réponse reçue, chiffre la réponse pour l&#39;envoyer à votre laptop qui va déchiffrer lui aussi.</p>
<p>Donc en gros : vous masquez votre activité en ligne (en partie en tout cas) à n&#39;importe qui entre vous (dans l&#39;exemple au-dessus : votre laptop) et votre serveur VPN (dans l&#39;exemple au-dessus : votre Freebox), mais à partir de votre serveur VPN vous êtes à nouveau sur Internet. </p>
<p>J&#39;imagine que vous vous dites &quot;Mais NordVPN / CyberGhost VPN / Proton VPN ! C&#39;est pas comme ça que ça marche ! ça change ma géo-localisation et protège ma connexion !&quot;. Alors oui mais non. Si on prend NordVPN (pour les autres c&#39;est pareil) : votre laptop va chiffrer les requêtes vers Internet pour les envoyer à un serveur NordVPN, on peut imaginer que vous ayez choisi NordVPN Belgique parce que vous êtes fan de F1 (comment ça j&#39;ai vu trop de pub pour des VPN ?) donc un serveur en Belgique va être choisi, ensuite ce serveur va lire tout ce que vous lui envoyez pour ajuster le contenu avant de l&#39;envoyer sur Internet (sans vraie protection en plus que si vous aviez fait la même chose depuis votre laptop du coup), puis il vous renverra la réponse qu&#39;on lui aura donnée, faisant croire que vous vous connectez depuis la Belgique de facto.</p>
<h2 id="article-pouvezvous-faire-confiance-a-votre-serveur-vpn-">Pouvez-vous faire confiance à votre serveur VPN ?<a href="#article-pouvezvous-faire-confiance-a-votre-serveur-vpn-" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Ce qu&#39;il faut bien comprendre c&#39;est qu&#39;utiliser un VPN veut dire déléguer sa connexion à une autre machine. Si vous êtes le propriétaire de la machine (au sens = elle est chez vous) vous pouvez à priori lui faire confiance (sauf si vous n&#39;avez aucune confiance en votre FAI (Fournisseur d&#39;Accès Internet)). Si c&#39;est le serveur de votre entreprise, pour votre machine professionnelle à priori c&#39;est plutôt sécurisé (pour du pro en tout cas, ça dépend de beaucoup d&#39;autres paramètres). </p>
<p>Si c&#39;est un serveur commercial, c&#39;est un autre sujet à mon sens : vous n&#39;avez comme garantie que les promesses que l&#39;entreprise vous fait, et donc vous faites confiance à la machine de quelqu&#39;un d&#39;autre pour être plus fiable que votre connexion. Vous faites aussi confiance à l&#39;entreprise de ne pas stocker vos données, vous leur faites confiance sur le fait qu&#39;ils n&#39;ont pas de mécanique pour analyser votre trafic, vous leur faites aussi confiance sur le fait qu&#39;ils font uniquement office de VPN et qu&#39;ils ne font pas plus sur le réseau sans vous le dire.</p>
<p>Le but d&#39;utiliser un VPN c&#39;est d&#39;ajouter un niveau de confidentialité sur votre connexion, donc c&#39;est à vous de voir si la dite couche est plus fiable que votre connexion. Si vous êtes chez vous j&#39;aurais tendance à dire qu&#39;utiliser un VPN pour la sécurité est une erreur. Si vous êtes dans un hôtel ou un fast food avec un grand M jaune, ça peut se discuter car vous serez sur des réseaux publics avec un très faible contrôle sur les utilisateurs connectés, mais à voir.</p>
<h2 id="article-estce-que-tout-passe-par-le-vpn-">Est-ce que tout passe par le VPN ?<a href="#article-estce-que-tout-passe-par-le-vpn-" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Imaginons que vous êtes dans un cas où le VPN est bien utile. Il faut s&#39;assurer qu&#39;on fait bien passer l&#39;intégralité de son trafic par le VPN.</p>
<p>Par exemple si vos appels HTTP passent par le VPN mais que vos requêtes DNS (résolution des noms de domaines) passent sur le réseau classique, on peut savoir tous les sites que vous allez consulter. Il arrive aussi que votre configuration fasse qu&#39;en cas de rupture de session VPN, vous arriviez sur un fallback sans VPN et parfois silencieusement…</p>
<p>En fait ça dépend énormément de ce que vous cherchez dans le VPN : si c&#39;est la sécurité des données, la partie DNS n&#39;est pas très importante car ça ne donnera aucune information de données, par contre si vous cherchez l&#39;anonymat / pseudo-anonymat, vous voulez que 100% de votre trafic passe par le VPN.</p>
<h2 id="article-et-la-securite-sans-vpn-ca-existe-">Et la sécurité sans VPN ça existe ?<a href="#article-et-la-securite-sans-vpn-ca-existe-" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Déjà qu&#39;on soit clair : on a disposition énormément de solution de sécurité sans avoir besoin de passer par du VPN.</p>
<p>La première brique pour moi à ne pas oublier c&#39;est le HTTPS, le S étant important. En effet le S de HTTPS indique aujourd&#39;hui qu&#39;on va utiliser du chiffrement TLS pour les échanges. Clairement ce n&#39;est pas parfait, il est toujours possible de faire du Man In The Middle en ciblant quelqu&#39;un, on sait que si on capture un paquet TLS, il est possible de le déchiffrer en cassant la clé avec une grosse infrastructure ou beeeeeaaaaauuuucoup de temps, mais soyons honnêtes : on est pas si intéressant que ça individuellement pour que quelqu&#39;un prenne le temps de faire ça spécialement pour nous.</p>
<p>Si vraiment vous voulez augmenter votre anonymat en ligne, vous pouvez passer par le réseau Tor. Le plus simple c&#39;est d&#39;utiliser <a href="https://www.torproject.org/download/">Tor Browser</a>, une version de Firefox modifiée pour passer par le réseau Tor au maximum et accéder à Internet en faisant passer sa connexion chiffrée par plusieurs nœuds intermédiaires avant de rejoindre Internet de sorte que l&#39;origine de la requête soit presque intraçable (presque parce qu&#39;il y a des cas où on peut désanonymiser le trafic Tor). C&#39;est gratuit, ça fonctionne bien, vous ne choisissez pas explicitement la localisation du nœud de sortie (donc la localisation qui sera affichée pour le serveur), c&#39;est un choix au hasard parmi les nœuds du réseau, mais ça fonctionne très bien !</p>
<h2 id="article-le-vpn-en-entreprise-est-un-antipattern-a-mon-avis">Le VPN en entreprise est un anti-pattern à mon avis…<a href="#article-le-vpn-en-entreprise-est-un-antipattern-a-mon-avis" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Ça fait 10 ans que je travaille en entreprise. Ça fait 10 ans que je constate la même chose : on sécurise généralement très bien l&#39;entrée du réseau privé de l&#39;entreprise mais une fois qu&#39;on est dans le réseau interne il n&#39;y a presque plus de protection…</p>
<p>On voit parfois du HTTPS en interne mais plus d&#39;authentification &quot;parce qu&#39;on est dans le réseau interne&quot;. Parfois même le HTTPS n&#39;est pas là en interne… Parfois on voit du filtrage IP sur les plages d&#39;IP interne pour ouvrir les vannes sans plus de restriction…</p>
<p>Du coup il se passe quoi si quelqu&#39;un infiltre votre réseau interne ? C&#39;est simple : il a le champ libre pour faire ce qu&#39;il veut… Et accéder au réseau interne, ça va de physiquement se brancher sur une prise Ethernet dans les bureaux ou la wifi, à obtenir le mot de passe VPN d&#39;un utilisateur et se connecter à distance.</p>
<p>Mon avis est très clair : Zero Trusted Network / Aucun Réseau de Confiance. Partez du principe que vous ne pouvez avoir confiance en aucun réseau, que chaque connexion doit être sécurisé, contrôlé et traçable, peu importe la source.</p>
<blockquote>
<p>Note : il y a même des avantages métiers à fonctionner en tout authentifié si c&#39;est bien fait : vous pouvez savoir qui sont vos utilisateurs / consommateurs et donc créer des communications au besoin.</p>
</blockquote>
<h2 id="article-conclusion">Conclusion<a href="#article-conclusion" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Ici je ne vais même pas abordé les contraintes légales et/ou contractuels autour de l&#39;utilisation des VPNs (typiquement : en théorie vous n&#39;avez pas le droit d&#39;utiliser un VPN pour vous relocaliser et payer moins cher un service / accéder à un contenu géo-bloqué).</p>
<p>En tout cas je voulais parler du sujet depuis assez longtemps, j&#39;ai posé mon avis, vous n&#39;êtes pas obligé de le partager. Par contre si vous avez un avis différent avec des arguments, je suis complètement ouvert et intéressé pour échanger sur le sujet, et pourquoi pas même mettre à jour cet article !</p>
<p>Sources :</p>
<ul>
<li><a href="https://youtu.be/ckZGQ5cLIfs">NordVPN vous ment. (non sponsorisé)</a></li>
</ul>
<p>Crédit photo : Générée via Mistral AI avec le prompt suivant : </p>
<blockquote>
<p>A cozy wooden desk bathed in soft golden afternoon light, featuring futuristic technical magazines and a holographic screen with a wooden frame displaying animated lines of code. In the bottom right corner, a red panda is curled up on a cushion, gazing at a semi-transparent tunnel extending from the screen outward. The tunnel is a blend of circuit board patterns and tree branches, symbolizing the duality of technology and nature. The scene is filled with 8-10 minimalist red, orange, and yellow maple leaves floating gently around, creating a warm, autumnal atmosphere. The art style is inspired by Studio Ghibli, with soft lines, detailed textures, and a poetic, dreamy ambiance.&quot;</p>
</blockquote>
]]></content:encoded>
      <dc:creator><![CDATA[Anthony Pena]]></dc:creator>
      <media:content medium="image" url="https://anthonypena.fr/img/cover.min.jpg"/>
    </item>
    <item>
      <title><![CDATA[Reprendre le contrôle de vos dépendances NPM]]></title>
      <guid isPermaLink="false">2026/04/22/reprendre-le-controle-de-vos-dependances-npm</guid>
      <description><![CDATA[<p>Je vois souvent des gens ne pas maitriser l&#39;usage de NPM au quotidien. Des choses basiques, mais imp…</p>
]]></description>
      <link>https://anthonypena.fr/2026/04/22/reprendre-le-controle-de-vos-dependances-npm/index.html</link>
      <category><![CDATA[Frontend]]></category>
      <category><![CDATA[Backend]]></category>
      <category><![CDATA[JavaScript]]></category>
      <category><![CDATA[TypeScript]]></category>
      <pubDate>Wed, 22 Apr 2026 07:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>Je vois souvent des gens ne pas maitriser l&#39;usage de NPM au quotidien. Des choses basiques, mais importantes, surtout quand il s&#39;agit de se débarrasser d&#39;une faille de sécurité dans une dépendance transitive. Je ne suis pas expert NPM, mais après quasi 10 ans à l&#39;utiliser au quotidien, j&#39;ai appris quelques trucs qui servent bien, et j&#39;en apprends encore !</p>
<h2 id="article-cest-quoi-une-dependance-">C&#39;est quoi une dépendance ?<a href="#article-cest-quoi-une-dependance-" class="anchor" aria-label="permalink">🔗</a></h2>
<p>En général, on répondra &quot;tout ce qui est listé dans le <code>package.json</code>&quot;. Et ce n&#39;est pas faux en soi. Mais c&#39;est incomplet en théorie.</p>
<p>Déjà si vous faites du Node, vous avez au strict minimum deux dépendances : Node et <code>npm</code> (ou peut-être <code>yarn</code> ou <code>pnpm</code>, mais au fond vous avez quand même <code>npm</code> sur votre machine quoi qu&#39;il arrive, et je ne vais pas couvrir les spécificités de <code>yarn</code> (que je ne maitrise pas assez) et <code>pnpm</code> (qui est trop intéressant pour juste faire un paragraphe dessus)). Sans ces deux outils, vous ne pouvez pas travailler au sens compiler / exécuter votre application. Donc vous dépendez de ces deux outils. Je ne vais pas rentrer plus dans le détail mais juste : pensez à mettre à jour votre version Node régulièrement, particulièrement avec le changement de <a href="/2026/04/08/revue-de-presse-avril/#article-evolving-the-nodejs-release-schedulehttpsnodejsorgenblogannouncementsevolvingthenodejsreleaseschedule">cycle de release</a>.</p>
<p>L&#39;autre aspect qui manque c&#39;est la notion de dépendance transitive. On qualifie de dépendance transitive une dépendance d&#39;une de nos dépendances. Prenons un exemple simple : vous avez un projet SolidJS avec Vite, vous installez donc <code>vite-plugin-solid</code>. Vous avez donc dans votre <code>package.json</code> <code>solid-js</code>, <code>vite</code> et <code>vite-plugin-solid</code> qui sont vos dépendances directes, mais <code>vite-plugin-solid</code> dépend de <code>@babel/core</code>, <code>babel-preset-solid</code>, <code>solid-js</code>, <code>solid-refresh</code>, <code>vite</code> et <code>vitefu</code>, et si vous creusez encore vous verrez que <code>babel-preset-solid</code> dépend de <code>@babel/core</code>, <code>babel-plugin-jsx-dom-expressions</code> et <code>solid-js</code>, et on pourrait creuser un peu toutes les dépendances comme ça. Chaque dépendance pouvant dépendre d&#39;une version différente d&#39;une même dépendance (vous pouvez dépendance de <code>solid-js@1.9.12</code>, <code>babel-preset-solid</code> dépendre de <code>solid-js@1.9.11</code>, et <code>babel-preset-solid</code> dépendre de <code>solid-js@1.9.10</code>), ce ne serait pas forcément très stable / recommandé mais c&#39;est possible du point de vue de NPM.</p>
<p>Vous avez donc des dépendances que vous maitrisez et d&#39;autres que vous ne maitrisez pas directement. À priori.</p>
<h2 id="article-visualise-vos-dependances">Visualisé vos dépendances<a href="#article-visualise-vos-dependances" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Commençons par notre <code>package.json</code> :</p>
<pre><code class="hljs language-JSON"><span class="hljs-punctuation">{</span>
  ...
  <span class="hljs-attr">&quot;dependencies&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span>
    <span class="hljs-attr">&quot;solid-js&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;^1.9.5&quot;</span>
  <span class="hljs-punctuation">}</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;devDependencies&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span>
    <span class="hljs-attr">&quot;typescript&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;~5.8.3&quot;</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;vite&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;^6.3.5&quot;</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;vite-plugin-solid&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;^2.11.6&quot;</span>
  <span class="hljs-punctuation">}</span>
<span class="hljs-punctuation">}</span><div aria-hidden="true" class="language-tag">JSON</div>
</code></pre><p>On voit donc 4 dépendances ici.</p>
<p>Maintenant, installons nos dépendances (<code>npm ci</code> si vous avez un <code>package-lock.json</code>, <code>npm i</code> sinon, j&#39;y reviendrais plus tard).</p>
<pre><code>❯ npm ci # si vous n&#x27;avez pas encore de package-lock.json, utilisez npm i ou npm install

added 73 packages in 1m

13 packages are looking for funding
  run `npm fund` for details
</code></pre><p>Et là NPM nous dit avoir installé 73 packages. On est donc bien loin des 4 qu&#39;on voyait plus haut…</p>
<p>Ensuite on va utiliser <code>npm ls</code>.</p>
<pre><code>npm-deps-override@0.0.0 /home/anthony_p/tmp/npm-deps-override
├── solid-js@1.9.12
├── typescript@5.8.3
├── vite-plugin-solid@2.11.12
└── vite@6.4.2
</code></pre><p>C&#39;est logique, on retrouve les dépendances de notre <code>package.json</code>. Allons regarder plus en profondeur :</p>
<pre><code>❯ npm ls --depth 1

npm-deps-override@0.0.0 /home/anthony_p/tmp/npm-deps-override
├─┬ solid-js@1.9.12
│ ├── csstype@3.2.3
│ ├── seroval-plugins@1.5.2
│ └── seroval@1.5.2
├── typescript@5.8.3
├─┬ vite-plugin-solid@2.11.12
│ ├── @babel/core@7.29.0
│ ├── UNMET OPTIONAL DEPENDENCY @testing-library/jest-dom@^5.16.6 || ^5.17.0 || ^6.*
│ ├── @types/babel__core@7.20.5
│ ├── babel-preset-solid@1.9.12
│ ├── merge-anything@5.1.7
│ ├── solid-js@1.9.12 deduped
│ ├── solid-refresh@0.6.3
│ ├── vite@6.4.2 deduped
│ └── vitefu@1.1.3
└─┬ vite@6.4.2
  ├── UNMET OPTIONAL DEPENDENCY @types/node@^18.0.0 || ^20.0.0 || &gt;=22.0.0
  ├── esbuild@0.25.12
  ├── fdir@6.5.0
  ├── UNMET OPTIONAL DEPENDENCY fsevents@~2.3.3
  ├── UNMET OPTIONAL DEPENDENCY jiti@&gt;=1.21.0
  ├── UNMET OPTIONAL DEPENDENCY less@*
  ├── UNMET OPTIONAL DEPENDENCY lightningcss@^1.21.0
  ├── picomatch@4.0.4
  ├── postcss@8.5.9
  ├── rollup@4.60.1
  ├── UNMET OPTIONAL DEPENDENCY sass-embedded@*
  ├── UNMET OPTIONAL DEPENDENCY sass@*
  ├── UNMET OPTIONAL DEPENDENCY stylus@*
  ├── UNMET OPTIONAL DEPENDENCY sugarss@*
  ├── UNMET OPTIONAL DEPENDENCY terser@^5.16.0
  ├── tinyglobby@0.2.16
  ├── UNMET OPTIONAL DEPENDENCY tsx@^4.8.1
  └── UNMET OPTIONAL DEPENDENCY yaml@^2.4.2
</code></pre><p>Le fonctionnement de vite étant d&#39;essayer de s&#39;auto-configurer au maximum, on retrouve beaucoup de dépendances optionnelles. Épurons ces dépendances qui ne sont pas installées pour rendre l&#39;arbre plus lisible</p>
<pre><code>❯ npm ls --depth 1 | grep -v &#x27;UNMET OPTIONAL DEPENDENCY&#x27;
npm-deps-override@0.0.0 /home/anthony_p/tmp/npm-deps-override
├─┬ solid-js@1.9.12
│ ├── csstype@3.2.3
│ ├── seroval-plugins@1.5.2
│ └── seroval@1.5.2
├── typescript@5.8.3
├─┬ vite-plugin-solid@2.11.12
│ ├── @babel/core@7.29.0
│ ├── @types/babel__core@7.20.5
│ ├── babel-preset-solid@1.9.12
│ ├── merge-anything@5.1.7
│ ├── solid-js@1.9.12 deduped
│ ├── solid-refresh@0.6.3
│ ├── vite@6.4.2 deduped
│ └── vitefu@1.1.3
└─┬ vite@6.4.2
  ├── esbuild@0.25.12
  ├── fdir@6.5.0
  ├── picomatch@4.0.4
  ├── postcss@8.5.9
  ├── rollup@4.60.1
  ├── tinyglobby@0.2.16
</code></pre><blockquote>
<p>Note : <code>grep</code> permet de filtrer pour ne garder que les lignes qui contiennent un certain motif, mais si on ajoute l&#39;option <code>-v</code>, on garde les lignes qui ne contiennent pas le motif.</p>
</blockquote>
<p>Rien qu&#39;en ajoutant un niveau de profondeur on est déjà à 20 dépendances, avec <code>solid-js@1.9.12</code> et <code>vite@6.4.2</code> qui taggé comme <code>deduped</code>, c&#39;est à dire identifiées comme déjà résolue et donc n&#39;ont plus besoin d&#39;être résolus (car le package est tiré plus haut dans l&#39;arbre et avec la même version ou une version compatible).</p>
<p>On peut continuer comme ça en augmentant la profondeur affichée. On peut afficher tout l&#39;arbre directement en passant <code>--all</code>. On peut aussi cibler un package précis.</p>
<pre><code>❯ npm ls solid-js                                       
npm-deps-override@0.0.0 /home/anthony_p/tmp/npm-deps-override
├── solid-js@1.9.12
└─┬ vite-plugin-solid@2.11.12
  ├─┬ babel-preset-solid@1.9.12
  │ └── solid-js@1.9.12 deduped
  ├── solid-js@1.9.12 deduped
  └─┬ solid-refresh@0.6.3
    └── solid-js@1.9.12 deduped
</code></pre><p>Ici on voit où la dépendance <code>solid-js</code> est tirée dans l&#39;arbre, la version attendue, si elle est bien dédupliquée comme on s&#39;y attend (ici c&#39;est le cas).</p>
<p>En choisissant <code>solid-js</code> dans un projet SolidJS, on s&#39;attend à le voir. Si vous demande pour <code>esbuild</code> ?</p>
<pre><code>❯ npm ls esbuild 
npm-deps-override@0.0.0 /home/anthony_p/tmp/npm-deps-override
└─┬ vite@6.4.2
  └── esbuild@0.25.12
</code></pre><p>Il n&#39;est pas dans notre <code>package.json</code> pourtant il fait bien partie de l&#39;arbre. Une faille sur <code>esbuild</code> peut donc nous impacter. Et certains me diront qu&#39;<code>esbuild</code> sert uniquement à la compilation donc ne part pas en production. Ce n&#39;est pas aussi simple. Déjà <code>esbuild</code> sera installé sur chaque runner de notre CI, donc à défaut d&#39;infecter nos utilisateurs, on peut impacter notre SI via notre CI ce qui n&#39;est déjà pas terrible. Ensuite on peut se retrouver dans un cas où la faille n&#39;est pas dans <code>esbuild</code> mais dans le code qu&#39;il produit, en effet les outils de compilation vont modifier nos sources et peuvent donc injecter du code non sûr et là ça peut retomber chez les utilisateurs.</p>
<h2 id="article-comment-quon-dit-ce-quon-veut-comme-version-">Comment qu&#39;on dit ce qu&#39;on veut comme version ?<a href="#article-comment-quon-dit-ce-quon-veut-comme-version-" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Déjà il faut comprendre ce qu&#39;on appelle le SemVer ou <strong>Sem</strong>antic <strong>Ver</strong>sioning.</p>
<p>Pour faire très simple : on va définir une version sur trois nombre <code>X.Y.Z</code>. On va appeler X la version majeure, Y la mineure et Z le patch. L&#39;idée va être de se dire qu&#39;une modification qui vient corriger va juste incrémenter le patch, ensuite une nouvelle fonctionnalité qui ne casse rien pour les utilisateurs actuels incrémente uniquement le mineur, et si on casse quelque chose on incrémente le majeur.</p>
<blockquote>
<p>Note : je vous laisse aller voir sur Internet pour tous les détails du SemVer, je n&#39;irai pas plus loin ici. Il reste pas mal de chose à dire : les versions alpha/beta/RC, les versions à quatre nombres, les versionnings alternatifs compatible ou non avec SemVer, etc.</p>
</blockquote>
<p>À partir de là, on se dit qu&#39;on veut parfois dire &quot;je veux strictement cette version&quot;, parfois &quot;je veux bien prendre un nouveau patch mais pas de changement mineur&quot; et de temps en temps &quot;je veux bien tout mettre à jour sauf la majeure&quot;.</p>
<p>Par défaut, si vous faite <code>npm install lodash</code> (pareil si vous faite <code>npm install lodash@latest</code>), NPM va ajouter à votre <code>package.json</code> dans <code>dependencies</code> <code>&quot;lodash&quot;: &quot;^4.18.1&quot;</code> (la dernière version sortie à date). Sauf que là vous avez peut-être mis un doigt dans un système que vous ne vouliez pas avec le <code>^</code> devant la version. En effet <code>^4.18.1</code> veut dire &quot;n&#39;importe quelle version 4.x.x qui est supérieur à 4.18.1&quot;. Donc si vous refaite un <code>npm i</code> dans quelques jours/semaines/mois vous aurez peut-être la version 4.18.1, peut-être une 4.18.2 ou peut-être une 4.45.0. Est-ce que vous vouliez prendre en compte tous ces changements simplement en installant vos dépendances ? Pas sûr (même si, je vous l&#39;accorde : avec <code>lodash</code> on peut normalement mettre à jour les yeux fermés).</p>
<p>Si vous voulez &quot;toujours&quot; tirer la version 4.18.1, il faut retirer le <code>^</code> et refaire un <code>npm i</code> (pour mettre à jour le <code>package-lock.json</code>) ou simplement faire directement <code>npm install lodash --save-exact</code> qui va ajouter au <code>package.json</code> <code>&quot;lodash&quot;: &quot;4.18.1&quot;</code>.</p>
<p>Si vous voulez bien les mises à jours, mais seulement de patch, vous pouvez indiquer <code>&quot;~4.18.1&quot;</code>.</p>
<p>Sauf que là ça ne concerne que les versions qu&#39;on tire directement via notre <code>package.json</code>. Si je veux forcer la version <code>0.27.7</code> d&#39;<code>esbuild</code> je ne peux pas fonctionner comme ça.</p>
<p>En effet si je fais <code>npm i esbuild@0.27.7 --save-exact</code> (la dernière version à date) puis que je regarde l&#39;arbre de dépendance :</p>
<pre><code>❯ npm ls esbuild      
npm-deps-override@0.0.0 /home/anthony_p/tmp/npm-deps-override
├── esbuild@0.27.7
└─┬ vite@6.4.2
  └── esbuild@0.25.12
</code></pre><p>On voit bien que j&#39;ai version <code>0.27.7</code> à la racine de l&#39;arbre, mais sous <code>vite</code> j&#39;ai toujours la version <code>0.25.12</code>. Donc comment on fait ? Déjà on supprime <code>esbuild</code> qui est inutile à la racine du projet <code>npm uninstall esbuild</code>. Puis on va ajouter une section <code>overrides</code> à notre <code>package.json</code> pour forcer partout dans l&#39;arbre une certaine version d&#39;<code>esbuild</code> :</p>
<pre><code class="hljs language-JSON"><span class="hljs-punctuation">{</span>
  ...  
  <span class="hljs-attr">&quot;overrides&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span>
    <span class="hljs-attr">&quot;esbuild&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;0.27.7&quot;</span>
  <span class="hljs-punctuation">}</span>
<span class="hljs-punctuation">}</span><div aria-hidden="true" class="language-tag">JSON</div>
</code></pre><p>Là on fait <code>npm install</code> pour mettre à jour nos dépendances et on regarde notre arbre de dépendance :</p>
<pre><code>❯ npm ls esbuild
npm-deps-override@0.0.0 /home/anthony_p/tmp/npm-deps-override
└─┬ vite@6.4.2
  └── esbuild@0.27.7 overridden
</code></pre><p>Là on voit bien que la version n&#39;est plus la même et c&#39;est indiqué qu&#39;elle est <code>overridden</code> montrant bien que ce n&#39;est pas la version que NPM aurait choisi normalement.</p>
<p>À Noter qu&#39;on peut aller assez loin avec cette mécanique, par exemple :</p>
<pre><code class="hljs language-JSON"><span class="hljs-punctuation">{</span>
  ...  
  <span class="hljs-attr">&quot;overrides&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span>
    <span class="hljs-attr">&quot;esbuild&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;^0.27.0&quot;</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;vite&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span>
      <span class="hljs-attr">&quot;esbuild&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;^0.27.5&quot;</span>
    <span class="hljs-punctuation">}</span>
  <span class="hljs-punctuation">}</span>
<span class="hljs-punctuation">}</span><div aria-hidden="true" class="language-tag">JSON</div>
</code></pre><p>Permet d&#39;indiquer qu&#39;on veut surcharger la version d&#39;<code>esbuild</code> en autorisant n&#39;importe quelle version compatible avec <code>^0.27.0</code> partout dans l&#39;arbre de dépendance sauf dans le sous-arbre de <code>vite</code> où on va viser <code>~0.26.0</code> (en l’occurrence, la branche <code>0.26.x</code> ne contient que la version <code>0.26.0</code> donc NPM n&#39;a pas beaucoup de choix de version). Ici ça ne sert pas à grand-chose mais dans certains cas, ça peut être utile. // TODO</p>
<pre><code>❯ npm ls esbuild
npm-deps-override@0.0.0 /home/anthony_p/tmp/npm-deps-override
└─┬ vite@6.4.2
  └── esbuild@0.26.0
</code></pre><p>Ce n&#39;est pas une erreur de ma part, ici on ne voit plus l&#39;indication <code>overridden</code> alors que la version l&#39;est bien mais passons là-dessus. Par contre on voit bien que notre version est surchargée.</p>
<p>Et si maintenant on ajoute ça ?</p>
<pre><code class="hljs language-JSON"><span class="hljs-punctuation">{</span>
    ...
    <span class="hljs-attr">&quot;overrides&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span>
        ...
        <span class="hljs-attr">&quot;vite-plugin-solid&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span>
           <span class="hljs-attr">&quot;solid-js&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;1.9.4&quot;</span>
        <span class="hljs-punctuation">}</span>
    <span class="hljs-punctuation">}</span>
<span class="hljs-punctuation">}</span><div aria-hidden="true" class="language-tag">JSON</div>
</code></pre><p>Normalement au moment de l&#39;installation vous aurez une erreur du type : </p>
<pre><code>❯ npm i         
npm warn ERESOLVE overriding peer dependency
npm warn While resolving: solid-refresh@0.6.3
npm warn Found: solid-js@1.9.12
npm warn node_modules/solid-js
npm warn   solid-js@&quot;^1.9.5&quot; from the root project
npm warn
npm warn Could not resolve dependency:
npm warn peer overridden solid-js@&quot;1.9.4&quot; (was &quot;^1.3&quot;) from solid-refresh@0.6.3
npm warn node_modules/solid-refresh
npm warn   solid-refresh@&quot;^0.6.3&quot; from vite-plugin-solid@2.11.12
npm warn   node_modules/vite-plugin-solid
npm warn
npm warn Conflicting peer dependency: solid-js@1.9.4
npm warn node_modules/solid-js
npm warn   peer overridden solid-js@&quot;1.9.4&quot; (was &quot;^1.3&quot;) from solid-refresh@0.6.3
npm warn   node_modules/solid-refresh
npm warn     solid-refresh@&quot;^0.6.3&quot; from vite-plugin-solid@2.11.12
npm warn     node_modules/vite-plugin-solid
npm error code ERESOLVE
npm error ERESOLVE could not resolve
npm error
npm error While resolving: vite-plugin-solid@2.11.12
npm error Found: solid-js@1.9.12
npm error node_modules/solid-js
npm error   solid-js@&quot;^1.9.5&quot; from the root project
npm error
npm error Could not resolve dependency:
npm error peer overridden solid-js@&quot;1.9.4&quot; (was &quot;^1.7.2&quot;) from vite-plugin-solid@2.11.12
npm error node_modules/vite-plugin-solid
npm error   dev vite-plugin-solid@&quot;^2.11.6&quot; from the root project
npm error
npm error Conflicting peer dependency: solid-js@1.9.4
npm error node_modules/solid-js
npm error   peer overridden solid-js@&quot;1.9.4&quot; (was &quot;^1.7.2&quot;) from vite-plugin-solid@2.11.12
npm error   node_modules/vite-plugin-solid
npm error     dev vite-plugin-solid@&quot;^2.11.6&quot; from the root project
npm error
npm error Fix the upstream dependency conflict, or retry
npm error this command with --force or --legacy-peer-deps
npm error to accept an incorrect (and potentially broken) dependency resolution.
npm error
npm error
npm error For a full report see:
npm error /home/anthony_p/.npm/_logs/2026-04-15T05_25_31_667Z-eresolve-report.txt
npm error A complete log of this run can be found in: /home/anthony_p/.npm/_logs/2026-04-15T05_25_31_667Z-debug-0.log
</code></pre><p>Et là beaucoup vous diront &quot;passe --force et c&#39;est bon&quot; ou &quot;--legacy-peer-deps c&#39;est mieux !&quot;. Moi je vous dirais : à moins que vous soyez absolument sûr de vous ou que vous n&#39;ayez pas du tout le choix temporairement : ne le faites pas !</p>
<p>Dans mon exemple j&#39;ai indiqué à NPM que je voulais qu&#39;il tire une version &quot;1.9.4&quot; de <code>solid-js</code> pour <code>vite-plugin-solid</code> ce qui implique qu&#39;on casse le fonctionnement des peer dependancies (dépendance qu&#39;on attend qui soit tirée dans l&#39;arbre mais pas forcément par notre package). Passer <code>--force</code> ou <code>--legacy-peer-deps</code> ne va pas fonctionner ici de part le fonctionnement des peer dependancies (vous aurez la <code>1.9.12</code> qui sera prise partout dans l&#39;arbre quand même) mais passer <code>--force</code> ou <code>--legacy-peer-deps</code> va transformer les erreurs en warnings, masquant au passage (car personne ne lit les warnings) des futurs problèmes et donc vous rendant beaucoup plus difficile la montée de version de vos dépendances dans le futur…</p>
<p>Donc si vous arrivez dans le cas où NPM vous propose <code>--force</code> ou <code>--legacy-peer-deps</code> corriger la source du problème, mais n&#39;utilisez pas ces arguments !</p>
<h2 id="article-npm-i-npm-ci-npm-audit-et-packagelockjson"><code>npm i</code>, <code>npm ci</code>, <code>npm audit</code> et <code>package-lock.json</code><a href="#article-npm-i-npm-ci-npm-audit-et-packagelockjson" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Je vois souvent des gens utiliser sans distinction <code>npm i</code> et <code>npm ci</code>. Les deux sont fondamentalement différents dans l&#39;usage :</p>
<ul>
<li><code>npm i</code> va lire votre <code>package.json</code> puis va interroger le registry NPM (par défaut <a href="https://npmjs.com/">https://npmjs.com/</a>) pour résoudre chaque dépendance (directe et transitive), voir s&#39;il y a une nouvelle version à tirer qui correspond au pattern qu&#39;on a indiqué, puis une opération de dédoublonnement va rentrer en œuvre, pour enfin créer votre dossier <code>node_modules</code> et créer (ou mettre à jour) le <code>package-lock.json</code> qui va être une image de votre dossier <code>node_modules</code> avec tout l&#39;arbre, les checksums pour valider que les packages n&#39;ont pas changé (et donc n&#39;ont pas été infectés depuis la dernière fois où vous les avez téléchargés) ;</li>
<li><code>npm ci</code> quant à lui va lire le <code>package-lock.json</code>, vérifier qu&#39;il est bien synchronisé avec le <code>package.json</code> (une section au début du <code>package-lock.json</code> reprend le contenu des <code>dependencies</code> et <code>devDependencies</code> du <code>package.json</code>), puis va télécharger en vérifiant les checksums les versions indiquées dans le <code>package-lock.json</code>, sans plus de traitement, pour créer le dossier <code>node_modules</code> ;</li>
</ul>
<p>Donc autrement dit : <code>npm i</code> est là pour modifier / mettre à jour vos dépendances, <code>npm ci</code> pour les installer. Si vous utilisez continuellement <code>npm i</code> vous allez continuellement mettre à jour vos dépendances (en plus de largement perdre du temps sur cette étape), alors qu&#39;avec <code>npm ci</code> vous allez installer les mêmes versions que toute l&#39;équipe et que votre CI donc vous êtes certain que vous n&#39;aurez pas d&#39;écart à l&#39;exécution. C&#39;est encore plus important si vous exécutez du Node.js côté serveur, parce qu&#39;avec des <code>npm i</code> vous n&#39;avez aucune garantie que l&#39;exécution se fera avec les mêmes versions de dépendances en production qu&#39;en local.</p>
<p>Et <code>npm audit</code> qu&#39;on voit régulièrement quand on fait des <code>npm i</code> ? C&#39;est une commande qui va inspecter vos dépendances et va vous indiquer si c&#39;est possible de mettre à jour des packages dans l&#39;arbre de dépendance pour corriger des failles de sécurité. <code>npm audit</code> vous donnera les infos, <code>npm audit fix</code> va appliquer tout ce qui est sans risque d&#39;un point de vue SemVer. Dans la plupart des cas, <code>npm audit fix</code> va essentiellement modifier le <code>package-lock.json</code> pour changer une version d&#39;une dépendance transitive, donc vous ne voyez rien côté <code>package.json</code>.</p>
<p>Donc votre <code>package-lock.json</code> de facto n&#39;est pas une simple image de votre <code>package.json</code> qui est généré et jetable sans questionnement. C&#39;est un fichier qui a une vraiment importance en termes de sécurité et de garantie de fonctionnement dans le temps.</p>
<p>Autant que possible, aujourd&#39;hui, évitez de supprimer le <code>package-lock.json</code>.</p>
<blockquote>
<p>Note : c&#39;est un peu opaque de prime abord mais si vous utilisez la fonctionnalité d&#39;installation des dépendances via IntelliJ (ou autre IDE de la suite de Jetbrains), il lancera la commande <code>npm install</code>, pas <code>npm ci</code>. J&#39;imagine qu&#39;ils ont fait ça pour éviter d&#39;avoir à tester si le package-lock.json est synchronisé avant de lancer la commande <code>npm ci</code> ou <code>npm i</code>, mais c&#39;est une erreur fondamentale de fonctionner comme ça…</p>
</blockquote>
<h2 id="article-renovate--dependabot">Renovate / Dependabot<a href="#article-renovate--dependabot" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Il existe des outils pour vous aider à maintenir vos dépendances à jour sans trop d&#39;effort, particulièrement si vous avez un bon pipeline qui s&#39;exécute sur vos MR et qui valide assez largement votre application !</p>
<p>Quelques astuces : </p>
<ul>
<li>Mettez toutes vos versions en mode exacte (ne pas mettre de <code>~</code> ou <code>^</code> avant la version) ;</li>
<li>Forcez-vous à mettre de l&#39;auto-merge sur les patchs (normalement c&#39;est censé être gratuit), sauf sur les dépendances internes à votre entreprise (j&#39;ai rarement vu une librairie interne qui suivait entièrement le SemVer et j&#39;ai toujours eu des soucis, donc dans le doute…) ;</li>
<li>définissez un rôle tournant dans votre équipe de mise à jour des dépendances (essentiellement : regarder si le pipeline passe sur les branches de Renovate / Dependabot et cliquer sur &quot;merge&quot;) ;</li>
</ul>
<blockquote>
<p>Note : si on vous bloque pour une quelconque raison l&#39;usage de Renovate / Dependabot, NPM fourni la commande <a href="https://docs.npmjs.com/cli/v11/commands/npm-outdated"><code>npm outdated</code></a> qui va vous indiquer toutes les mises à jours que vous pouvez faire. À défaut d&#39;un outil qui travail à votre place, l&#39;exécuter une fois par semaine vous permettra de rester plutôt à jour à moindre effort. Et si un jour vous trouvez <code>npm outdated</code> trop lent, vous pouvez regarder du côté de <a href="https://www.npmjs.com/package/taze"><code>taze</code></a> qui est plus rapide et permet de mettre à jour par lot les dépendances dans le <code>package.json</code>. </p>
</blockquote>
<h2 id="article-astuce--semver-calculator">Astuce : SemVer Calculator<a href="#article-astuce--semver-calculator" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Si vous avez dû mal à identifier quelles versions seront tirées pour un certain pattern, vous pouvez utiliser le <a href="https://semver.npmjs.com/">npm SemVer Calculator</a>. C&#39;est un outil en ligne fourni par NPM pour visualiser les versions compatibles avec un certain pattern.</p>
<figure>
<img src="https://anthonypena.fr/2026/04/22/reprendre-le-controle-de-vos-dependances-npm/img/semver-calculator.png" alt="SemVer Calculateur avec une démonstration sur une version de lodash" is="img-zoom"/>
<figcaption>SemVer Calculateur avec une démonstration sur une version de lodash</figcaption>
</figure>
<p>Par défaut c&#39;est <code>lodash</code> qui est pointé, mais vous pouvez cibler un autre package, vous pouvez tester n&#39;importe quel pattern de version. C&#39;est vraiment pratique pour valider un pattern très vite, et comprendre comment tout ça fonctionne par la pratique.</p>
<h2 id="article-conclusion">Conclusion<a href="#article-conclusion" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Les dépendances avec NPM c&#39;est parfois un peu compliqué. Surtout parce qu&#39;en général on ne prend pas le temps de se projeter sur le comment ça fonctionne vraiment avant d&#39;avoir un problème et se battre avec. C&#39;est souvent un moment où on s&#39;est embourbé avec des mois de <code>--force</code> ou <code>--legacy-peer-deps</code>, où on a tout cassé et là on dit &quot;NPM c&#39;est de la m**de&quot;, alors que juste on s&#39;est loupé.</p>
<p>NPM fait partie de ses outils avec des défauts historiques mais qui ont tendances à nous laisser décider pas mal de choses et de facto demande de comprendre un minimum ce qu&#39;on fait pour que ça fonctionne dans le temps.</p>
<p>En tout cas, j&#39;espère que cet article vous aidera à mieux gérer vos dépendances NPM ! 🤓</p>
<p>Sources :</p>
<ul>
<li><a href="https://docs.npmjs.com/cli/v11/commands/npm-ls">npm ls</a></li>
<li><a href="https://docs.npmjs.com/cli/v11/commands/npm-install">npm install</a></li>
<li><a href="https://docs.npmjs.com/cli/v11/commands/npm-ci">npm ci</a></li>
<li><a href="https://docs.npmjs.com/cli/v11/commands/npm-audit">npm audit</a></li>
<li><a href="https://docs.npmjs.com/cli/v11/commands/npm-outdated">npm outdated</a></li>
<li><a href="https://semver.npmjs.com/">npm SemVer Calculator</a></li>
</ul>
<p>Crédit photo : Générée via Mistral AI avec le prompt suivant : </p>
<blockquote>
<p>Un style graphique inspiré de l&#39;anime japonais Studio Ghibli, avec une ambiance chaleureuse, immersive, poétique et onirique. Une bibliothèque futuriste en bois sculpté, avec des escaliers en colimaçon, des échelles mobiles, et des étagères remplies de livres flottants. Chaque livre représente une version de package NPM (ex: <a href="mailto:%26#108;%26#x6f;%26#100;%26#x61;%26#115;%26#104;%26#64;%26#x34;%26#46;%26#x31;%26#x38;%26#46;%26#x31;">&#108;&#x6f;&#100;&#x61;&#115;&#104;&#64;&#x34;&#46;&#x31;&#x38;&#46;&#x31;</a>, <a href="mailto:%26#101;%26#115;%26#98;%26#x75;%26#x69;%26#108;%26#100;%26#x40;%26#x30;%26#x2e;%26#50;%26#55;%26#46;%26#x37;">&#101;&#115;&#98;&#x75;&#x69;&#108;&#100;&#x40;&#x30;&#x2e;&#50;&#55;&#46;&#x37;</a>) avec des titres lumineux et des couvertures colorées. Au centre, un grand hologramme central montre un arbre de dépendances NPM avec npm ls --all, avec des lignes lumineuses reliant les livres entre eux pour symboliser les relations entre les dépendances. En bas à droite, un panda roux anthropomorphe (style Ghibli, vêtements amples) est assis sur un tapis en tissu, un livre ouvert sur ses genoux (titre visible : &quot;SemVer pour les nuls&quot;), avec une tasse de thé fumant à côté. L&#39;arrière-plan est rempli de détails organiques : plantes grimpantes, feuilles d&#39;érable rouges/oranges/jaunes tombant doucement, et une lumière dorée tamisée évoquant un après-midi d&#39;automne. Les couleurs dominantes sont des tons doux de beige, bleu pâle, orange chaud, et des accents de vert et de doré pour les éléments technologiques et naturels. L&#39;image doit être détaillée, immersive, avec des textures riches et une atmosphère à la fois cosy et magique, mêlant technologie et nature de manière harmonieuse.</p>
</blockquote>
]]></content:encoded>
      <dc:creator><![CDATA[Anthony Pena]]></dc:creator>
      <media:content medium="image" url="https://anthonypena.fr/img/cover.min.jpg"/>
    </item>
    <item>
      <title><![CDATA[Revue de presse - Avril 2026]]></title>
      <guid isPermaLink="false">2026/04/08/revue-de-presse-avril</guid>
      <description><![CDATA[]]></description>
      <link>https://anthonypena.fr/2026/04/08/revue-de-presse-avril/index.html</link>
      <category><![CDATA[Revue de presse]]></category>
      <pubDate>Wed, 08 Apr 2026 07:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<h2 id="article-frontend">Frontend<a href="#article-frontend" class="anchor" aria-label="permalink">🔗</a></h2>
<h3 id="article-announcing-npmx-a-fast-modern-browser-for-the-npm-registryhttpsnpmxdevblogalpharelease"><a href="https://npmx.dev/blog/alpha-release">Announcing npmx: a fast, modern browser for the npm registry</a><a href="#article-announcing-npmx-a-fast-modern-browser-for-the-npm-registryhttpsnpmxdevblogalpharelease" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#NPM #Node.JS #Frontend</p>
<p>Annonce officielle de npmx.dev, qui est pour l&#39;instant un frontend alternatif à npmjs.com. Je dis pour l&#39;instant, car l&#39;article parle de frustration autour du CLI npm aussi donc peut-être qu&#39;ils tenteront quelque chose aussi. </p>
<p>Personnellement ça fait quelques semaines que j&#39;utilise npmx.dev en remplacement de npmjs.com au quotidien (sauf pour la partie privée de gestion de package) car :</p>
<ul>
<li>même url pour atteindre la description d&#39;un package (<a href="https://npmjs.com/package/@anthonypena/fp">https://npmjs.com/package/@anthonypena/fp</a> =&gt; <a href="https://npmx.dev/package/@anthonypena/fp">https://npmx.dev/package/@anthonypena/fp</a>) donc peu d&#39;effort là-dessus ;</li>
<li>thème light-dark automatique ;</li>
<li>Navigation dans le code propre ;</li>
<li>meilleure vision des versions ;</li>
<li>meilleure vision des dépendances ;</li>
<li>je trouve ça plus rapide (aucune métrique, juste un ressenti) ;</li>
</ul>
<p>Ce n&#39;est évidemment pas parfait (parfois des pages que je dois refresh pour que ça fonctionne, etc) mais ça me facilite la vie, donc je recommande. Surtout que ça n&#39;a aucune incidence sur vos projets ! </p>
<h3 id="article-absorbing-unknown-into-the-type-realmhttpswwwsolbergisunknowntotyped"><a href="https://www.solberg.is/unknown-to-typed">Absorbing unknown Into the Type Realm</a><a href="#article-absorbing-unknown-into-the-type-realmhttpswwwsolbergisunknowntotyped" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#TypeScript #Frontend</p>
<p>L&#39;intro donne une bonne idée du problème </p>
<blockquote>
<p>Every as in your TypeScript is a tiny lie. Sometimes a necessary one, but a lie nonetheless — you&#39;re telling the compiler &quot;trust me&quot; about data it can&#39;t verify. The question is: when can you avoid it?</p>
</blockquote>
<p>La conclusion résume assez bien l&#39;article :</p>
<blockquote>
<p>When unknown data arrives at your boundary:</p>
<ol>
<li><strong>Can you validate it?</strong> Use zod (or any schema library). This is the best option for JSON from APIs, databases, localStorage, URL params.
<strong>2. Can you narrow it?</strong> Write a type guard or assertion function. Best for discriminated unions, string literals, set membership, preconditions.</li>
<li><strong>Is it a generic boundary?</strong> One as in the utility, validation at the call site.</li>
<li><strong>Is it structural plumbing?</strong> (Proxies, generated code) Inline disable, move on.</li>
</ol>
<p>The goal isn&#39;t zero as — it&#39;s zero unexamined as. Every cast should be a conscious decision, not a reflex.</p>
</blockquote>
<p>Faut vraiment que j&#39;utilise plus Zod de mon côté ! Et je découvre better-result c&#39;est intéressant ! </p>
<h3 id="article-humanjsonhttpscodebergorgrobidahumanjson"><a href="https://codeberg.org/robida/human.json">human.json</a><a href="#article-humanjsonhttpscodebergorgrobidahumanjson" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#Web #Frontend</p>
<p>L&#39;idée c&#39;est que chaque humain qui publie en ligne peut ajouter un fichier <code>human.json</code> qui a cette forme :</p>
<pre><code class="hljs language-JSON"><span class="hljs-punctuation">{</span>
  <span class="hljs-attr">&quot;version&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;0.1.1&quot;</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;url&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;https://example.com/~alice&quot;</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;vouches&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span>
    <span class="hljs-punctuation">{</span>
      <span class="hljs-attr">&quot;url&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;https://bob.example.com&quot;</span><span class="hljs-punctuation">,</span>
      <span class="hljs-attr">&quot;vouched_at&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;2026-01-15&quot;</span>
    <span class="hljs-punctuation">}</span><span class="hljs-punctuation">,</span>
    <span class="hljs-punctuation">{</span>
      <span class="hljs-attr">&quot;url&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;https://example.com/~charlie&quot;</span><span class="hljs-punctuation">,</span>
      <span class="hljs-attr">&quot;vouched_at&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;2025-11-02&quot;</span>
    <span class="hljs-punctuation">}</span>
  <span class="hljs-punctuation">]</span>
<span class="hljs-punctuation">}</span><div aria-hidden="true" class="language-tag">JSON</div>
</code></pre><p>Qui permet d&#39;indiquer qu&#39;on affirme être un humain qui écrit un site et qu&#39;on atteste que d&#39;autres sites sont rédigés par des humains. Si quelqu&#39;un d&#39;autres attestent qu&#39;on est un humain on a donc une chaîne de confiance qui se crée brique par brique. </p>
<p>Pour suivre cette chaîne de confiance :</p>
<ul>
<li>on doit indiquer dans nos pages web <code>&lt;link rel=&quot;human-json&quot; href=&quot;/path/to/human.json&quot;&gt;</code> ;</li>
<li>on peut utiliser l&#39;extension dédiée pour suivre cette chaîne de confiance avoir une indication dans son navigateur de la confiance ;</li>
</ul>
<p>J&#39;aime bien l&#39;idée même si c&#39;est purement basé sur la confiance. </p>
<h2 id="article-backend">Backend<a href="#article-backend" class="anchor" aria-label="permalink">🔗</a></h2>
<h3 id="article-evolving-the-nodejs-release-schedulehttpsnodejsorgenblogannouncementsevolvingthenodejsreleaseschedule"><a href="https://nodejs.org/en/blog/announcements/evolving-the-nodejs-release-schedule">Evolving the Node.js Release Schedule</a><a href="#article-evolving-the-nodejs-release-schedulehttpsnodejsorgenblogannouncementsevolvingthenodejsreleaseschedule" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#NodeJS #Node.JS #Backend</p>
<p>Changement historique et majeure pour l&#39;écosystème Node.js : le cycle de release va radicalement changer pour le mieux ! </p>
<p>On passe d&#39;un modèle où 2 versions majeures sortaient chaque année mais une seule considérée comme stable (exemple en 2025 : la 24 sortie en mai était stable, la 25 sortie en octobre ne l&#39;était pas) à un modèle où on aura une seule version chaque année, à date à peu près fixe (avril) et où toutes les versions deviendront stables. </p>
<figure>
<img src="https://nodejs.org/static/images/blog/announcements/2026-new-release-schedule.svg?dpl=dpl_XdcK2vFXvVGQwjrEhLjF22zubcNx" alt="Timeline de sortie des versions à partir de maintenant" is="img-zoom"/>
<figcaption>Timeline de sortie des versions à partir de maintenant</figcaption>
</figure>
<p>La version 26 est la dernière à suivre l&#39;ancien modèle (sur une LTS donc pour permettre aux utilisateurs de prendre en compte le changement en douceur), la 27 la première version à suivre le nouveau modèle.</p>
<p>Pour la version 27 :</p>
<ul>
<li>en octobre 2026, sortie en &quot;Alpha&quot; : phase de test préparation à la release ;</li>
<li>en avril 2027, sortie de la release en &quot;Current&quot; : la version sort comme les versions actuelles, on peut encore voir des mineurs et patchs mais c&#39;est pour améliorer / corriger en fonction des retours sans casser de fonctionnalité ;</li>
<li>en octobre 2027, passage en LTS (pour 30 mois) : on s&#39;assure que la version reçoit les patchs de sécurité pour garantir que les utilisateurs en productions sont tranquilles ;</li>
</ul>
<blockquote>
<p>Point utile à noter : les versions seront alignées sur l&#39;année de release, la version 27 en 2027, la version 28 en 2028, etc. </p>
</blockquote>
<p>Il va falloir prendre le pli de mettre à jour Node.js chaque année, et tester les versions Current, même Alpha si possible, pour pouvoir remonter les problèmes au plus tôt </p>
<h2 id="article-ia">IA<a href="#article-ia" class="anchor" aria-label="permalink">🔗</a></h2>
<h3 id="article-how-to-kill-the-code-reviewhttpswwwlatentspacepreviewsdead"><a href="https://www.latent.space/p/reviews-dead">How to Kill the Code Review</a><a href="#article-how-to-kill-the-code-reviewhttpswwwlatentspacepreviewsdead" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#IA</p>
<p>Je cite le sous-titre qui résume bien l&#39;idée :</p>
<blockquote>
<p>Human-written code died in 2025. Code reviews will die in 2026.</p>
</blockquote>
<p>L&#39;article nous explique qu&#39;on tend à tuer la code review, car si on utilise un agent pour coder le produit et un autre agent pour coder les tests du produit tous les deux à partir des specs, on peut ne review que les specs, ce qu&#39;on fait déjà en tant que développeur agentique. Que de toutes façons le volume de code généré entraîne un goulet d&#39;étranglement sur la délivrabilité, du fait qu&#39;en tant qu&#39;humain on est lent à relire du code, que souvent ça incombe aux techs leads et que ça les épuise. </p>
<p>Qu&#39;il faut viser :</p>
<blockquote>
<p>The future is ship fast, observe everything, revert faster.</p>
</blockquote>
<p>Premier point : l&#39;auteur de l&#39;article est le fondateur d&#39;Aviator, qui se décrit comme &quot;multiplayer AI coding platform&quot;. Donc je cite aussi un vieil adage :</p>
<blockquote>
<p>Pendant la ruée vers l’or, ce n’est pas les chercheurs d’or qui se sont le plus enrichis, mais les vendeurs de pelles et de pioches…</p>
</blockquote>
<p>Ce que nous dit ce monsieur : ne faites plus rien vous-même, utilisez une IA pour coder le produit, une autre IA pour tester le produit, et déployer le tout avec des briques construites avec des IAs. Donc en gros &quot;donnez-moi de l&#39;argent&quot;. </p>
<p>Ensuite on nous rabâche qu&#39;avec l&#39;IA on peut aller, plus vite, plus loin, avec une meilleure qualité. Mais du coup : comme on s&#39;assure que toute l&#39;équipe comprend ce qu&#39;elle fait ? La première raison d&#39;être de la code review ce n&#39;est pas de garantir qu&#39;aucun bug n&#39;arrivera, mais de partager la connaissance dans l&#39;équipe sur comment fonctionne le produit et éviter des mauvaises pratiques. Si on enlève la code review, seul le dev qui a défini la fonctionnalité saura comment elle fonctionne (et encore vu le mouvement actuel qui dit qu&#39;on devrait ne même plus regarder le code et faire confiance aux specs…), et personne n&#39;aura regardé s&#39;il a suivi les bonnes pratique sur la définition de ses specs, les conventions, etc. Donc on va avoir plusieurs devs en roue libre qui partent chacun dans leur direction peu importe qu&#39;ils bossent sur un seul produit. Réjouissant futur à mon avis… </p>
<h3 id="article-openai-to-nearly-double-workforce-to-8000-by-end2026-ft-reports--reuterscomhttpswwwreuterscombusinessopenainearlydoubleworkforce8000byend2026ftreports20260321"><a href="https://www.reuters.com/business/openai-nearly-double-workforce-8000-by-end-2026-ft-reports-2026-03-21/">OpenAI to nearly double workforce to 8,000 by end-2026, FT reports — reuters.com</a><a href="#article-openai-to-nearly-double-workforce-to-8000-by-end2026-ft-reports--reuterscomhttpswwwreuterscombusinessopenainearlydoubleworkforce8000byend2026ftreports20260321" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#IA #OpenAI #ChatGPT #LLM #Dev</p>
<blockquote>
<p>Artificial intelligence start-up OpenAI plans to nearly ​double its workforce to 8,000 ‌from 4,500 by the end of 2026, the Financial Times reported on Saturday, ​citing two people with knowledge of ​the matter.</p>
</blockquote>
<blockquote>
<p>OpenAI to nearly double workforce to 8,000 by end-2026, FT reports said. </p>
</blockquote>
<blockquote>
<p>The ChatGPT-maker is ​also ramping up recruitment of specialists focused on &quot;technical ambassadorship,&quot; ‌aimed ⁠at helping businesses make better use of its tools, the report added.</p>
</blockquote>
<p>Si je résume la position d&#39;OpenAI &quot;vous n&#39;avez plus besoin de dev vu notre IA fait tout mais nous on a toujours besoin de dev vu que notre IA ne fait pas tout.&quot; </p>
<h2 id="article-securite">Sécurité<a href="#article-securite" class="anchor" aria-label="permalink">🔗</a></h2>
<h3 id="article-proton-mail-a-aide-le-fbi-a-demasquer-un-manifestant-anonyme-affilie-au-mouvement-decentralise-de-protestation--stop-cop-city-httpsdroitdeveloppezcomactu380880protonmailaaidelefbiademasquerunmanifestantanonymeaffilieaumouvementdecentralisedeprotestationstopcopcitysuscitantdenouveaudesquestionssursesgarantiesenmatieredesecurite"><a href="https://droit.developpez.com/actu/380880/Proton-Mail-a-aide-le-FBI-a-demasquer-un-manifestant-anonyme-affilie-au-mouvement-decentralise-de-protestation-Stop-Cop-City-suscitant-de-nouveau-des-questions-sur-ses-garanties-en-matiere-de-securite/">Proton Mail a aidé le FBI à démasquer un manifestant anonyme affilié au mouvement décentralisé de protestation « Stop Cop City »,</a><a href="#article-proton-mail-a-aide-le-fbi-a-demasquer-un-manifestant-anonyme-affilie-au-mouvement-decentralise-de-protestation--stop-cop-city-httpsdroitdeveloppezcomactu380880protonmailaaidelefbiademasquerunmanifestantanonymeaffilieaumouvementdecentralisedeprotestationstopcopcitysuscitantdenouveaudesquestionssursesgarantiesenmatieredesecurite" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#Communication #Vie-privée #Sécurité</p>
<p>Si on regarde dans le détail, on est obligé d&#39;admettre que quand bien même Proton tente de minimiser les données qu&#39;ils possèdent sur leurs utilisateurs, ils ont aussi des contraintes légales pour certaines données (comme les coordonnées de paiement). Proton garanti la sécurité des communications pas l&#39;anonymat des utilisateurs. </p>
<p>Il faut aussi rappeler que si Proton ne se conformait pas un minimum aux requêtes judiciaires de l&#39;État Suisse, ce serait eux qui seraient sur le banc des accusés et donc leur mission serait remise en cause 😅 </p>
<h3 id="article-android-developer-verification-balancing-openness-and-choice-with-safetyhttpsandroiddevelopersgoogleblogcom202603androiddeveloperverificationhtmlm1"><a href="https://android-developers.googleblog.com/2026/03/android-developer-verification.html?m%3D1">Android developer verification: Balancing openness and choice with safety</a><a href="#article-android-developer-verification-balancing-openness-and-choice-with-safetyhttpsandroiddevelopersgoogleblogcom202603androiddeveloperverificationhtmlm1" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#Android #Google #Sécurité</p>
<p>Je cite la démarche :</p>
<blockquote>
<p>How the advanced flow works for users</p>
<ul>
<li>Enable developer mode in system settings: Activating this is simple. This prevents accidental triggers or &quot;one-tap&quot; bypasses often used in high-pressure scams.</li>
<li>Confirm you aren&#39;t being coached: There is a quick check to make sure that no one is talking you into turning off your security. While power users know how to vet apps, scammers often pressure victims into disabling protections.</li>
<li>Restart your phone and reauthenticate: This cuts off any remote access or active phone calls a scammer might be using to watch what you’re doing.</li>
<li>Come back after the protective waiting period and verify: There is a one-time, one-day wait and then you can confirm that this is really you who’s making this change with our biometric authentication (fingerprint or face unlock) or device PIN. Scammers rely on manufactured urgency, so this breaks their spell and gives you time to think.</li>
<li>Install apps: Once you confirm you understand the risks, you’re all set to install apps from unverified developers, with the option of enabling for 7 days or indefinitely. For safety, you’ll still see a warning that the app is from an unverified developer, but you can just tap “Install Anyway.”</li>
</ul>
</blockquote>
<p>Ça peut sembler facile et pas si bloquant mais pensez à un truc simple : j&#39;utilise des apps au quotidien que j&#39;installe via <a href="https://f-droid.org/">f-droid</a>, certaines pas du tout présentes sur le Play Store, donc le jour où je vais changer de téléphone, je devrais faire la manip au-dessus, attendre 24h, et là je pourrais commencer à utiliser mon téléphone (que j&#39;ai payé, qui m&#39;appartient, dont je suis censé disposer librement sans condition, sans avoir à demander de permission) normalement. Pas pour des limitations techniques, parce que Google aura décidé que c&#39;est mieux pour mon bien. </p>
<p>Franchement tout jusqu&#39;au dernier point, je peux comprendre, ça peut sûrement éviter des arnaques de personnes en illectronisme. Le dernier point est 100% abusif à mon sens. </p>
<h2 id="article-divers">Divers<a href="#article-divers" class="anchor" aria-label="permalink">🔗</a></h2>
<h3 id="article-a-website-to-destroy-all-websiteshttpshenrycodeswritingawebsitetodestroyallwebsites"><a href="https://henry.codes/writing/a-website-to-destroy-all-websites/">A website to destroy all websites.</a><a href="#article-a-website-to-destroy-all-websiteshttpshenrycodeswritingawebsitetodestroyallwebsites" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#Web #Internet</p>
<p>Cet article est une ode à un retour à un Internet plus humain. Les parallèles sont intéressants, et franchement je suis d&#39;accord avec l&#39;auteur, pour retrouver un Internet plus humain, il suffit qu&#39;on lâche les gros acteurs pour revenir à la base : publier nos propres sites, simple, imparfait mais humain. </p>
<p>Article qui vaut la peine d&#39;être lu à mon sens (et je voulais vraiment le lire depuis la revue de presse de l&#39;ami <a href="https://ehret.me/2026/02/nflm-developer/?ref%3Drss">Siegfried</a> de février… ). Sous certains aspects il me fait d&#39;ailleurs penser au discours d&#39;Edward Snowden dans <em>Mémoire Vives</em>, sa découverte d&#39;Internet, tout ce qu&#39;il a appris et tout le temps passé à échanger avec des inconnus (mais pas si inconnu à force d&#39;échange à travers un écran). </p>
<h3 id="article-two-years-of-emacs-solo-35-modules-zero-external-packages-and-a-full-refactorhttpswwwrahuljuliatocompostsemacssolotwoyears"><a href="https://www.rahuljuliato.com/posts/emacs-solo-two-years">Two Years of Emacs Solo: 35 Modules, Zero External Packages, and a Full Refactor</a><a href="#article-two-years-of-emacs-solo-35-modules-zero-external-packages-and-a-full-refactorhttpswwwrahuljuliatocompostsemacssolotwoyears" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#Emacs</p>
<p>Je suis depuis longtemps aussi attiré que repoussé par Emacs. Je fais un peu de vim au quotidien (surtout via git d&#39;ailleurs). Mais Emacs est pour moi beaucoup plus puissant et permet beaucoup plus de chose. </p>
<p>J&#39;ai toujours pensé que pour avoir un environnement développement proche d&#39;un IDE (ou même d&#39;un éditeur de texte ++ comme VSCode) il fallait empiler des packages à foison, ce qui m&#39;a toujours embêté. Pourquoi ? C&#39;est compliqué à maintenir et c&#39;est lent (là où ce qui m&#39;intéresse dans vim ou Emacs c&#39;est la légèreté, la simplicité et la vitesse) </p>
<p>Ici c&#39;est l&#39;auteur de &quot;emacs-solo&quot;, une configuration d&#39;Emacs sans aucune dépendance, super modulaire, sans package à télécharger, juste quelques fichiers lisp à copier. Et franchement ça a l&#39;air de vraiment bien marcher ! Ça donne envie de tester ! </p>
<h3 id="article-wifi-trop-faible--sortez-votre-ancien-smartphone-android-du-tiroir-et-transformezle-en-repeteurhttpswwwlesnumeriquescomtelephoneportablewifitropfaiblesortezvotreanciensmartphoneandroiddutiroirettransformezleenrepeteurn253258html"><a href="https://www.lesnumeriques.com/telephone-portable/wifi-trop-faible-sortez-votre-ancien-smartphone-android-du-tiroir-et-transformez-le-en-repeteur-n253258.html">WiFi trop faible ? Sortez votre ancien smartphone Android du tiroir et transformez-le en répéteur</a><a href="#article-wifi-trop-faible--sortez-votre-ancien-smartphone-android-du-tiroir-et-transformezle-en-repeteurhttpswwwlesnumeriquescomtelephoneportablewifitropfaiblesortezvotreanciensmartphoneandroiddutiroirettransformezleenrepeteurn253258html" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#Wifi #Android #Smartphone</p>
<p>J&#39;avoue, j&#39;avais jamais pensé à utiliser un ancien smartphone comme ça 😅 </p>
<p>Mais : </p>
<ul>
<li>il faut un smartphone pas trop ancien pour supporter d&#39;être à la fois à émettre un réseau wifi et de connecter à un autre (il faut qu&#39;il soit dual band) ;</li>
<li>s&#39;il est trop peu perf ça va être lent à cause de lui pas à cause de la portée wifi ;</li>
<li>je pense que ça consomme plus d&#39;électricité qu&#39;un répéteur / routeur wifi (j&#39;ai pas mesuré, donc c&#39;est du pif) ; </li>
<li>ce sera sûrement moins stable (sur des sessions un peu longues de partage de connexion, je trouve que je perds en stabilité parce que mon téléphone chauffe un peu, et j&#39;ai toujours constaté ça) ;</li>
</ul>
<p>Mais, ça veut pas dire que ça vaut pas le coup de tenter, même en tant que solution temporaire, surtout si on a un smartphone dans un tiroir qui dort : ça ne vous coûtera pas grand-chose de tester. Et au pire si c&#39;est moins stable. Il sera toujours temps d&#39;investir dans un répéteur wifi plus tard ! </p>
<h3 id="article-datashield--la-blocklist-qui-vire-les-ips-pourrieshttpskorbeninfodatashieldipv4blocklisthtml"><a href="https://korben.info/data-shield-ipv4-blocklist.html">Data-Shield - La blocklist qui vire les IPs pourries</a><a href="#article-datashield--la-blocklist-qui-vire-les-ips-pourrieshttpskorbeninfodatashieldipv4blocklisthtml" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#Réseau #Firewall #Open-Source</p>
<blockquote>
<p>Hé bien c&#39;est exactement ce que fait Data-Shield IPv4 Blocklist , un projet open source qui maintient une liste d&#39;environ 100 000 adresses IP identifiées comme malveillantes. Le principe est simple… on colle l&#39;URL RAW de la liste dans la config de son firewall (genre dans les alias d&#39;OPNsense ou les External Block Lists de Fortinet) et hop, tout ce beau monde est filtré au niveau périmétrique. La liste (un simple fichier texte avec une IP par ligne) est rafraîchie toutes les 6 heures avec une fenêtre de rétention de 15 jours, du coup les IPs qui ne sont plus actives finissent par sortir automatiquement.</p>
</blockquote>
<p>Franchement un super travail de maintenir une liste comme ça ! Il faudrait vraiment que je commence à utiliser une liste comme au niveau firewall 😅 </p>
<h3 id="article-la-france-rachete-a-atos-lentreprise-bull-fleuron-trop-longtemps-en-souffrance-des-supercalculateurshttpswwwclubiccomactualite607144lafranceracheteaatoslentreprisebullfleurontroplongtempsensouffrancedessupercalculateurshtml"><a href="https://www.clubic.com/actualite-607144-la-france-rachete-a-atos-l-entreprise-bull-fleuron-trop-longtemps-en-souffrance-des-supercalculateurs.html">La France rachète à Atos l&#39;entreprise Bull, fleuron trop longtemps en souffrance des supercalculateurs</a><a href="#article-la-france-rachete-a-atos-lentreprise-bull-fleuron-trop-longtemps-en-souffrance-des-supercalculateurshttpswwwclubiccomactualite607144lafranceracheteaatoslentreprisebullfleurontroplongtempsensouffrancedessupercalculateurshtml" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#France #Bull #Supercalculateur #Atos</p>
<blockquote>
<p>L&#39;État français a finalisé ce 31 mars 2026 le rachat de Bull, spécialiste du calcul haute performance et de l&#39;IA, pour une valeur pouvant atteindre 404 millions d&#39;euros. L&#39;acquisition d&#39;une entreprise historique.</p>
</blockquote>
<p>Je trouve ça assez faible sachant que l&#39;entreprise a généré &quot;un chiffre d&#39;affaires de 720 millions d&#39;euros en 2025.&quot;. Après c&#39;est peut-être une astuce financière pour protéger d&#39;entreprise. </p>
<p>J&#39;y apprends d&#39;autres choses intéressantes au passage :</p>
<blockquote>
<p>L&#39;usine d&#39;Angers est la seule en Europe capable de fabriquer des supercalculateurs, ces machines colossales qui traitent des milliards d&#39;opérations par seconde et qui sont devenues indispensables pour entraîner les grands modèles d&#39;intelligence artificielle, simuler des scénarios militaires ou faire avancer la recherche scientifique. Cerise sur le gâteau, elles sont reconnues pour leur sobriété énergétique, un critère de plus en plus décisif à l&#39;heure où faire tourner une IA coûte une énergie considérable.</p>
</blockquote>
<p>Une usine de super calculateur à Angers 😮 </p>
<p>Crédit photo : Générée via Mistral AI avec le prompt suivant : </p>
<blockquote>
<p>Une scène chaleureuse et immersive, inspirée par l’esthétique poétique de Studio Ghibli, représentant un bureau de travail en bois clair et vieilli, baigné d’une lumière dorée et tamisée, comme un après-midi d’automne. Au centre, une silhouette stylisée (style anime Ghibli : traits doux, visage non détaillé, vêtements amples et confortables) est assise en tailleur sur un tapis épais, absorbée par la lecture d’un journal tech futuriste. Le journal est ouvert, ses pages légèrement froissées, avec des titres en en-tête calligraphiés à la main : &quot;Frontend&quot;, &quot;Backend&quot;, &quot;IA&quot;, &quot;Sécurité&quot;, et &quot;Vie privée&quot;. Les pages brillent d’un halo bleu pâle, évoquant des lignes de code et des schémas techniques qui s’animent discrètement, comme par magie.
Autour d’elle, des piles de magazines et de carnets s’empilent de manière désordonnée mais harmonieuse. Certains sont ouverts, révélant des extraits d’articles, des croquis de frameworks (représentés par des icônes génériques : un crochet pour le frontend, un engrenage pour le backend, un cerveau pour l’IA, un cadenas pour la sécurité, et un masque pour la vie privée), ou des diagrammes de réseaux de neurones dessinés à la main. Un écran transparent et flottant (style holographique, mais avec un cadre en bois sculpté) affiche des flux d’informations en temps réel : des graphiques de données, des alertes de sécurité, et des extraits de code, le tout dans un style doux et organique, comme intégré à la scène.
En arrière-plan, une grande fenêtre donne sur un paysage urbain nocturne style Ghibli : des bâtiments aux formes arrondies, des lanternes suspendues, et des néons bleutés qui reflètent des motifs de code binaire sur les murs. Une tasse de thé fumant et un petit robot de bureau (inspiré des créatures de Ghibli, comme un mélange entre un Totoro miniature et un assistant tech) observent la scène avec curiosité.
À droite, un panda roux (ton animal préféré) est lové sur un coussin, les yeux mi-clos, comme s’il écoutait attentivement. Il ne doit pas dépasser le tiers de la hauteur de l’image et est positionné en bas à droite, légèrement tourné vers le centre, avec une queue soyeuse enroulée autour de lui.
L’ambiance est à la fois cosy, onirique et high-tech : les couleurs sont douces (beiges, bleus pâles, oranges chauds), avec des contrastes subtils pour mettre en valeur les éléments tech. Les détails sont soignés, avec des textures visibles (grain du bois, tissu du tapis, pelage du panda), et une lumière qui crée des jeux d’ombres chaleureuses. Le tout respire la sérénité et l’inspiration, comme un moment suspendu entre la magie et la technologie.</p>
</blockquote>
]]></content:encoded>
      <dc:creator><![CDATA[Anthony Pena]]></dc:creator>
      <media:content medium="image" url="https://anthonypena.fr/img/cover.min.jpg"/>
    </item>
    <item>
      <title><![CDATA[Créer une vue calendrier minimaliste avec du HTML et du CSS]]></title>
      <guid isPermaLink="false">2026/03/31/creer-une-vue-calendrier-minimaliste-avec-du-html-et-du-css</guid>
      <description><![CDATA[<p>Si vous allez sur un profil Github (par exemple : le miens), vous verrez quelque chose qui ressemble…</p>
]]></description>
      <link>https://anthonypena.fr/2026/03/31/creer-une-vue-calendrier-minimaliste-avec-du-html-et-du-css/index.html</link>
      <category><![CDATA[Frontend]]></category>
      <category><![CDATA[HTML]]></category>
      <category><![CDATA[CSS]]></category>
      <pubDate>Tue, 31 Mar 2026 07:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>Si vous allez sur un profil Github (par exemple : <a href="https://github.com/kuroidoruido">le miens</a>), vous verrez quelque chose qui ressemble à ça :</p>
<figure>
<img src="https://anthonypena.fr/2026/03/31/creer-une-vue-calendrier-minimaliste-avec-du-html-et-du-css/img/github-contributions.png" alt="Contributions Github" is="img-zoom"/>
<figcaption>Contributions Github</figcaption>
</figure>
<p>Pour plein de raisons j&#39;aime bien et pas trop cette vue. Et j&#39;avais envie d&#39;avoir quelque chose de similaire sur mon blog… Je vous explique !</p>
<p>Tout ce que je vous montre ici est disponible ici :</p>
<ul>
<li><a href="https://kuroidoruido.github.io/css-is-magic/minimalist-calendar-view/index.html">Démonstration interactive</a></li>
<li><a href="https://github.com/kuroidoruido/css-is-magic/blob/main/minimalist-calendar-view/">Code source de la démo</a></li>
</ul>
<h2 id="article-ce-que-jaime-et-aime-moins-dans-la-vue-contribution-de-github">Ce que j&#39;aime et aime moins dans la vue contribution de Github<a href="#article-ce-que-jaime-et-aime-moins-dans-la-vue-contribution-de-github" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Ce qui fait la popularité de cette vue c&#39;est que ça permet à des gens de montrer qu&#39;ils travaillent plus que tout le monde… J&#39;aime pas trop ça… Ce que ça montre c&#39;est votre activité, en grande partie basé sur votre volume de commit, ce qui ne veut rien dire ni de votre activité réelle, ni de votre apport aux projets, ni rien en fait, juste vous savez faire des <code>git commit -m &quot;truc&quot; --allow-empty</code>…</p>
<p>Par contre j&#39;aime bien ce genre de graphique avec un côté prise de recul car ça permet d&#39;avoir une vue d&#39;ensemble d&#39;une période assez longue (sur ma capture d&#39;écran les 12 derniers mois, mais ça peut être aussi les 12 mois d&#39;une année), sans prendre trop de place et si on sait qu&#39;on ne triche pas sur l&#39;activité qu&#39;on a, de voir quand on a été moins bon, et peut-être prendre du recul là-dessus pour comprendre pourquoi, ensuite au choix faire en sorte de pouvoir être actif plus souvent parce que ça nous manquait à cette période, ou à l&#39;inverse réduire son activité pour être mieux (ça c&#39;est vous qui voyez).</p>
<p>Globalement, j&#39;aime vraiment la vue d&#39;ensemble que ça apporte qui donne une info en un coup d&#39;œil ! Et c&#39;est ça que j&#39;aimerai avoir sur mon blog !</p>
<p>J&#39;aimerai une vue très simple, beaucoup plus minimaliste que ce que fait Github, avec les couleurs du blog, sur chaque page archives (une page archive présente tous les articles d&#39;une année), pour naviguer visuellement dans l&#39;année.</p>
<h2 id="article-lets-go-html">Let&#39;s go HTML!<a href="#article-lets-go-html" class="anchor" aria-label="permalink">🔗</a></h2>
<p><a href="/2026/01/15/nouveau-blog-partie-1-html/">Mon blog est généré statiquement</a> donc je veux une solution purement HTML et CSS. Je passe sur la manière dont je mouline mon modèle interne pour générer le HTML, mais voici le résultat :</p>
<pre><code class="hljs language-HTML"><span class="hljs-tag">&lt;<span class="hljs-name">section</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;overview&quot;</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">&quot;true&quot;</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">data-previous-year</span>=<span class="hljs-string">&quot;true&quot;</span> <span class="hljs-attr">data-date</span>=<span class="hljs-string">&quot;2025-12-29&quot;</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span><span class="hljs-comment">&lt;!-- Monday --&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">data-previous-year</span>=<span class="hljs-string">&quot;true&quot;</span> <span class="hljs-attr">data-date</span>=<span class="hljs-string">&quot;2025-12-30&quot;</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span><span class="hljs-comment">&lt;!-- Tuesday --&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">data-previous-year</span>=<span class="hljs-string">&quot;true&quot;</span> <span class="hljs-attr">data-date</span>=<span class="hljs-string">&quot;2025-12-31&quot;</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span><span class="hljs-comment">&lt;!-- Wednesday --&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">data-date</span>=<span class="hljs-string">&quot;2026-01-01&quot;</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span><span class="hljs-comment">&lt;!-- Thursday --&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">data-date</span>=<span class="hljs-string">&quot;2026-01-02&quot;</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span><span class="hljs-comment">&lt;!-- Friday --&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">data-date</span>=<span class="hljs-string">&quot;2026-01-03&quot;</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span><span class="hljs-comment">&lt;!-- Saturday --&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">data-date</span>=<span class="hljs-string">&quot;2026-01-04&quot;</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span><span class="hljs-comment">&lt;!-- Sunday --&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">data-date</span>=<span class="hljs-string">&quot;2026-01-05&quot;</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">data-date</span>=<span class="hljs-string">&quot;2026-01-06&quot;</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&quot;#2026/01/06/revue-de-presse-janvier&quot;</span> <span class="hljs-attr">title</span>=<span class="hljs-string">&quot;Revue de presse - Janvier 2026&quot;</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
        ...
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">data-date</span>=<span class="hljs-string">&quot;2026-03-17&quot;</span> <span class="hljs-attr">data-today</span>=<span class="hljs-string">&quot;true&quot;</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">data-date</span>=<span class="hljs-string">&quot;2026-03-18&quot;</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
        ...
    <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span><div aria-hidden="true" class="language-tag">HTML</div>
</code></pre><blockquote>
<p>Note : j&#39;ai ajouté les jours de la semaine sur la première semaine pour aider à comprendre.</p>
</blockquote>
<p>Je veux une grille donc j&#39;ai choisi de faire une liste non ordonnée (<code>&lt;ul&gt;</code>) ! What!? 🧐</p>
<p>Ça peut vous surprendre mais oui j&#39;ai choisi de faire une liste et pas un tableau. Pourquoi ? Un tableau c&#39;est beaucoup plus difficile à styliser graphiquement, et ça demande beaucoup plus d&#39;effort à produire en termes de HTML. Si j&#39;avais choisi de le faire sous la forme d&#39;un <code>&lt;table&gt;</code> j&#39;aurai dû penser le positionnement des dates dès la génération du HTML par exemple…</p>
<p>Vous noterez aussi que j&#39;ai mis un <code>aria-hidden=&quot;true&quot;</code> sur la liste. En effet j&#39;ai <em>choisi</em> d&#39;exclure cet élément des outils d&#39;accessibilité types lecteurs d&#39;écran. La première raison est que ça n&#39;aurait rien apporté : j&#39;aurais sur ma page une liste de date avec pour chaque s&#39;il y a un article, puis la liste directe des articles… Je dois aussi admettre que je n&#39;avais aucune idée de comment rendre tout ça accessible… Je n&#39;ai pas encore fait le travaille d&#39;auditer l&#39;accessibilité de mon blog avec des outils, je m&#39;en mordrais peut-être les doigts ce jour-là et si c&#39;est le cas j&#39;en reparlerais !</p>
<p>Dans cette liste on peut voir une série de <code>&lt;li&gt;</code> avec chacun un attribut <code>data-date=&quot;yyyy-MM-dd&quot;</code>, c&#39;est simple mais ça fonctionne et vous allez voir que ça va nous servir plus tard ! </p>
<p>On notera que les premiers ont l&#39;attribut <code>data-previous-year=&quot;true&quot;</code>, car comme le nom de l&#39;attribut l&#39;indique : il s&#39;agit des derniers jours de l&#39;année précédente. Pourquoi ? Parce que je veux mettre les jours en colonne par semaine, et que la première semaine de l&#39;année ne commence pas forcément un lundi (ou un dimanche), et que pourtant les derniers jours de l&#39;année sont considérés comme faisant partie de la semaine 1 de l&#39;année suivante (j&#39;imagine pour n&#39;avoir que des semaines complètes).</p>
<p>La date du jour est indiqué aussi avec un attribut spécifique <code>data-today=&quot;true&quot;</code>. Vous verrez que ça nous servira plus tard aussi !</p>
<blockquote>
<p>Note : vous pouvez noter aussi que tous mes attributs personnalisés (et donc non standards) sont préfixés avec <code>data-</code>, sans ça fonctionne mais ce n&#39;est pas du HTML valide, qui oblige à avoir un préfixe <code>data-</code>, l&#39;intérêt de ça c&#39;est aussi que jamais vous n&#39;aurez de conflit avec une éventuelle évolution de la spécification HTML.</p>
</blockquote>
<p>Les dates où j&#39;ai publié un article, dans l&#39;élément <code>&lt;li&gt;</code> on retrouve un lien qui n&#39;a pas de texte (car je n&#39;en ai pas besoin), mais qui a une ancre comme URL et un title. Le title pour commencer indique simplement le nom de l&#39;article, ce qui permet de l&#39;afficher au survol (comportement natif du navigateur). L&#39;ancre c&#39;est moins habituel quand on ne construit pas de site web (par opposition aux logiciels de gestions / web app) : au clic sur un lien ancre, l&#39;URL va changer pour faire apparaitre l&#39;ancre (sans chargement / navigation), et si l&#39;ancre correspond à un élément de la page (comprendre : si l&#39;ancre a la même valeur que l&#39;attribut <code>id</code> d&#39;un élément de la page), le navigateur va scroll jusqu&#39;à cet élément et l&#39;indiquer comme &quot;focus&quot;. On s&#39;en servira plus tard là aussi !</p>
<p>Et visuellement ça donne ça :</p>
<figure>
<img src="https://anthonypena.fr/2026/03/31/creer-une-vue-calendrier-minimaliste-avec-du-html-et-du-css/img/initial-screen.png" alt="Vue de la page avec uniquement les puces de la liste visible" is="img-zoom"/>
<figcaption>Vue de la page avec uniquement les puces de la liste visible</figcaption>
</figure>
<p>Ça fait rêver hein ? Non ? 🤡</p>
<h2 id="article-note-sur-le-theme">Note sur le thème<a href="#article-note-sur-le-theme" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Quitte à faire les choses biens, je vais faire une vue qui fonctionne bien en thème clair et sombre. Et je veux faire les choses proprement, donc je vais utiliser des variables CSS.</p>
<p>Je vous donne les variables de thème que je vais utiliser :</p>
<pre><code class="hljs language-CSS"><span class="hljs-selector-pseudo">:root</span> {
  <span class="hljs-comment">/* ATOMS */</span>
  <span class="hljs-attr">--color--white</span>: <span class="hljs-number">#ffffff</span>;
  <span class="hljs-attr">--color--black</span>: <span class="hljs-number">#121212</span>;
  <span class="hljs-attr">--color--dark-gray</span>: <span class="hljs-number">#333333</span>;
  <span class="hljs-attr">--color--gray</span>: <span class="hljs-number">#6c757d</span>;
  <span class="hljs-attr">--color--light-gray</span>: <span class="hljs-number">#e0e0e0</span>;
  <span class="hljs-attr">--color--blue</span>: <span class="hljs-number">#007bff</span>;
  <span class="hljs-attr">--color--green</span>: <span class="hljs-number">#28a745</span>;
  <span class="hljs-attr">--size--quarter</span>: <span class="hljs-number">0.125rem</span>;
  <span class="hljs-attr">--size--half</span>: <span class="hljs-number">0.25rem</span>;
  <span class="hljs-attr">--size--1</span>: <span class="hljs-number">0.5rem</span>;
  <span class="hljs-attr">--size--2</span>: <span class="hljs-number">1rem</span>;
  <span class="hljs-attr">--size--3</span>: <span class="hljs-number">1.5rem</span>;
  <span class="hljs-attr">--size--4</span>: <span class="hljs-number">2rem</span>;
  <span class="hljs-attr">--size--5</span>: <span class="hljs-number">4rem</span>;

  <span class="hljs-comment">/* MOLECULES */</span>
  <span class="hljs-attr">--color--bg</span>: <span class="hljs-built_in">light-dark</span>(<span class="hljs-built_in">var</span>(--color--white), <span class="hljs-built_in">var</span>(--color--black));
  <span class="hljs-attr">--color--text</span>: <span class="hljs-built_in">light-dark</span>(<span class="hljs-built_in">var</span>(--color--dark-gray), <span class="hljs-built_in">var</span>(--color--light-gray));
  <span class="hljs-attr">--color--primary</span>: <span class="hljs-built_in">var</span>(--color--blue);
  <span class="hljs-attr">--color--secondary</span>: <span class="hljs-built_in">var</span>(--color--gray);
  <span class="hljs-attr">--color--accent</span>: <span class="hljs-built_in">var</span>(--color--green);
  <span class="hljs-attr">--main-text--max-width</span>: <span class="hljs-number">100ch</span>;
  <span class="hljs-attr">--reponsive-main-text-max-width</span>: <span class="hljs-built_in">min</span>(
    <span class="hljs-number">100</span>dvw,
    <span class="hljs-built_in">min</span>(<span class="hljs-number">100vw</span>, <span class="hljs-built_in">var</span>(--main-text--max-width))
  );
}<div aria-hidden="true" class="language-tag">CSS</div>
</code></pre><p>Il n&#39;y a pas de magie, c&#39;est le thème de mon blog (avec quelques variables en moins dont je n&#39;aurai pas du tout besoin). Pour plus de détail sur comment tout ça fonctionne, je vous renvoie vers <a href="/2026/01/21/nouveau-blog-partie-2-css/">mon article sur le style de mon blog</a>.</p>
<p>J&#39;en profite aussi pour rappeler que pour avoir proprement deux thèmes sur votre site, il suffit d&#39;avoir <code>&lt;meta name=&quot;color-scheme&quot; content=&quot;light dark&quot;&gt;</code> dans le <code>&lt;head&gt;</code> de votre page.</p>
<h2 id="article-dune-liste-a-une-grille">D&#39;une liste à une grille<a href="#article-dune-liste-a-une-grille" class="anchor" aria-label="permalink">🔗</a></h2>
<p>L&#39;idée de base c&#39;est d&#39;aligner tous les éléments en colonne, sept par sept jusqu&#39;à les avoir tous mis. De cette façon, la première colonne représente la semaine 1 de l&#39;année, la seconde colonne la semaine 2 et ainsi de suite. Donc on veut une grille qui aura 7 lignes et entre 52 et 54 colonnes. Dans un premier temps : restons sur 53 semaines (le cas le plus courant).</p>
<p>Pour faire ça c&#39;est simple, on va utiliser un <code>display: grid</code> associé à <code>grid-template-columns: repeat(53, var(--overview--border-width))</code> pour avoir 53 colonnes, <code>grid-template-rows: repeat(7, var(--overview--border-width))</code> pour avoir 7 lignes et <code>grid-auto-flow: column</code> pour lui dire de remplir colonne par colonne (par défaut, le layout grid remplit ligne à ligne).</p>
<pre><code class="hljs language-CSS"><span class="hljs-selector-id">#overview</span> {
    <span class="hljs-attr">--overview--day-width</span>: <span class="hljs-built_in">var</span>(--size--<span class="hljs-number">1</span>);

    <span class="hljs-selector-tag">ul</span> {
        <span class="hljs-attribute">display</span>: grid;
        <span class="hljs-attribute">grid-template-columns</span>: <span class="hljs-built_in">repeat</span>(<span class="hljs-number">53</span>, <span class="hljs-built_in">var</span>(--overview--day-width));
        <span class="hljs-attribute">grid-template-rows</span>: <span class="hljs-built_in">repeat</span>(<span class="hljs-number">7</span>, <span class="hljs-built_in">var</span>(--overview--day-width));
        <span class="hljs-attribute">grid-auto-flow</span>: column;
    }
}<div aria-hidden="true" class="language-tag">CSS</div>
</code></pre><p>Notre vue est tout de suite plus compacte !</p>
<figure>
<img src="https://anthonypena.fr/2026/03/31/creer-une-vue-calendrier-minimaliste-avec-du-html-et-du-css/img/grid-no-style.png" alt="Vue avec juste la définition de la grille" is="img-zoom"/>
<figcaption>Vue avec juste la définition de la grille</figcaption>
</figure>
<p>Je ne veux pas un point pour chaque jour, je veux des cercles, avec une bordure fine. Donc pour ça j&#39;ajoute un peu de style sur les <code>&lt;li&gt;</code> :</p>
<pre><code class="hljs language-CSS"><span class="hljs-selector-id">#overview</span> {
    <span class="hljs-attr">--overview--month-border-color</span>: <span class="hljs-built_in">var</span>(--color--secondary);
    <span class="hljs-attr">--overview--day-width</span>: <span class="hljs-built_in">var</span>(--size--<span class="hljs-number">1</span>);
    <span class="hljs-attr">--overview--day-border-radius</span>: <span class="hljs-built_in">calc</span>(<span class="hljs-built_in">var</span>(--overview--day-width) / <span class="hljs-number">2</span>);

    <span class="hljs-selector-tag">ul</span> {
        <span class="hljs-selector-tag">li</span> {
            <span class="hljs-attribute">border</span>: <span class="hljs-number">1px</span> solid <span class="hljs-built_in">var</span>(--overview--month-border-color);
            <span class="hljs-attribute">border-radius</span>: <span class="hljs-built_in">var</span>(--overview--day-border-radius);
            <span class="hljs-attribute">width</span>: <span class="hljs-built_in">var</span>(--overview--day-width);
            <span class="hljs-attribute">height</span>: <span class="hljs-built_in">var</span>(--overview--day-width);
            <span class="hljs-attribute">padding</span>: <span class="hljs-number">0</span>;
            <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span>;
        }
    }
}<div aria-hidden="true" class="language-tag">CSS</div>
</code></pre><figure>
<img src="https://anthonypena.fr/2026/03/31/creer-une-vue-calendrier-minimaliste-avec-du-html-et-du-css/img/grid-with-dots.png" alt="Vue avec les jours en forme de cercle" is="img-zoom"/>
<figcaption>Vue avec les jours en forme de cercle</figcaption>
</figure>
<p>C&#39;est un peu mieux, mais il y a toujours les puces des différents <code>&lt;li&gt;</code> et on a aussi le padding-left natif des listes (c&#39;est ça qui permet à la fois de laisser de la place pour les puces et que les listes soient de base un peu indentée par rapport au reste du texte). Corrigeons ça ! Et au passage on va ajouter un peu d&#39;espace entre les cercles pour que ce ne soit plus tout tassé !</p>
<pre><code class="hljs language-CSS"><span class="hljs-selector-id">#overview</span> {
    <span class="hljs-attr">--overview--padding</span>: <span class="hljs-built_in">var</span>(--size--half);

    <span class="hljs-selector-tag">ul</span> {
        <span class="hljs-attribute">list-style-type</span>: none;
        <span class="hljs-attribute">gap</span>: <span class="hljs-number">1px</span>;
        <span class="hljs-attribute">padding</span>: <span class="hljs-built_in">var</span>(--overview--padding);
    }
}<div aria-hidden="true" class="language-tag">CSS</div>
</code></pre><figure>
<img src="https://anthonypena.fr/2026/03/31/creer-une-vue-calendrier-minimaliste-avec-du-html-et-du-css/img/grid-white.png" alt="Grille minimaliste sans aucune indication" is="img-zoom"/>
<figcaption>Grille minimaliste sans aucune indication</figcaption>
</figure>
<p>On a notre grille propre. Il ne reste plus qu&#39;à mettre en avant les éléments :</p>
<ul>
<li>masquer les jours de l&#39;année précédente en effaçant la bordure les <code>&lt;li&gt;</code> avec l&#39;attribut <code>data-previous-year</code> ;</li>
<li>ajouter un fond pour les <code>&lt;li&gt;</code> qui contiennent un élément <code>&lt;a&gt;</code> (pour mettre en évidence les jours avec un article) ;</li>
<li>ajouter une bordure colorée pour la date du jour (les <code>&lt;li&gt;</code> qui ont l&#39;attribut <code>data-today</code>) ;</li>
</ul>
<p>Pour faire tout ça on va utiliser des sélecteurs sur attribut (<code>li[data-today]</code> par exemple) et le pseudo-sélecteur <code>:has()</code> (<code>:has(a)</code> par exemple).</p>
<p>Je vais aussi en profiter pour faire en sorte que le lien ancre vers l&#39;article prenne toute la place dans le cercle, ça va permettre de cliquer n&#39;importe où dans le cercle pour accéder à l&#39;ancre.</p>
<pre><code class="hljs language-CSS"><span class="hljs-selector-id">#overview</span> {
    <span class="hljs-attr">--overview--today-border-color</span>: <span class="hljs-built_in">var</span>(--color--accent);
    <span class="hljs-attr">--overview--with-article-color</span>: <span class="hljs-built_in">var</span>(--color--primary);

    <span class="hljs-selector-tag">ul</span> {
        <span class="hljs-selector-tag">li</span> {
            &amp;<span class="hljs-selector-attr">[data-previous-year]</span> {
                <span class="hljs-attribute">border</span>: none;
            }

            &amp;<span class="hljs-selector-attr">[data-today]</span> {
                <span class="hljs-attribute">border-color</span>: <span class="hljs-built_in">var</span>(--overview--today-border-color);
                <span class="hljs-attribute">border-width</span>: <span class="hljs-number">2px</span>;
            }

            &amp;<span class="hljs-selector-pseudo">:has</span>(<span class="hljs-selector-tag">a</span>) {
                <span class="hljs-attribute">background-color</span>: <span class="hljs-built_in">var</span>(--overview--with-article-color);
                <span class="hljs-selector-tag">a</span> {
                    <span class="hljs-attribute">display</span>: block;
                    <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
                    <span class="hljs-attribute">height</span>: <span class="hljs-number">100%</span>;
                }
            }
        }
    }
}<div aria-hidden="true" class="language-tag">CSS</div>
</code></pre><figure>
<img src="https://anthonypena.fr/2026/03/31/creer-une-vue-calendrier-minimaliste-avec-du-html-et-du-css/img/grid-with-color.png" alt="Vue de la grille en mettant en évidence les éléments intéressants" is="img-zoom"/>
<figcaption>Vue de la grille en mettant en évidence les éléments intéressants</figcaption>
</figure>
<p>On peut encore faire mieux ! </p>
<p>Et si on colorait différemment la bordure des mois pair ? Sans ajouter quoi que ce soit au HTML évidemment ! On va utiliser un sélecteur d&#39;attribut qui se base sur sa valeur : <code>li[data-date*=&quot;-02-&quot;]</code> signifie &quot;tous les <code>&lt;li&gt;</code> qui ont l&#39;attribut <code>data-date</code> avec une valeur contenant (<code>*=</code>) la chaîne de caractère <code>-02-</code>&quot;, autrement dit pour nous &quot;tous les <code>&lt;li&gt;</code> de février. Et donc il suffit de faire pareil pour les autres mois. </p>
<p>On va aussi utiliser une fonctionnalité récente de CSS : les couleurs relatives. L&#39;idée c&#39;est de pouvoir prendre la valeur d&#39;une couleur et changer juste une partie des valeurs, dans mon cas je vais prendre la couleur <code>--overview--month-border-color</code> et réduire de 30% son opacité en passant le canal alpha à 0.7, ça permet que la couleur s&#39;adapte au thème automatiquement sans me casser la tête.</p>
<p>Au passage je renomme <code>--overview--month-border-color</code> en <code>--overview--odd-month-border-color</code> pour être plus logique.</p>
<pre><code class="hljs language-CSS"><span class="hljs-selector-id">#overview</span> {
    <span class="hljs-attr">--overview--odd-month-border-color</span>: <span class="hljs-built_in">var</span>(--color--secondary);
    <span class="hljs-attr">--overview--even-month-border-color</span>: <span class="hljs-built_in">rgb</span>(from <span class="hljs-built_in">var</span>(--overview--odd-month-border-color) r g b / <span class="hljs-number">0.7</span>);

    <span class="hljs-selector-tag">ul</span> {

        <span class="hljs-selector-tag">li</span> {
            <span class="hljs-attribute">border</span>: <span class="hljs-number">1px</span> solid <span class="hljs-built_in">var</span>(--overview--odd-month-border-color);

            &amp;<span class="hljs-selector-attr">[data-date*=<span class="hljs-string">&quot;-02-&quot;</span>]</span>, &amp;<span class="hljs-selector-attr">[data-date*=<span class="hljs-string">&quot;-04-&quot;</span>]</span>,
            &amp;<span class="hljs-selector-attr">[data-date*=<span class="hljs-string">&quot;-06-&quot;</span>]</span>, &amp;<span class="hljs-selector-attr">[data-date*=<span class="hljs-string">&quot;-08-&quot;</span>]</span>,
            &amp;<span class="hljs-selector-attr">[data-date*=<span class="hljs-string">&quot;-10-&quot;</span>]</span>, &amp;<span class="hljs-selector-attr">[data-date*=<span class="hljs-string">&quot;-12-&quot;</span>]</span> {
                <span class="hljs-attribute">border-color</span>: <span class="hljs-built_in">var</span>(--overview--even-month-border-color);
            }
        }
    }
}<div aria-hidden="true" class="language-tag">CSS</div>
</code></pre><figure>
<img src="https://anthonypena.fr/2026/03/31/creer-une-vue-calendrier-minimaliste-avec-du-html-et-du-css/img/grid-with-months.png" alt="Avec les mois en évidence" is="img-zoom"/>
<figcaption>Avec les mois en évidence</figcaption>
</figure>
<p>Comme on connaît la date du jour, on pourrait aussi rendre moins visible les jours des dates dans le futur. Toujours sans rien ajouter au HTML évidemment. Facile avec le combinateur &quot;frère suivant&quot; (Subsequent-sibling Combinator en anglais) : <code>li[data-today] ~ li</code> va indiquer qu&#39;on veut sélectionner tous les <code>&lt;li&gt;</code> qui suivent un <code>&lt;li data-today&gt;</code>.</p>
<pre><code class="hljs language-CSS"><span class="hljs-selector-id">#overview</span> {
    <span class="hljs-selector-tag">ul</span> {
        <span class="hljs-selector-tag">li</span><span class="hljs-selector-attr">[data-today]</span> ~ <span class="hljs-selector-tag">li</span> {
            <span class="hljs-attribute">opacity</span>: <span class="hljs-number">0.5</span>;
        }
    }
}<div aria-hidden="true" class="language-tag">CSS</div>
</code></pre><figure>
<img src="https://anthonypena.fr/2026/03/31/creer-une-vue-calendrier-minimaliste-avec-du-html-et-du-css/img/grid-futur-dates.png" alt="Vue avec les dates futures identifiées" is="img-zoom"/>
<figcaption>Vue avec les dates futures identifiées</figcaption>
</figure>
<p>Facile non ?</p>
<h2 id="article-52-a-54-semaines-par-an">52 à 54 semaines par an…<a href="#article-52-a-54-semaines-par-an" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Il manque un dernier truc : comment on gère le fait d&#39;avoir entre 52 et 54 semaines ? Et dans quels cas ça arrive ?</p>
<p>Je vous ai mis un article qui détaille tout ça dans les sources mais pour résumé : je suis français, je suis donc dans une zone qui fonctionne en ISO 8601, donc je vais me baser là-dessus (en Amérique du Nord ce serait différent par exemple).</p>
<p>Pour faire un résumé grossier : </p>
<ul>
<li>mathématiquement : une année c&#39;est 52 semaines (7 jours x 52 semaines = 364 jours) + 1 à 2 jours (2j si c&#39;est une année bissextile) ;</li>
<li>mais comme les années ne sont pas sur un nombre de jour divisible par 7, les jours de la première semaine de l&#39;année se décale d&#39;année en année et la dernière semaine de l&#39;année est souvent la même semaine que la première de l&#39;année suivante ;</li>
<li>la règle est simple : si le 1er janvier tombe entre le lundi et jeudi inclus, les derniers jours de l&#39;année N-1 et les premiers de l&#39;année N sont comptés comme la semaine 1, si le 1er janvier tombe entre le vendredi et le dimanche inclus, ces mêmes jours sont la dernière semaine de l&#39;année N-1 (donc semaine 53) ;</li>
<li>en cas d&#39;année bissextile où le 1er janvier est un dimanche (dernier jour de la semaine en ISO), alors le 31 décembre sera un lundi (premier jour de la semaine en ISO), on aura donc 54 semaines à afficher ;</li>
</ul>
<blockquote>
<p>Note : je vous laisse regarder plus en détail le site que j&#39;ai mis en source, mais il n&#39;y a qu&#39;en notation américaine qu&#39;on aura une semaine numérotée 54, pas en calendrier ISO.</p>
</blockquote>
<p>Bon et du coup, pour nous on fait comment ? On fait des calculs savants pour gérer ça ? 🤔</p>
<p>Plus simple : on se pose pour voir le problème autrement et on laisse CSS se débrouiller. 😇</p>
<p>Le cas 52 semaines à afficher n&#39;arrivera jamais à cause du nombre de jour dans l&#39;année, sur une année de 365 jours, les cas les plus extrêmes ce sera 52 semaines pleines et une journée toute seule soit au début (comme 2026, le 1er janvier est un dimanche, tout seul sur sa semaine) soit à la fin (comme en 2028, où le 1er janvier est un lundi, et le 31 décembre un lundi aussi). 53 semaines sera notre cas par défaut le plus courant. </p>
<p>Et de temps en temps, on aura une 54ème semaine qui va apparaitre. Quand on aura 366 jours dans l&#39;année uniquement, et dans le cas où le premier jour de l&#39;année et le dernier jours de l&#39;année sont seuls sur leur semaine. En d&#39;autres mots : on aura 366 jours affichés + 6 jours de l&#39;année précédente qui sont masqués mais sont là pour l&#39;alignement ; donc on aura 54 semaines si on a 372 <code>&lt;li&gt;</code> dans notre liste <code>&lt;ul&gt;</code>, et ça c&#39;est facile à gérer en CSS !</p>
<pre><code class="hljs language-CSS"><span class="hljs-selector-id">#overview</span> {
    <span class="hljs-selector-tag">ul</span> {
        &amp;<span class="hljs-selector-pseudo">:has</span>(<span class="hljs-selector-tag">li</span><span class="hljs-selector-pseudo">:nth-child</span>(<span class="hljs-number">372</span>)) {
            <span class="hljs-attribute">grid-template-columns</span>: <span class="hljs-built_in">repeat</span>(<span class="hljs-number">54</span>, <span class="hljs-built_in">var</span>(--overview--day-width));
        }
    }
}<div aria-hidden="true" class="language-tag">CSS</div>
</code></pre><h2 id="article-mettre-en-avant-lelement-selectionne">Mettre en avant l&#39;élément sélectionné<a href="#article-mettre-en-avant-lelement-selectionne" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Je l&#39;expliquais un peu plus haut : quand on clique sur un de mes liens dans la vue calendrier, on va créer une ancre dans l&#39;URL :</p>
<figure>
<img src="https://anthonypena.fr/2026/03/31/creer-une-vue-calendrier-minimaliste-avec-du-html-et-du-css/img/url-with-anchor.png" alt="Ancre vue dans la barre d&#39;URL" is="img-zoom"/>
<figcaption>Ancre vue dans la barre d&#39;URL</figcaption>
</figure>
<p>Eh bien en CSS l&#39;élément qui possède l&#39;id de même valeur pourra être sélectionné avec le pseudo-sélecteur <code>:target</code>.</p>
<p>Donc je peux faire une mise en avant toute simple avec :</p>
<pre><code class="hljs language-CSS"><span class="hljs-selector-id">#previous-posts</span> {
    <span class="hljs-selector-tag">ul</span> {
        <span class="hljs-selector-tag">li</span> {
            <span class="hljs-selector-tag">a</span> {
                &amp;<span class="hljs-selector-pseudo">:target</span> {
                    <span class="hljs-attribute">color</span>: <span class="hljs-built_in">var</span>(--color--primary)
                }
            }
        }
    }
}<div aria-hidden="true" class="language-tag">CSS</div>
</code></pre><figure>
<img src="https://anthonypena.fr/2026/03/31/creer-une-vue-calendrier-minimaliste-avec-du-html-et-du-css/img/target-focus.png" alt="Mise en avant de la cible de l&#39;ancre" is="img-zoom"/>
<figcaption>Mise en avant de la cible de l&#39;ancre</figcaption>
</figure>
<h2 id="article-conclusion">Conclusion<a href="#article-conclusion" class="anchor" aria-label="permalink">🔗</a></h2>
<p>À la base quand j&#39;ai ajouté ça à mon blog, je ne pensais pas en faire un article : je me suis amusé à ajouter ça, puis j&#39;ai pris un pas de recul en me disant que y&#39;avait des trucs intéressants à montrer et expliquer ! Surtout à l&#39;heure des LLMs qui crachent du Tailwind les yeux fermés à longueur de temps alors qu&#39;on pourrait faire tellement plus simple en CSS… Mais bref !</p>
<p>On aurait pu faire des choses très différentes visuellement, même en se basant sur des mécaniques très similaires côté sélecteurs. Mais là on parle d&#39;une question de goût / choix. J&#39;ai choisi de faire quelque chose de très simple et minimaliste parce que c&#39;est ça que j&#39;avais envie de faire !</p>
<p>À noter que j&#39;ai une particularité sur le blog : je compte mes années de mars à février, donc j&#39;ai décalé mes archives pour caler à ce cycle. Maintenant : ça ne change rien à tout ce que j&#39;ai décrit dans cet article, simplement, ne comparez pas les jours exacts avec mon blog, vous allez vous arracher les cheveux !</p>
<p>Sources :</p>
<ul>
<li><a href="https://kuroidoruido.github.io/css-is-magic/minimalist-calendar-view/index.html">Démonstration interactive</a></li>
<li><a href="https://github.com/kuroidoruido/css-is-magic/blob/main/minimalist-calendar-view/">Code source de la démo</a></li>
<li><a href="https://sacreesblogueuses.com/combien-de-semaines-dans-une-annee-52-ou-53-selon-le-calendrier/">Combien de semaines dans une année : 52 ou 53 selon le calendrier</a></li>
<li><a href="https://www.w3schools.com/Css/css_combinators.asp">CSS Combinators (w3schools)</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Colors/Using_relative_colors">Using relative colors (mdn)</a></li>
</ul>
<p>Crédit photo : Générée via Mistral AI avec le prompt suivant : </p>
<blockquote>
<p>A cozy wooden desk bathed in soft golden light, reminiscent of a late autumn afternoon. The centerpiece is a large wooden calendar, intricately carved with circular reliefs representing each day of the year. Some circles are illuminated in soft blue or green, symbolizing published articles. A red panda, sitting on a cushion in the bottom right corner (occupying less than 1/3 of the height), is gently painting one of the calendar circles with a fine brush. The red panda is slightly turned in a 3/4 back view, surrounded by a subtle halo of light and 8-10 floating maple leaves in shades of red, orange, and yellow. Around the calendar, faint holograms display snippets of CSS/HTML code and dates, blending seamlessly into the scene. The atmosphere is warm, poetic, and dreamlike, inspired by Studio Ghibli&#39;s style, with a harmonious mix of organic textures (wood, fabric) and subtle high-tech elements (holograms with wooden frames). The overall mood is immersive, cozy, and magical, evoking a sense of timeless creativity and reflection.</p>
</blockquote>
]]></content:encoded>
      <dc:creator><![CDATA[Anthony Pena]]></dc:creator>
      <media:content medium="image" url="https://anthonypena.fr/img/cover.min.jpg"/>
    </item>
    <item>
      <title><![CDATA[Créer un composant Tabs avec Angular]]></title>
      <guid isPermaLink="false">2026/03/24/creer-composants-tabs-avec-angular</guid>
      <description><![CDATA[<p>Récemment j&#39;ai eu besoin de créer un composant Tabs pour une vue avec des onglets. Ce n&#39;est pas très…</p>
]]></description>
      <link>https://anthonypena.fr/2026/03/24/creer-composants-tabs-avec-angular/index.html</link>
      <category><![CDATA[Angular]]></category>
      <category><![CDATA[Frontend]]></category>
      <pubDate>Tue, 24 Mar 2026 07:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>Récemment j&#39;ai eu besoin de créer un composant Tabs pour une vue avec des onglets. Ce n&#39;est pas très compliqué, mais il y a quelques trucs intéressants à faire pour avoir des éléments très simples à manipuler en tant que consommateur du composant, avec peu d&#39;effort de maintenance ensuite.</p>
<blockquote>
<p>Note : pour cet article j&#39;ai créé un projet Angular en version 21 et j&#39;ai décidé de suivre la nouvelle convention de nommage des fichiers (sans les suffixes <code>.component</code>, <code>.service</code>, etc.), vous êtes évidemment libre de suivre l&#39;ancienne convention.</p>
</blockquote>
<p>Tout le code montré ici est disponible dans un projet prêt à lancer ici : <a href="https://github.com/kuroidoruido/ng-tabs-sample">https://github.com/kuroidoruido/ng-tabs-sample</a></p>
<h2 id="article-le-style">Le style<a href="#article-le-style" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Je ne vais pas m&#39;attarder sur la partie style. Pas que ça n&#39;ait aucun intérêt, mais il y a pléthore d&#39;exemples et finalement ce n&#39;est pas très intéressant à détailler ici à mon sens. Je vais donc faire un style assez minimaliste (et un peu incomplet) mais suffisant pour que ça fonctionne !</p>
<p>Le HTML :</p>
<pre><code class="hljs language-HTML"><span class="hljs-tag">&lt;<span class="hljs-name">section</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;tab-group&quot;</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">nav</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;tab-headers&quot;</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;tab-header&quot;</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">data-tab</span>=<span class="hljs-string">&quot;tab-1&quot;</span>&gt;</span>Tab 1<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;tab-header active&quot;</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">data-tab</span>=<span class="hljs-string">&quot;tab-2&quot;</span>&gt;</span>Tab 2<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;tab-header&quot;</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">data-tab</span>=<span class="hljs-string">&quot;tab-3&quot;</span>&gt;</span>Tab 3<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">nav</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">section</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;tab-content&quot;</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;tab-1&quot;</span>&gt;</span>
    ...
  <span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">section</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;tab-content active&quot;</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;tab-2&quot;</span>&gt;</span>
    ...
  <span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">section</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;tab-content&quot;</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;tab-3&quot;</span>&gt;</span>
    ...
  <span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span><div aria-hidden="true" class="language-tag">HTML</div>
</code></pre><p>Le style qui va avec :</p>
<pre><code class="hljs language-CSS"><span class="hljs-selector-tag">section</span><span class="hljs-selector-class">.tab-group</span> {
    <span class="hljs-attr">--color--gray</span>: <span class="hljs-number">#ccc</span>;
    <span class="hljs-attr">--color--gray-dark</span>: <span class="hljs-number">#999</span>;

    <span class="hljs-attr">--border--color</span>: <span class="hljs-built_in">var</span>(--color--gray);
    <span class="hljs-attr">--border--width</span>: <span class="hljs-number">1px</span>;
    <span class="hljs-selector-tag">nav</span><span class="hljs-selector-class">.tab-headers</span> {
        <span class="hljs-selector-tag">ul</span> {
            <span class="hljs-attribute">display</span>: flex;
            <span class="hljs-attribute">list-style</span>: none;
            <span class="hljs-attribute">padding</span>: <span class="hljs-number">0</span>;
            <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span>;
            <span class="hljs-attribute">border-bottom</span>: <span class="hljs-built_in">var</span>(--border--width) solid <span class="hljs-built_in">var</span>(--border--color);
        }
        <span class="hljs-selector-class">.tab-header</span> {
            <span class="hljs-attribute">border</span>: <span class="hljs-built_in">var</span>(--border--width) solid <span class="hljs-built_in">var</span>(--border--color);
            <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">0.5rem</span> <span class="hljs-number">0.5rem</span> <span class="hljs-number">0</span> <span class="hljs-number">0</span>;
            <span class="hljs-attribute">border-bottom-color</span>: white;
            <span class="hljs-attribute">padding</span>: <span class="hljs-number">0</span>;
            <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-built_in">calc</span>(-<span class="hljs-number">1</span> * <span class="hljs-built_in">var</span>(--border--width));
            
            <span class="hljs-selector-tag">button</span> {
                <span class="hljs-attribute">padding</span>: <span class="hljs-number">0.5rem</span> <span class="hljs-number">1.5rem</span>;
                <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
                <span class="hljs-attribute">height</span>: <span class="hljs-number">100%</span>;
                <span class="hljs-attribute">background</span>: none;
                <span class="hljs-attribute">border</span>: none;
                <span class="hljs-attribute">cursor</span>: pointer;
            }
            
            &amp;<span class="hljs-selector-pseudo">:hover</span> {
                <span class="hljs-attribute">border-color</span>: <span class="hljs-built_in">var</span>(--color--gray-dark);
            }

            &amp;<span class="hljs-selector-pseudo">:not</span>(<span class="hljs-selector-class">.active</span>) {
                <span class="hljs-attribute">background-color</span>: <span class="hljs-built_in">var</span>(--border--color);
                <span class="hljs-attribute">border-bottom-color</span>: <span class="hljs-built_in">var</span>(--border--color);
                <span class="hljs-selector-tag">button</span> {
                    <span class="hljs-attribute">color</span>: black;
                }
            }
        }
    }
    
    <span class="hljs-selector-class">.tab-content</span> {
        <span class="hljs-attribute">display</span>: none;
        <span class="hljs-attribute">border</span>: <span class="hljs-built_in">var</span>(--border--width) solid <span class="hljs-built_in">var</span>(--border--color);
        <span class="hljs-attribute">border-top</span>: none;
        <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">0</span> <span class="hljs-number">0</span> <span class="hljs-number">0.5rem</span> <span class="hljs-number">0.5rem</span>;
        <span class="hljs-attribute">padding</span>: <span class="hljs-number">0.5rem</span> <span class="hljs-number">1rem</span>;

        &amp; &gt; <span class="hljs-selector-pseudo">:first-child</span> {
            <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">0</span>;
            <span class="hljs-attribute">padding-top</span>: <span class="hljs-number">0</span>;
        }
        &amp; &gt; <span class="hljs-selector-pseudo">:last-child</span> {
            <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">0</span>;
            <span class="hljs-attribute">padding-bottom</span>: <span class="hljs-number">0</span>;
        }

        &amp;<span class="hljs-selector-class">.active</span> {
            <span class="hljs-attribute">display</span>: block;
        }
    }
}<div aria-hidden="true" class="language-tag">CSS</div>
</code></pre><figure>
<img src="https://anthonypena.fr/2026/03/24/creer-composants-tabs-avec-angular/img/html-css-screenshot.png" alt="Vu avec seulement HTML et CSS" is="img-zoom"/>
<figcaption>Vu avec seulement HTML et CSS</figcaption>
</figure>
<p>Maintenant on passe à ce qui est intéressant !</p>
<h2 id="article-cote-utilisation">Côté utilisation<a href="#article-cote-utilisation" class="anchor" aria-label="permalink">🔗</a></h2>
<p>J&#39;ai fait quelque chose d&#39;assez simple côté DOM, mais je n&#39;ai pas trop ce genre de code sur le tous les jours en mode composant : ça devient vite un énorme monolithe, avec la logique des onglets perdue au milieu de la logique métier, quand on a pas plusieurs occurrences du composant avec de la duplication… Et bonus : dans 2-3 ans, le style va évoluer et il va falloir repasser sur toutes les occurrences du composant pour changer, en prenant en compte les &quot;quelques petites améliorations/corrections&quot; locales à chaque occurrence…</p>
<p>Bref : si je travaille avec un framework, je n&#39;utilise pas directement le HTML, je vais cacher ça dans un composant avec un DSL propre qui s&#39;adapte bien à mon projet (pas forcément tous les projets). C&#39;est aussi vrai pour pas mal de briques du genre.</p>
<p>Voilà ce que je veux écrire :</p>
<pre><code class="hljs language-HTML"><span class="hljs-tag">&lt;<span class="hljs-name">app-tab-group</span> <span class="hljs-attr">default</span>=<span class="hljs-string">&quot;tab-2&quot;</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">nav</span> <span class="hljs-attr">app-tab-headers</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">app-tab</span>=<span class="hljs-string">&quot;tab-1&quot;</span>&gt;</span>Tab 1<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">app-tab</span>=<span class="hljs-string">&quot;tab-2&quot;</span>&gt;</span>Tab 2<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">app-tab</span>=<span class="hljs-string">&quot;tab-3&quot;</span>&gt;</span>Tab 3<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">nav</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">section</span> <span class="hljs-attr">app-tab-content</span>=<span class="hljs-string">&quot;tab-1&quot;</span>&gt;</span>
        ...
    <span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">section</span> <span class="hljs-attr">app-tab-content</span>=<span class="hljs-string">&quot;tab-2&quot;</span>&gt;</span>
        ...
    <span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">section</span> <span class="hljs-attr">app-tab-content</span>=<span class="hljs-string">&quot;tab-3&quot;</span>&gt;</span>
        ...
    <span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">app-tab-group</span>&gt;</span><div aria-hidden="true" class="language-tag">HTML</div>
</code></pre><p>Ce n&#39;est pas si différent que ça de la version HTML pure. Ça va me permettre de ne pas ajouter d&#39;élément dans le DOM en plus de ce qui est requis, car certains styles d&#39;entreprise utilisent des sélecteurs du type <code>.tab-group &gt; .tab-headers</code> (pour cibler le <code>.tab-headers</code> qui est l&#39;enfant direct de <code>.tab-group</code>), donc vous ne pouvez pas intercaler d&#39;éléments.</p>
<p>On reste un peu proche du DOM d&#39;origine avec les <code>&lt;li&gt;</code> et <code>&lt;section&gt;</code> qui sont toujours là, mais on s&#39;est débarrassé de toutes les classes et on va pouvoir gérer facilement un peu tout proprement chacun de son côté !</p>
<h2 id="article-construisons-les-composants">Construisons les composants<a href="#article-construisons-les-composants" class="anchor" aria-label="permalink">🔗</a></h2>
<p>La première étape c&#39;est de construire les différents composants :</p>
<ul>
<li><code>&lt;app-tab-group&gt;</code> : qui sera notre composant parent ;</li>
<li><code>[app-tab-headers]</code> : qui va contenir nos titres d&#39;onglet ;</li>
<li><code>[app-tab]</code> : qui va gérer chaque titre d&#39;onglet individuellement ;</li>
<li><code>[app-tab-content]</code> : qui va gérer le contenu de chaque onglet ;</li>
</ul>
<p>Les rôles sont bien divisés. Chaque composant a un rôle bien défini et on va pouvoir faire des petits composants !</p>
<p>Personnellement ce genre de brique réutilisable plutôt générique, je les place dans un dossier <code>shared/components</code> (ou quelque chose de similaire en fonction des conventions de l&#39;équipe / du projet), avec un fichier <code>index.ts</code> pour directement pouvoir importer un peu partout nos différentes briques. L&#39;intérêt du <code>index.ts</code> ici c&#39;est qu&#39;on va pouvoir assez facilement refactorer / déplacer nos composants / fichiers sans forcément avoir des changements d&#39;import partout dans l&#39;application (ça évite donc du bruit dans les relectures de code).</p>
<pre><code class="hljs language-TypeScript"><span class="hljs-comment">// src/app/shared/components/tabs/index.ts</span>
<span class="hljs-keyword">export</span> * <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;./tab-group&#x27;</span>
<span class="hljs-keyword">export</span> * <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;./tab-headers&#x27;</span>
<span class="hljs-keyword">export</span> * <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;./tab&#x27;</span>
<span class="hljs-keyword">export</span> * <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;./tab-content&#x27;</span>;<div aria-hidden="true" class="language-tag">TypeScript</div>
</code></pre><p>Pour le composant <code>app-tab-group</code> c&#39;est simplement un composant conteneur qui ne fait rien (pour l&#39;instant en tout cas) :</p>
<pre><code class="hljs language-TypeScript"><span class="hljs-comment">// src/app/shared/components/tabs/tab-group.ts</span>
<span class="hljs-keyword">import</span> { <span class="hljs-title class_">Component</span>, input } <span class="hljs-keyword">from</span> <span class="hljs-string">&quot;@angular/core&quot;</span>;

<span class="hljs-meta">@Component</span>({
    <span class="hljs-attr">selector</span>: <span class="hljs-string">&quot;app-tab-group&quot;</span>,
    <span class="hljs-attr">template</span>: <span class="hljs-string">`
    &lt;section class=&quot;tab-group&quot;&gt;
        &lt;ng-content /&gt;
    &lt;/section&gt;`</span>,
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">TabGroup</span> {
    <span class="hljs-keyword">default</span> = input.<span class="hljs-property">required</span>&lt;<span class="hljs-built_in">string</span>&gt;();
}<div aria-hidden="true" class="language-tag">TypeScript</div>
</code></pre><p>On voit le paramètre <code>default</code> qui est défini mais on ne s&#39;en sert pas pour l&#39;instant.</p>
<p>Les composants <code>app-tab-headers</code> et <code>app-tab</code> sont assez similaires à part que leur sélecteur se base sur un attribut et pas un élément, et qu&#39;on va retrouver l&#39;utilisation de <code>host</code> pour définir des attributs sur l&#39;élément qui va porter l&#39;attribut : </p>
<pre><code class="hljs language-TypeScript"><span class="hljs-comment">// src/app/shared/components/tabs/tab-headers.ts</span>
<span class="hljs-keyword">import</span> { <span class="hljs-title class_">Component</span> } <span class="hljs-keyword">from</span> <span class="hljs-string">&quot;@angular/core&quot;</span>;

<span class="hljs-meta">@Component</span>({
    <span class="hljs-attr">selector</span>: <span class="hljs-string">&quot;[app-tab-headers]&quot;</span>,
    <span class="hljs-attr">host</span>: {
        <span class="hljs-string">&quot;[class.tab-headers]&quot;</span>: <span class="hljs-string">&quot;true&quot;</span>,
    },
    <span class="hljs-attr">template</span>: <span class="hljs-string">`
    &lt;nav class=&quot;tab-headers&quot;&gt;
        &lt;ul&gt;
            &lt;ng-content /&gt;
        &lt;/ul&gt;
    &lt;/nav&gt;`</span>,
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">TabHeaders</span> {}<div aria-hidden="true" class="language-tag">TypeScript</div>
</code></pre><pre><code class="hljs language-TypeScript"><span class="hljs-comment">// src/app/shared/components/tabs/tab.ts</span>
<span class="hljs-keyword">import</span> { <span class="hljs-title class_">Component</span>, input } <span class="hljs-keyword">from</span> <span class="hljs-string">&quot;@angular/core&quot;</span>;

<span class="hljs-meta">@Component</span>({
    <span class="hljs-attr">selector</span>: <span class="hljs-string">&quot;[app-tab]&quot;</span>,
    <span class="hljs-attr">host</span>: {
        <span class="hljs-string">&quot;[class.tab-header]&quot;</span>: <span class="hljs-string">&quot;true&quot;</span>,
        <span class="hljs-string">&quot;[attr.data-tab]&quot;</span>: <span class="hljs-string">&quot;tab()&quot;</span>,
    },
    <span class="hljs-attr">template</span>: <span class="hljs-string">`
    &lt;button [attr.data-tab]=&quot;tab()&quot;&gt;
        &lt;ng-content /&gt;
    &lt;/button&gt;
    `</span>,
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">Tab</span> {
    tab = input.<span class="hljs-property">required</span>&lt;<span class="hljs-built_in">string</span>&gt;({ <span class="hljs-attr">alias</span>: <span class="hljs-string">&quot;app-tab&quot;</span> });
}<div aria-hidden="true" class="language-tag">TypeScript</div>
</code></pre><blockquote>
<p>Note : on aurait pu se passer de l&#39;alias sur l&#39;input <code>tab</code> mais je trouve ça plus simple d&#39;écrire <code>&lt;li app-tab=&quot;tab-1&quot;&gt;Tab 1&lt;/li&gt;</code> que d&#39;écrire <code>&lt;li app-tab tab=&quot;tab-1&quot;&gt;Tab 1&lt;/li&gt;</code>.</p>
</blockquote>
<p>On retrouve ensuite <code>app-tab-content</code> qui est assez simple avec rien d&#39;original par rapport aux autres composants : </p>
<pre><code class="hljs language-TypeScript"><span class="hljs-comment">// src/app/shared/components/tabs/tab-content.ts</span>
<span class="hljs-keyword">import</span> { <span class="hljs-title class_">Component</span>, input } <span class="hljs-keyword">from</span> <span class="hljs-string">&quot;@angular/core&quot;</span>;

<span class="hljs-meta">@Component</span>({
    <span class="hljs-attr">selector</span>: <span class="hljs-string">&quot;[app-tab-content]&quot;</span>,
    <span class="hljs-attr">host</span>: {
        <span class="hljs-string">&quot;[class.tab-content]&quot;</span>: <span class="hljs-string">&quot;true&quot;</span>,
        <span class="hljs-string">&quot;[class.active]&quot;</span>: <span class="hljs-string">&quot;true&quot;</span>,
        <span class="hljs-string">&quot;[attr.id]&quot;</span>: <span class="hljs-string">&quot;tab()&quot;</span>,
    },
    <span class="hljs-attr">template</span>: <span class="hljs-string">&quot;&lt;ng-content /&gt;&quot;</span>,
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">TabContent</span> {
    tab = input.<span class="hljs-property">required</span>&lt;<span class="hljs-built_in">string</span>&gt;({ <span class="hljs-attr">alias</span>: <span class="hljs-string">&quot;app-tab-content&quot;</span> });
}<div aria-hidden="true" class="language-tag">TypeScript</div>
</code></pre><p>En l&#39;état ça ne fonctionne évidemment pas, et on voit à la fois tout le contenu et tous les onglets en version inactive.</p>
<figure>
<img src="https://anthonypena.fr/2026/03/24/creer-composants-tabs-avec-angular/img/static-angular-screenshot.png" alt="Version non finie mais en composant Angular" is="img-zoom"/>
<figcaption>Version non finie mais en composant Angular</figcaption>
</figure>
<h2 id="article-creer-un-etat-partage-entre-tout-le-monde">Créer un état partagé entre tout le monde<a href="#article-creer-un-etat-partage-entre-tout-le-monde" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Maintenant on se pose et on réfléchit : on a besoin qu&#39;à chaque clic sur un onglet, on indique aux contenus qu&#39;ils doivent se masquer / s&#39;afficher. Donc il faut que les composants <code>app-tab</code> puissent communiquer avec les composants <code>app-tab-content</code>.</p>
<p>L&#39;option de base serait d&#39;avoir un service global qui gère tous les onglets et tous les groupes d&#39;onglets, garde un identifiant pour chaque, se débrouille pour tout track, et nettoyer quand y&#39;a besoin, etc. Mais non : ça parait simple mais en fait c&#39;est plein de complexités…</p>
<p>On pourrait se dire que quelque chose comme <a href="https://ngrx.io/">NgRx</a> ou un <a href="https://ngrx.io/guide/signals/signal-store">signal store</a> pourrait être une bonne solution, mais le premier pose une grande partie des mêmes problèmes que le service global, le second n&#39;apportera pas grand-chose de plus…</p>
<p>Alors on fait comment ? On va utiliser un service qu&#39;on provide nous-même avec un scope restreint à notre groupe d&#39;onglet : à la création de <code>&lt;app-tab-group&gt;</code>, on veut une nouvelle instance de notre service, et que cette instance soit partagée uniquement avec les composants enfants. C&#39;est facile, et vraiment : c&#39;est pas compliqué !</p>
<p>Commençons par créer notre service :</p>
<pre><code class="hljs language-TypeScript"><span class="hljs-comment">// src/app/shared/components/tabs/tab-state.ts</span>
<span class="hljs-keyword">import</span> { computed, <span class="hljs-title class_">Injectable</span>, <span class="hljs-title class_">Signal</span>, signal } <span class="hljs-keyword">from</span> <span class="hljs-string">&quot;@angular/core&quot;</span>;

<span class="hljs-meta">@Injectable</span>()
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">TabState</span> {
    <span class="hljs-keyword">private</span> _defaultTab = signal&lt;<span class="hljs-built_in">string</span> | <span class="hljs-literal">null</span>&gt;(<span class="hljs-literal">null</span>);
    <span class="hljs-keyword">private</span> _activeTab = signal&lt;<span class="hljs-built_in">string</span> | <span class="hljs-literal">null</span>&gt;(<span class="hljs-literal">null</span>);

    <span class="hljs-keyword">public</span> <span class="hljs-title function_">setActiveTab</span>(<span class="hljs-params"><span class="hljs-attr">tabId</span>: <span class="hljs-built_in">string</span></span>) {
        <span class="hljs-variable language_">this</span>.<span class="hljs-property">_activeTab</span>.<span class="hljs-title function_">set</span>(tabId ?? <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">_defaultTab</span>());
    }

    <span class="hljs-keyword">public</span> <span class="hljs-title function_">setDefaultTab</span>(<span class="hljs-params"><span class="hljs-attr">tabId</span>: <span class="hljs-built_in">string</span></span>) {
        <span class="hljs-variable language_">this</span>.<span class="hljs-property">_defaultTab</span>.<span class="hljs-title function_">set</span>(tabId);

        <span class="hljs-keyword">if</span> (<span class="hljs-variable language_">this</span>.<span class="hljs-title function_">_activeTab</span>() == <span class="hljs-literal">null</span>) {
            <span class="hljs-variable language_">this</span>.<span class="hljs-property">_activeTab</span>.<span class="hljs-title function_">set</span>(tabId);
        }
    }

    <span class="hljs-keyword">public</span> <span class="hljs-title function_">isActive</span>(<span class="hljs-attr">tabId</span>: <span class="hljs-title class_">Signal</span>&lt;<span class="hljs-built_in">string</span>&gt;): <span class="hljs-title class_">Signal</span>&lt;<span class="hljs-built_in">boolean</span>&gt; {
        <span class="hljs-keyword">return</span> <span class="hljs-title function_">computed</span>(<span class="hljs-function">() =&gt;</span> <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">_activeTab</span>() === <span class="hljs-title function_">tabId</span>());
    }
}<div aria-hidden="true" class="language-tag">TypeScript</div>
</code></pre><p>Ici mon service <code>TabState</code> va porter l&#39;état d&#39;un seul groupe d&#39;onglet, donc on a besoin que de deux choses : garder en mémoire l&#39;onglet par défaut et garder en mémoire l&#39;onglet actif. Le reste c&#39;est des méthodes utilitaires pour s&#39;assurer qu&#39;on garde bien encapsulé les signaux.</p>
<p>Vous noterez que contrairement à ce qu&#39;on fait habituellement : je **n&#39;**ai <strong>pas</strong> mis de <code>{ providedIn: &#39;root&#39; }</code> dans l&#39;annotation <code>@Injectable()</code>. Avoir un <code>{ providedIn: &#39;root&#39; }</code> entrainerait que le service serait global, or ce n&#39;est pas ce qu&#39;on veut, on peut nous-mêmes indiquer le <code>provide</code>.</p>
<p>C&#39;est là que la magie opère :</p>
<pre><code class="hljs language-TypeScript"><span class="hljs-comment">// src/app/shared/components/tabs/tab-group.ts</span>

<span class="hljs-meta">@Component</span>({
    ...
    <span class="hljs-attr">providers</span>: [<span class="hljs-title class_">TabState</span>]
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">TabGroup</span> {
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> tabState = <span class="hljs-title function_">inject</span>(<span class="hljs-title class_">TabState</span>);

    <span class="hljs-keyword">default</span> = input.<span class="hljs-property">required</span>&lt;<span class="hljs-built_in">string</span>&gt;();

    <span class="hljs-title function_">constructor</span>(<span class="hljs-params"></span>) {
        <span class="hljs-title function_">effect</span>(<span class="hljs-function">() =&gt;</span> <span class="hljs-variable language_">this</span>.<span class="hljs-property">tabState</span>.<span class="hljs-title function_">setDefaultTab</span>(<span class="hljs-variable language_">this</span>.<span class="hljs-title function_">default</span>()));
    }
}<div aria-hidden="true" class="language-tag">TypeScript</div>
</code></pre><p>Ici on va ajouter notre service comme <code>provider</code>, ce qui va lier une instance du service <code>TabState</code> à chaque instance de <code>TabGroup</code>. Ensuite on peut l&#39;injecter comme n&#39;importe quel autre service. On en profite pour définir notre onglet par défaut via un <code>effect</code> dans le constructor.</p>
<p>Ensuite on peut rendre dynamique nos autres composants :</p>
<pre><code class="hljs language-TypeScript"><span class="hljs-comment">// src/app/shared/components/tabs/tab.ts</span>
<span class="hljs-meta">@Component</span>({
    <span class="hljs-attr">selector</span>: <span class="hljs-string">&quot;[app-tab]&quot;</span>,
    <span class="hljs-attr">host</span>: {
        <span class="hljs-string">&quot;[class.tab-header]&quot;</span>: <span class="hljs-string">&quot;true&quot;</span>,
        <span class="hljs-string">&quot;[class.active]&quot;</span>: <span class="hljs-string">&quot;isActive()&quot;</span>,
        <span class="hljs-string">&quot;[attr.data-tab]&quot;</span>: <span class="hljs-string">&quot;tab()&quot;</span>,
    },
    <span class="hljs-attr">template</span>: <span class="hljs-string">`
    &lt;button [attr.data-tab]=&quot;tab()&quot; (click)=&quot;tabState.setActiveTab(tab())&quot;&gt;
        &lt;ng-content /&gt;
    &lt;/button&gt;
    `</span>,
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">Tab</span> {
    <span class="hljs-keyword">protected</span> <span class="hljs-keyword">readonly</span> tabState = <span class="hljs-title function_">inject</span>(<span class="hljs-title class_">TabState</span>);
    
    tab = input.<span class="hljs-property">required</span>&lt;<span class="hljs-built_in">string</span>&gt;({ <span class="hljs-attr">alias</span>: <span class="hljs-string">&quot;app-tab&quot;</span> });
    
    <span class="hljs-keyword">protected</span> <span class="hljs-keyword">readonly</span> isActive = <span class="hljs-variable language_">this</span>.<span class="hljs-property">tabState</span>.<span class="hljs-title function_">isActive</span>(<span class="hljs-variable language_">this</span>.<span class="hljs-property">tab</span>);
}<div aria-hidden="true" class="language-tag">TypeScript</div>
</code></pre><pre><code class="hljs language-TypeScript"><span class="hljs-comment">// src/app/shared/components/tabs/tab.ts</span>
<span class="hljs-meta">@Component</span>({
    <span class="hljs-attr">selector</span>: <span class="hljs-string">&quot;[app-tab-content]&quot;</span>,
    <span class="hljs-attr">host</span>: {
        <span class="hljs-string">&quot;[class.tab-content]&quot;</span>: <span class="hljs-string">&quot;true&quot;</span>,
        <span class="hljs-string">&quot;[class.active]&quot;</span>: <span class="hljs-string">&quot;isActive()&quot;</span>,
        <span class="hljs-string">&quot;[attr.id]&quot;</span>: <span class="hljs-string">&quot;tab()&quot;</span>,
    },
    <span class="hljs-attr">template</span>: <span class="hljs-string">&quot;&lt;ng-content /&gt;&quot;</span>,
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">TabContent</span> {
    <span class="hljs-keyword">protected</span> <span class="hljs-keyword">readonly</span> tabState = <span class="hljs-title function_">inject</span>(<span class="hljs-title class_">TabState</span>);
    
    tab = input.<span class="hljs-property">required</span>&lt;<span class="hljs-built_in">string</span>&gt;({ <span class="hljs-attr">alias</span>: <span class="hljs-string">&quot;app-tab-content&quot;</span> });
    
    <span class="hljs-keyword">protected</span> <span class="hljs-keyword">readonly</span> isActive = <span class="hljs-variable language_">this</span>.<span class="hljs-property">tabState</span>.<span class="hljs-title function_">isActive</span>(<span class="hljs-variable language_">this</span>.<span class="hljs-property">tab</span>);
}<div aria-hidden="true" class="language-tag">TypeScript</div>
</code></pre><figure>
<img src="https://anthonypena.fr/2026/03/24/creer-composants-tabs-avec-angular/img/demo.gif" alt="Démonstration des onglets fonctionnels" is="img-zoom"/>
<figcaption>Démonstration des onglets fonctionnels</figcaption>
</figure>
<h2 id="article-conclusion">Conclusion<a href="#article-conclusion" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Faire des briques dans ce genre implique souvent la création d&#39;une grosse usine compliqué à cause de la méconnaissance du framework. C&#39;est finalement assez facile d&#39;avoir un état partagé à un groupe de composant (encore plus depuis les standalone component !), assez peu verbeux quand on travaille en Single File Component et avec des signaux comme je l&#39;ai fait.</p>
<p>Si finalement le code n&#39;est pas très compliqué, je trouve que c&#39;est le genre de mécanique qui peut se transposer facilement à des briques plus complexes !</p>
<p>Sources :</p>
<ul>
<li><a href="https://github.com/kuroidoruido/ng-tabs-sample">Projet démo</a></li>
</ul>
<p>Crédit photo : Générée via Mistral AI avec le prompt suivant : </p>
<blockquote>
<p>Studio Ghibli-inspired magical workshop: a wooden desk with old grimoires and floating holographic screens showing a modern Angular Tabs component with &quot;Sortilèges&quot;, &quot;Ingrédients&quot;, and &quot;Recettes&quot; tabs. An axolotl in a lab coat watches nearby, surrounded by golden light and maple leaves. Warm, dreamy autumn lighting, soft textures, 8K, detailed.</p>
</blockquote>
]]></content:encoded>
      <dc:creator><![CDATA[Anthony Pena]]></dc:creator>
      <media:content medium="image" url="https://anthonypena.fr/img/cover.min.jpg"/>
    </item>
    <item>
      <title><![CDATA[2025 c'est fini, en route pour 2026 !]]></title>
      <guid isPermaLink="false">2026/03/11/2025-cest-fini-en-route-pour-2026</guid>
      <description><![CDATA[<p>Nouvelle année, nouveau bilan ! Cette année est encore une année un peu mouvementée !</p>
]]></description>
      <link>https://anthonypena.fr/2026/03/11/2025-cest-fini-en-route-pour-2026/index.html</link>
      <category><![CDATA[Edito]]></category>
      <category><![CDATA[Blog]]></category>
      <pubDate>Wed, 11 Mar 2026 07:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>Nouvelle année, nouveau bilan ! Cette année est encore une année un peu mouvementée !</p>
<p>Si vous découvrez mon blog ou mes bilans annuels, je les fais en mars, car je suis né fin février, ce qui fait que je fais mes bilans en année &quot;Anthony&quot; (vous pouvez vous dire aussi que c&#39;est en <a href="https://fr.wikipedia.org/wiki/Calendrier_romain#Les_mois">calendrier romain pompilien</a> aussi si vous trouvez ça trop égocentrique). Tout ça pour dire que ça me semble finalement plus logique de faire mon bilan annuel en suivant mes années de vie que début janvier.</p>
<nav data-serie="bilan-annuel">
<h2>Série d'article</h2>
<ul>
<li><a href="https://anthonypena.fr/2022/03/08/2021-cest-fini-en-route-pour-2022/index.html">2021 c'est fini, en route pour 2022 !</a></li>
<li><a href="https://anthonypena.fr/2023/03/07/2022-cest-fini-en-route-pour-2023/index.html">2022 c'est fini, en route pour 2023 !</a></li>
<li><a href="https://anthonypena.fr/2024/03/12/2023-cest-fini-en-route-pour-2024/index.html">2023 c'est fini, en route pour 2024 !</a></li>
<li><a href="https://anthonypena.fr/2025/03/11/2024-cest-fini-en-route-pour-2025/index.html">2024 c'est fini, en route pour 2025 !</a></li>
<li><a href="https://anthonypena.fr/2026/03/11/2025-cest-fini-en-route-pour-2026/index.html">2025 c'est fini, en route pour 2026 !</a></li>
</ul>
</nav>
<h2 id="article-cote-mission">Côté mission<a href="#article-cote-mission" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Ça fait maintenant plus d&#39;un an que je travaille sur cette mission (commencé en novembre 2024). Je suis bien sur cette mission, l&#39;équipe est bien, le projet est intéressant. Comme partout tout n&#39;est pas parfait, mais j&#39;y trouve un certain équilibre. J&#39;ai aussi depuis quelque temps une position plus transverse : on a dû doubler le nombre de personne pour encaisser le volume de travail en avançant la date de livraison et fini par prendre un peu de hauteur en prenant des sujets plus long court et plus complexe.</p>
<p>Dans un sens j&#39;ai aussi pu évoluer sur l&#39;aspect mentoring et je me questionne sur l&#39;éventualité d&#39;en faire plus (et même hors de cette mission).</p>
<p>Je ne sais pas comment tout ça va évoluer, mais on verra : en tout cas je vois dans la roadmap des sujets que j&#39;ai envie de mener !</p>
<h2 id="article-cote-sfeir">Côté SFEIR<a href="#article-cote-sfeir" class="anchor" aria-label="permalink">🔗</a></h2>
<p>J&#39;ai soufflé la semaine dernière ma 7ème bougie. Je me répète, mais j&#39;aurai jamais cru resté aussi longtemps.</p>
<p>Toujours Staff Engineer, j&#39;ai quand même eu un focus plutôt sur des sujets groupes plutôt qu&#39;agence cette année à mon sens. J&#39;ai en effet essentiellement travaillé sur l&#39;outillage des formations et l&#39;expérience formateur.</p>
<p>J&#39;ai encore fait pas mal de chose cette année, même hors de la casquette Staff Engineer, mais je commence à laisser mes casquettes à d&#39;autres pour laisser d&#39;autres grandir à leur tour. On verra de quoi 2026 sera fait !</p>
<h2 id="article-cote-langage-et-projets-perso">Côté langage et projets perso<a href="#article-cote-langage-et-projets-perso" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Est-ce que j&#39;ai fait ce qui était prévu ? Non. Est-ce que c&#39;est grave ? Non plus !</p>
<p>J&#39;ai enfin sorti le blog de Ghost ! J&#39;en ai fait une série d&#39;article pour tout expliqué.</p>
<p>J&#39;ai aussi continué à travailler sur <a href="https://anthonypena-easy-wiremock.deno.dev">Easy Wiremock</a> (qui est un frontend à Wiremock pour pouvoir visualiser différents éléments). J&#39;ai ajouté des petites fonctionnalités qui m&#39;aident au quotidien (qui aident aussi les membres de mon équipe), ça fonctionne bien, donc c&#39;est un succès à mon sens !</p>
<p>Je pensais retravailler mon fork de <a href="https://github.com/kuroidoruido/canis-dirus/">Canis Dirus</a> (et repousser à Siegfried ces contributions) et finalement je n&#39;ai jamais pris le temps de le faire… J&#39;ai toujours des idées, mais je vais peut-être changer de fonctionnement pour pouvoir aller plus loin (et faire aussi beaucoup plus que &quot;juste&quot; pousser sur Mastodon ma veille en continu). Si ça abouti j&#39;en reparlerai, car je pense que ça pourrait intéresser des gens !</p>
<h2 id="article-conferences--talks">Conférences / Talks<a href="#article-conferences--talks" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Année encore plutôt calme côté conférences et meetups :</p>
<ul>
<li>J&#39;ai rejoué mon talk <a href="https://kuroidoruido.github.io/talks/2025/06-05_devquest-2025_adieu-rxjs/index.html">Adieu RxJS ! Vive les Signals ! Oh wait…</a> en juin à DevQuest à Niort ;</li>
<li>J&#39;ai joué un talk en interne de Sfeir Nantes sur <a href="https://kuroidoruido.github.io/talks/2025/07-09_sfeir-share_post-linkedin-parfait/index.html">Comment faire le post LinkedIn parfait ?</a> ;</li>
</ul>
<p>Par contre j&#39;ai toujours été impliqué à d&#39;autres niveaux :</p>
<ul>
<li>J&#39;ai continué à travailler sur <a href="https://angulardevs.fr">Angular Devs France</a> même s&#39;il faut avouer qu&#39;on s&#39;est beaucoup concentré sur <a href="https://2025-ngbaguette.angulardevs.fr/fr/">NG Baguette Conf 2025</a> et qu&#39;on est toujours pas mal occupé sur <a href="https://ngbaguette.angulardevs.fr">NG Baguette Conf 2026</a> (dont la billetterie est ouverte en ce moment !) ;</li>
<li>J&#39;ai continué jusqu&#39;à l&#39;été les apéros du <a href="https://naoned.computer-club.fr/">Naoned Computer Club</a> mais je n&#39;ai pas réussi à reprendre après l&#39;été et j&#39;ai finalement annoncé côté association Computer Club que j&#39;arrêtais ;</li>
<li>J&#39;ai été à nouveau bénévole pour Devfest Nantes ;</li>
</ul>
<h2 id="article-le-blog">Le blog<a href="#article-le-blog" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Bilan de l&#39;année : 41 articles publiés depuis mon dernier bilan (cet article inclus) ! Ceci incluant 12 revues de presses, j&#39;ai donc écrit 29 articles à proprement parler.</p>
<p>C&#39;est 15 de plus que ce que je comptais pour 2024. Clairement une de mes plus grosses années ! Et j&#39;en suis très content !</p>
<p>J&#39;aime toujours écrire, j&#39;aime toujours partager, j&#39;ai envie de partager beaucoup de choses (pas que via mon blog / en mode texte), ça me fait toujours du bien à moi, donc je ne compte pas m&#39;arrêter là !</p>
<p>Je sais que le blog en lui-même m&#39;a demandé pas mal de travail pour la migration, je sais aussi que j&#39;ai encore du chemin à parcourir pour aller au bout du blog tel que je l&#39;imaginais. En tout cas je suis toujours content de voir que des gens me lisent !</p>
<p>N&#39;hésitez pas à me contacter en privé ou m&#39;interpeler si on se croise en personne ou commenter mes publications sur les réseaux sociaux. Je vous répondrais, et ça pourrait créer de la discussion ou des idées d&#39;articles !</p>
<h2 id="article-mon-bujo-et-moi">Mon BuJo et moi<a href="#article-mon-bujo-et-moi" class="anchor" aria-label="permalink">🔗</a></h2>
<p>J&#39;ai encore beaucoup utilisé mon BuJo cette année, et je confirme ce que je disais l&#39;année dernière : les carnets de La Boutique de Margaux sont parfaits ! Donc j&#39;ai à nouveau pris un carnet de cette boutique, et j&#39;ai choisi <a href="https://laboutiquedemargaux.fr/collections/lorganise/products/bullet-journal-lorganise-cerise-carnet-a5">l&#39;Organisé &quot;Cerise&quot;</a> qui est un carnet rouge, avec un embossage représentant deux cerises. </p>
<p>J&#39;ai pas changé du tout ma formule BuJo minimaliste que j&#39;avais tenté l&#39;année dernière : elle me convient ! </p>
<p>J&#39;ai par contre changé de crayon. Je suis passé d&#39;un Kaco Green avec 3 couleurs (noir, rouge et bleue) + 1 porte mine (en gros comme un stylo 4 couleurs mais avec un couleur qui est un porte-mine, pas trouvé de lien) au combo d&#39;un stylo plume <a href="https://www.lamy.com/fr-fr/p/lamy-safari-stylo-plume/49729340014939">Lamy Safari Umbra F (Fine)</a> et d&#39;un critérium <a href="https://www.staedtler.com/fr/fr/produits/crayons-et-accessoires/porte-mine-fins/mars-micro-775-porte-mines-m775/">Staedtler Mars Micro 775 7mm</a>. Je ne pensais sincèrement pas retourné sur un stylo plume un jour, mais celui-ci m&#39;a tenté et est extrêmement agréable à manipuler et l&#39;écriture est super fluide ! J&#39;en suis très content. Si je ne devais citer qu&#39;un bémol : j&#39;aurai dû choisir la plume EF (Extra-Fine), car je trouve le trait légèrement trop épais à mon goût. Si un jour je dois le changer je tenterai peut-être le Lamy AL-star qui est globalement le même stylo que le Safari est en aluminium (juste un peu peur au côté désagréable du froid de l&#39;aluminium quand on commence à écrire). Mais passons sur mes histoires de stylos ! (quand bien même j&#39;adore la papeterie et je pourrais en parler encore pas mal 😅)</p>
<p>Sinon j&#39;utilise toujours un &quot;BuJo numérique&quot; à base d&#39;Obsidian pour ma mission, et ça correspond toujours à mon besoin !</p>
<h2 id="article-cote-lecture">Côté lecture<a href="#article-cote-lecture" class="anchor" aria-label="permalink">🔗</a></h2>
<p>J&#39;ai commencé à noter tout ce que je lis (pour l&#39;instant dans une checklist dans mon Trello en attendant mieux). Et je peux vous dire que je lis beaucoup, plus que je pensais ! 😅 Après je me dis que c&#39;est peut-être aussi un effet de mesure : comme je mesure je lis encore plus pour la métrique !</p>
<p>Pour vous donner des chiffres, entre le 1er novembre 2025 et le 28 février 2026 (j&#39;ai décidé de noter à partir de novembre, donc j&#39;arrête ce bloc au 28 février comme le reste), j&#39;ai lu 73 livres. Alors y&#39;a de tout : 2 magazines (Linux Magazine), 2 comics (dont un recueil des 15 premiers tomes de Spawn), 1 recueil de nouvelle, 1 essai économique, 6 romans, 24 bandes dessinées, 35 mangas et 2 manhuas (BD chinoise).</p>
<p>En tout cas je lis ! Et ça me fait du bien ! J&#39;ai aussi commencé à lire des livres qui me paraissent différent de ce que j&#39;ai déjà lu. J&#39;ai aussi commencé à lire de littérature japonaise, même si clairement j&#39;y connais pas grand-chose donc je teste un peu au hasard pour l&#39;instant. J&#39;ai commencé à regarder la littérature asiatique au sens large mais pour l&#39;instant j&#39;ai surtout accroché à des œuvres japonaises 🤷</p>
<p>Quelques recommandations de mon année (pas forcément d&#39;ordre précis) :</p>
<ul>
<li><em>Le recueil de l’angoisse</em> de Maël Sargel : auteur indépendant que j&#39;ai rencontré dans un salon du livre, j&#39;ai vraiment aimé ce recueil quand bien même je ne l&#39;ai pas forcément trouvé angoissant ;</li>
<li><em>Sang neuf</em> de Jean-Christophe Chauzy : bande dessiné d&#39;un auteur qui raconte son histoire face à la maladie, c&#39;est parfois un peu cru (moi ça me dérange pas du tout, mais ça peut déranger donc je préviens), mais c&#39;est vraiment touchant ;</li>
<li><em>La citadelle des vertiges</em> d&#39;Alain Grousset : roman que j&#39;avais lu adolescent et que j&#39;ai retrouvé par hasard dans une recyclerie, donc je me suis laissé aller à la nostalgie, et je ne regrette pas, c&#39;est un très bon livre qui se lit tout seul, même adolescent, tout en étant une bonne introduction à la science-fiction ;</li>
<li><em>La bibliothèque des rêves secrets</em> de Michiko Aoyama : très bon roman japonais, posé et relaxant, qui vous fera suivre des tranches de vie de personne croisant une bibliothécaire un peu particulière ;</li>
<li><em>Les milliardaires ne paient pas d&#39;impôts sur le revenu et nous allons y mettre fin</em> de Gabriel Zucman : pour dépasser ce qu&#39;on a peu entendre à droite ou à gauche et se poser sur ce qu&#39;il essaie d&#39;expliquer vraiment ;</li>
<li><em>Ikigami</em> de Motorō Mase (10 tomes) : dystopie où un pays proche du Japon aurait adopté après la Seconde Guerre Mondiale la &quot;Loi de prospérité nationale&quot; qui implique de tuer 1 personne sur 1000, âgée de 18 à 24 ans par injection d&#39;une capsule pendant la vaccination obligatoire à 6 ans, c&#39;est la 3ème fois que je lis cette histoire, c&#39;est bien écrit, on voit 20 points de vue différents autour de cette Loi et comment les gens gèrent leurs derniers instants, vraiment un très bon manga ;</li>
<li><em>The Walking Dead</em> de Robert Kirkman, Tony Moore et Charlie Adlard : le comics qui donnera par la suite la série TV, je ne suis pas intéressé par les zombies, les comics pas plus que ça non plus, mais la vache cette série est incroyable (et l&#39;histoire est assez différente de la série quand bien même on retrouve énormément de personnes) ;</li>
</ul>
<h2 id="article-conclusion">Conclusion<a href="#article-conclusion" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Encore une année riche, encore une année où j&#39;ai pu faire des choses, mais aussi une année où j&#39;ai appris à fermer des portes. Que ce soit le Naoned Computer Club ou même les événements internes SFEIR, j&#39;ai fait des choix pour me préserver moi, et même si j&#39;ai pu réaliser des choses très sympas : je suis content que ce soit fini !</p>
<p>Pas forcément un laïus à faire dessus mais ça fait un an que j&#39;ai quitté Nantes et que je vis du côté de Cholet. Je continue de m&#39;approprier cette nouvelle vie, à commencer par le jardinage, mais ça fait du bien d&#39;avoir quitté le tumulte de la ville. Le seul truc qui me manque : il n&#39;y a pas de vraie bonne boutique vendant des mangas dans le choletait, j&#39;ai trouvé du mainstream, des rayonnages plus mal rangés les uns que les autres (ou avec des classements sans queue ni tête) mais pas de vrai rayon manga (pour être clair : il manque toujours 70-80% des titres que je suis…). Tant pis, Internet est mon ami pour corriger ce problème, et je ne parle pas d&#39;Amazon, il se trouve qu&#39;Otaku no Dera (la boutique que je fréquentais depuis 2010) vend aussi en livraison !</p>
<p>Sinon une nouvelle passion est rentrée dans ma vie : Magic The Gathering ! (Pas) Merci Myriam ! 😂 Bon en vrai, ça faisait pas mal de temps que j&#39;hésitais à mettre le nez dans un TCG (j&#39;ai joué pendant des années à Yu-Gi-Oh! avant de lâcher l&#39;affaire pour plein de raisons) et je me retrouve pas mal dans Magic, donc à voir dans le temps ! </p>
<p>Crédit photo : Générée via Mistral AI avec le prompt suivant</p>
<blockquote>
<p>A Ghibli-style illustration featuring a masculine character with a round face, full cheeks, a marked chin, curly hair tied in a low bun, dense short beard, and dark brown eyes slightly squinted, wearing black rectangular glasses and a silver chain necklace. He has a robust build with broad shoulders and wears a light blue t-shirt with two subtle, light-toned koi carp designs on the back. He stands in a 3/4 view on a Venetian bridge, left hand with a watch resting on the railing, gazing thoughtfully at the canal at dusk. The canal is lined with colorful houses, automated gondolas glide on the water, and bioluminescent jellyfish float gently. In the background, a warm, inviting bookstore glows softly. A red panda, curled up on a cushion in the lower right corner, watches the scene. The atmosphere is golden and dreamy, blending magic and subtle technology, with autumn leaves and a serene, reflective mood.</p>
</blockquote>
]]></content:encoded>
      <dc:creator><![CDATA[Anthony Pena]]></dc:creator>
      <media:content medium="image" url="https://anthonypena.fr/img/cover.min.jpg"/>
    </item>
    <item>
      <title><![CDATA[Revue de presse - Mars 2026]]></title>
      <guid isPermaLink="false">2026/03/03/revue-de-presse-mars</guid>
      <description><![CDATA[]]></description>
      <link>https://anthonypena.fr/2026/03/03/revue-de-presse-mars/index.html</link>
      <category><![CDATA[Revue de presse]]></category>
      <pubDate>Tue, 03 Mar 2026 07:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<h2 id="article-frontend">Frontend<a href="#article-frontend" class="anchor" aria-label="permalink">🔗</a></h2>
<h3 id="article-oathttpsoatinkcomponents"><a href="https://oat.ink/components/">Oat</a><a href="#article-oathttpsoatinkcomponents" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#Frontend #CSS #JavaScript #Web</p>
<p>Encore une library de composant web super légère qui à l&#39;air plutôt complète ! </p>
<blockquote>
<p>Semantic, minimal, zero dependencies. ~8KB CSS and JS.</p>
</blockquote>
<p>Indépendant de tout framework, vous pouvez l&#39;utiliser partout dans vos frontend ! </p>
<h3 id="article-optimiser-les-perfs-et-la-securite-dun-site-hugo--julien-wittouckhttpscodekaio20260220optimiserlesperfsetlasc3a9curitc3a9dunsitehugo"><a href="https://codeka.io/2026/02/20/optimiser-les-perfs-et-la-s%C3%A9curit%C3%A9-dun-site-hugo/">Optimiser les perfs et la sécurité d&#39;un site Hugo - Julien Wittouck</a><a href="#article-optimiser-les-perfs-et-la-securite-dun-site-hugo--julien-wittouckhttpscodekaio20260220optimiserlesperfsetlasc3a9curitc3a9dunsitehugo" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#Web #Frontend</p>
<p>Un REX sur quelques techniques pour optimiser le chargement / la sécurité d&#39;un site web </p>
<p>Pas surprise :</p>
<ul>
<li>utilisation de Lighthouse ;</li>
<li>changement de format d&#39;image pour du webp ; </li>
<li>resize des images pour avoir des images plus petites ;</li>
<li>utilisation de srcset pour laisser le navigateur choisir la taille optimale par rapport à l&#39;usage ;</li>
<li>ajout des bons headers de sécurité ;</li>
</ul>
<p>Faut que je me penche là-dessus sur mon site aussi ! </p>
<h3 id="article-optimisation-webperf--avif-et-precompression-pour-le-bloghttpsblogzwindlerfr20260219optimisationwebperfavifprecompression"><a href="https://blog.zwindler.fr/2026/02/19/optimisation-webperf-avif-precompression/">Optimisation webperf : AVIF et pré-compression pour le blog</a><a href="#article-optimisation-webperf--avif-et-precompression-pour-le-bloghttpsblogzwindlerfr20260219optimisationwebperfavifprecompression" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#Frontend #Web #HTTP</p>
<p>Encore quelqu&#39;un qui revient de Touraine Tech et qui optimise son blog avec les conseils qui viennent d&#39;un talk ! </p>
<p>Ce coup-ci c&#39;est Denis, avec des résultats chiffrés ! </p>
<p>Franchement je suis pressé qu&#39;il y ait les replays en ligne pour voir le talk d&#39;Antoine Caron et Mathieu Mure <a href="https://touraine.tech/talk/cmgah8mo800fj1elbs7lmahsn?day%3D2">&quot;Au secours ! Mes images pourrissent mes perfs&quot;</a> !</p>
<h3 id="article-so-ive-been-thinking-about-static-site-generatorshttpswolfgirldevblog20260223soivebeenthinkingaboutstaticsitegenerators"><a href="https://wolfgirl.dev/blog/2026-02-23-so-ive-been-thinking-about-static-site-generators/">So I&#39;ve Been Thinking About Static Site Generators</a><a href="#article-so-ive-been-thinking-about-static-site-generatorshttpswolfgirldevblog20260223soivebeenthinkingaboutstaticsitegenerators" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#Blog #Web #Frontend #Performance</p>
<p>Article assez détaillé sur comment avoir une génération statique d&#39;un site (SSG) type blog en cumulant 2 parties : la partie incrémentale / transformation du markdown dans un langage compilé comme Rust (car la logique est compilée très vite, de manière incrémentale, et ne bougera pas quand on aura besoin de générer le contenu) et la partie template dans un langage interprété comme JavaScript pour sa souplesse. </p>
<p>Les arguments sont intéressants je trouve. C&#39;est pas la voie que j&#39;ai prise par contre (mon blog est écrit entièrement avec un moteur maison en TypeScript exécuté avec Deno) par contre j&#39;ai des performances à date qui tiennent la route (1 à 3 secondes pour rebuilder mon blog). C&#39;est au-dessus de ce que l&#39;autrice souhaiterait (elle vise 300ms, si possible 100ms, même 20ms en but ultime), mais je trouve ça raisonnable (après dans 5 ans quand j&#39;aurai beaucoup plus de contenu j&#39;aurai peut-être un avis différent). </p>
<p>En tout cas je pense qu&#39;il y a de l&#39;inspiration à prendre !</p>
<h3 id="article-beulogue-v5httpsehretme202601beuloguev5"><a href="https://ehret.me/2026/01/beulogue-v5/">beulogue v5</a><a href="#article-beulogue-v5httpsehretme202601beuloguev5" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#Astro #Blog #Frontend</p>
<p>J&#39;aime toujours autant voir comment les autres gèrent leur blog.</p>
<p>Ici Siegfried nous explique comment est construit la v5 de son blog, et ça tient surtout en un mot : Astro. </p>
<p>Je comprends complètement pourquoi, si vous avez lu <a href="https://anthonypena.fr/2026/01/15/nouveau-blog-partie-1-html/index.html">ma série d&#39;article que la réécriture de mon blog</a> vous savez que j&#39;ai failli le faire en Astro aussi mais finalement non. Ça reste un super framework ! </p>
<h2 id="article-ia">IA<a href="#article-ia" class="anchor" aria-label="permalink">🔗</a></h2>
<h3 id="article-containers-cloud-blockchain-ai--its-all-the-same-old-bs-says-veteran-red-hatterhttpswwwtheregistercom20260208waves_of_tech_bs"><a href="https://www.theregister.com/2026/02/08/waves_of_tech_bs/">Containers, cloud, blockchain, AI – it&#39;s all the same old BS, says veteran Red Hatter</a><a href="#article-containers-cloud-blockchain-ai--its-all-the-same-old-bs-says-veteran-red-hatterhttpswwwtheregistercom20260208waves_of_tech_bs" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#LLM #IA #Kubernetes #Cloud</p>
<p>Je cite directement car pas besoin de plus :</p>
<blockquote>
<p><strong>Containers</strong>: Sure, yes, they work, they are handy for testing. But they aren&#39;t a deployment method. You shouldn&#39;t need them. Anything that you can run in a container, you can just run on the bare metal, and if you&#39;re not competent enough to get – and keep – that working, then you probably aren&#39;t competent enough to deploy a container either.</p>
<p><strong>Kubernetes</strong>: If you don&#39;t need containers, then you don&#39;t need another vastly more complicated tool to deploy those containers. The chances are, you are not a vast multinational that must be able to withstand ten million potential new customers visiting your site all at once. It won&#39;t happen, so you won&#39;t lose any of that imaginary business.</p>
<p><strong>The cloud</strong>: Nebulous by name and by nature. Who thought it was smart to take all your company&#39;s important data and hand it to some internet rando – probably the lowest bidder – trusting them to store the crown jewels, keep them safe, and never ever peek at them. If that sounds reasonable to you, maybe you should try selling homeopathy.</p>
<p><strong>Anything &quot;as a service&quot; – it doesn&#39;t matter what</strong>: Infrastructure as a service – if you need servers, buy servers, or rent your own private servers. Nobody else will ever care as much about your servers as you will. Platform as a Service – now you don&#39;t even get servers, just OS instances. That&#39;s even worse. Software as a Service? Now you don&#39;t even know what the server is, or where it is, or what it&#39;s running; you don&#39;t get software, and you don&#39;t even know what data you have or how it&#39;s stored – you&#39;re paying for access to your own stuff.</p>
<p><strong>The blockchain, and anything built on the blockchain</strong>: the world&#39;s slowest and most-distributed database. Cryptocurrencies? Hashcash on the blockchain. NFTs – URL shorteners on the blockchain, only they&#39;re longer rather than shorter. Worthless. Web3? Get ripped off, as a service.</p>
<p>Which brings us round to <strong>&quot;generative AI&quot;</strong> or, as we prefer to term them, large language models, powered by the transformer algorithm. If The Financial Times can explain how it works to a banker in a couple of thousand words and a few minutes, it can&#39;t be that complicated or hard to understand, and it isn&#39;t. It&#39;s predictive text turned up to 11. It can&#39;t even count. As Daniel Stenberg, author of curl, caustically observed:</p>
<blockquote>
<p>The &quot;i&quot; in &quot;LLM&quot; stands for intelligence.</p>
</blockquote>
</blockquote>
<p>Si tout ça peut sembler &quot;l&#39;évolution logique&quot; pour certains, je trouve quand même qu&#39;on empile toujours plus de marketing et de bullshit… En ce moment c&#39;est l&#39;<strong>IA</strong> sans intelligence, demain ce sera autre chose 🤷‍♂️ </p>
<h3 id="article-waymo-exec-reveals-company-uses-operators-in-the-philippines-to-assist-autonomous-vehicleshttpssebsauvagenetlinksyqpe7w"><a href="https://sebsauvage.net/links/?yqpE7w">Waymo Exec Reveals Company Uses Operators in the Philippines to Assist Autonomous Vehicles</a><a href="#article-waymo-exec-reveals-company-uses-operators-in-the-philippines-to-assist-autonomous-vehicleshttpssebsauvagenetlinksyqpe7w" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#IA #Voiture-autonome #Voiture #Google</p>
<p>L&#39;IA de Waymo, une société de transport en voiture autonome appartenant à Google (pour être précis : au groupe Alphabet qui est la maison mère de Google), repose beaucoup sur l&#39;usage de philippins qui conduisent à distance les voitures &quot;autonomes piloté par IA&quot;… </p>
<p>Encore une entreprise IA qui ment sur son usage de l&#39;IA. Encore une IA qui repose sur des humains Sous-payés dans un pays pauvre. Les IA actuelles savent faire des choses, mais sont clairement très loin de ce qui est annoncé ! </p>
<h3 id="article-rtkhttpsgithubcomrtkairtk"><a href="https://github.com/rtk-ai/rtk">rtk</a><a href="#article-rtkhttpsgithubcomrtkairtk" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#IA #Agentic</p>
<blockquote>
<p>CLI proxy that reduces LLM token consumption by 60-90% on common dev commands. Single Rust binary, zero dependencies </p>
</blockquote>
<p>Pas encore testé mais vu le prix que coûte l&#39;usage des IA comme Claude / Gemini, etc. réduire le volume de token en réduisant le bruit inutile des sorties des commandes courantes ça peut pas faire de mal ! </p>
<h3 id="article-jai-demande-a-claude-pourquoi-il-ne-recommande-jamais-vuejs--nicolas-bonnefoyhttpswwwlinkedincompostsnbonnefoy_jaidemand25c325a925c325a0claudepourquoiilnerecommandeshare7433139537821921280ror7utm_sourceshareutm_mediummember_androidrcmacoaabstacubdsnx13s7uh8twss8u8br5ts2ga"><a href="https://www.linkedin.com/posts/nbonnefoy_jai-demand%25C3%25A9-%25C3%25A0-claude-pourquoi-il-ne-recommande-share-7433139537821921280-roR7?utm_source%3Dshare%26utm_medium%3Dmember_android%26rcm%3DACoAABstAcUBDSnX1-3s7Uh8tWSS8u8BR5Ts2gA">J&#39;ai demandé à Claude pourquoi il ne recommande jamais Vue.js. — Nicolas Bonnefoy</a><a href="#article-jai-demande-a-claude-pourquoi-il-ne-recommande-jamais-vuejs--nicolas-bonnefoyhttpswwwlinkedincompostsnbonnefoy_jaidemand25c325a925c325a0claudepourquoiilnerecommandeshare7433139537821921280ror7utm_sourceshareutm_mediummember_androidrcmacoaabstacubdsnx13s7uh8twss8u8br5ts2ga" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#IA #Claude #LLM</p>
<blockquote>
<p>J&#39;ai demandé à Claude pourquoi il ne recommande jamais Vue.js.</p>
<p>Sa réponse, en substance : &quot;Je ne sais pas. Probablement parce que j&#39;ai vu plus de React dans mes données d&#39;entraînement.&quot;</p>
<p>Une étude d&#39;Amplifying vient de documenter le phénomène à grande échelle. Ils ont envoyé 2 430 prompts ouverts à Claude Code, du type &quot;j&#39;ai besoin d&#39;une base de données&quot; ou &quot;ajoute l&#39;authentification&quot;. Sans jamais nommer un outil.</p>
<p>Les résultats sont nets. GitHub Actions : 94%. Stripe : 91%. shadcn/ui : 90%. Vercel : 100% sur les projets JS.</p>
<p>Plus intéressant : les modèles les plus récents abandonnent des outils établis. Prisma passe de 79% à 0% entre Sonnet 4.5 et Opus 4.6. Celery de 100% à 0%. Au profit de Drizzle et des solutions natives FastAPI.</p>
<p>Le mécanisme est simple. Plus un outil est présent dans les données d&#39;entraînement, plus il est recommandé. Plus il est recommandé, plus il est adopté. Plus il est adopté, plus il apparaît dans les futures données d&#39;entraînement.</p>
<p>Ce n&#39;est pas un classement qualité. C&#39;est un classement de visibilité.</p>
<p>Quand je lui demande si c&#39;est justifié techniquement, Claude répond :</p>
<p>&quot;Pas vraiment. Vue 3 avec la Composition API, Nuxt 3, Pinia, VueUse : c&#39;est un écosystème mature, performant, avec une DX souvent supérieure pour certains profils de projets. La courbe d&#39;apprentissage est plus douce, l&#39;API est plus cohérente, et pour des équipes qui ne sont pas déjà dans l&#39;écosystème React, c&#39;est souvent un meilleur choix.</p>
<p>Le fait que je ne le propose pas par défaut est un bon exemple de ce que l&#39;étude appelle &#39;training data frequency vs actual quality&#39; : la fréquence dans mes données n&#39;est pas un signal de qualité, c&#39;est un signal de popularité. Et les deux ne sont pas la même chose.&quot;</p>
<p>Quand un founder me demande &quot;on part sur quelle stack ?&quot;, la vraie question n&#39;est plus seulement quel outil est le meilleur. C&#39;est : est-ce que ton CTO (ou ton agent IA) a évalué les alternatives, ou est-ce qu&#39;il suit le chemin par défaut ?</p>
<p>L&#39;étude complète : <a href="https://amplifying.ai/research/claude-code-picks/report">https://amplifying.ai/research/claude-code-picks/report</a> </p>
</blockquote>
<p>(j&#39;ai cité le post LinkedIn complet sans y toucher sauf pour le lien final qui pointe la source pas le lien LinkedIn)</p>
<p>Je ne suis pas du tout étonné de ce résultat ! J&#39;ajouterai même une sur utilisation de Tailwind CSS (c&#39;est d&#39;ailleurs cité dans l&#39;étude) car c&#39;est plus facile de laisser les LLMs faire du Tailwind CSS que de leur faire faire du CSS 🤷‍♂️ </p>
<p>Rappelez-vous d&#39;une chose super importante : quand vous utilisez des LLMs pour le code, c&#39;est VOUS qui devez faire les choix de technologie et d&#39;architecture, sauf si vous ne voulez pas maîtriser votre projet et aller dans le mur à un moment ! </p>
<h3 id="article-mcp-is-dead-long-live-the-clihttpsejholmesgithubio20260228mcpisdeadlonglivetheclihtml"><a href="https://ejholmes.github.io/2026/02/28/mcp-is-dead-long-live-the-cli.html">MCP is dead. Long live the CLI</a><a href="#article-mcp-is-dead-long-live-the-clihttpsejholmesgithubio20260228mcpisdeadlonglivetheclihtml" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#IA #MCP</p>
<p>L&#39;article est intéressant parce qu&#39;on a vu émergé une alternative aux API REST sous la forme d&#39;une nouvelle forme d&#39;API alors qu&#39;on aurait simplement pu pousser massive à la création de CLI pour tous les tools qui n&#39;avait pas de CLI. </p>
<p>Et en effet j&#39;avais pas réalisé qu&#39;on consommait plus de token en MCP qu&#39;en CLI. En plus d&#39;avoir moins de capacité à l&#39;utiliser nous en tant qu&#39;humain 🙃 </p>
<h3 id="article-claude-code-vatil-nous-remplacer---olivier-poncethttpsyoutube4lh_ag57dxs"><a href="https://youtu.be/4Lh_AG57dXs">Claude code va-t-il nous remplacer ? — Olivier Poncet</a><a href="#article-claude-code-vatil-nous-remplacer---olivier-poncethttpsyoutube4lh_ag57dxs" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#IA #Claude #Dev</p>
<p><a href="https://youtu.be/4Lh_AG57dXs"><img src="https://anthonypena.fr/2026/03/03/revue-de-presse-mars/img/youtube-4Lh_AG57dXs.jpg" alt="https://youtu.be/4Lh_AG57dXs" title="Youtube video preview"/></a></p>
<p>Vidéo super intéressante sur un sujet d&#39;actualité : l&#39;IA et Claude Code.</p>
<p>Pour faire un résumé très grossier : non l&#39;IA ne va pas remplacer les devs, on va juste devoir passer plus de temps sur la définition des spécifications, de la documentation, etc. En fait tout ce qui est autour du code, tout ce qui est souvent négligé.</p>
<p>Les IAs (enfin plutôt les LLMs de code) ne remplaceront pas les humains, ils vont nous faire gagner du temps sur tout ce qui est répétitif et mécanique. On va pouvoir se concentrer sur ce qui est important.</p>
<p>Par contre, il faut partir du principe que l&#39;IA a tort par défaut, l&#39;IA doit être très largement cadrée pour pouvoir produire le même niveau de qualité de code que vous auriez fait sans IA.</p>
<p>Exemple cité par Olivier : un projet web qu&#39;il a réalisé en 3 jours, donc une grosse journée et demie à raffiner le besoin et les spécifications et une maquette interactive, avant de passer à l&#39;implémentation réelle. Le genre de projet que sur LinkedIn on verrait beaucoup annoncer avoir codé en 2-3h en vibe codant… L&#39;IA c&#39;est un outil, soyez en maître ou oui vous serez remplacé !</p>
<h2 id="article-securite">Sécurité<a href="#article-securite" class="anchor" aria-label="permalink">🔗</a></h2>
<h3 id="article-attention-votre-imprimante-pourrait-bientot-ne-plus-fonctionner-a-cause-de-windows-11-httpswwwgenerationntcomactualiteswindows11microsoftimprimantepiloteobsolescence2070410"><a href="https://www.generation-nt.com/actualites/windows-11-microsoft-imprimante-pilote-obsolescence-2070410">Attention, votre imprimante pourrait bientôt ne plus fonctionner à cause de Windows 11 !</a><a href="#article-attention-votre-imprimante-pourrait-bientot-ne-plus-fonctionner-a-cause-de-windows-11-httpswwwgenerationntcomactualiteswindows11microsoftimprimantepiloteobsolescence2070410" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#Windows #Microsoft #Hardware #Sécurité #Imprimante</p>
<p>Je cite :</p>
<blockquote>
<p>La raison invoquée par la firme de Redmond est encore une fois la même que pour Windows 11 : la sécurité. Les anciens pilotes d&#39;imprimantes, spécifiquement les versions V3 (héritée de Windows Vista) et V4 (Windows 8), sont considérés comme un véritable talon d&#39;Achille pour le système d&#39;exploitation.</p>
</blockquote>
<p>Mais du coup une imprimante parfaitement fonctionnelle devrait aller à la casse parce qu&#39;aussi bien les constructeurs et Microslop en a décidé ainsi ? Une solution proposée c&#39;est d&#39;utiliser un serveur d&#39;impression sous Linux (comprendre : une petite machine sous Linux, brancher à l&#39;imprimante et au réseau pour faire intermédiaire, parce que sous Linux, tant que ça marche côté hardware, ça marchera côté software)… </p>
<p>Y&#39;a un monde où on arrête d&#39;accepter que Microslop décide pour tout le monde comme ça ? Parce qu&#39;à un moment si les anciens pilotent ont des trous de sécurités la solution c&#39;est corriger les pilotes pas jeter les imprimantes… </p>
<p>Edit : je me suis fait avoir comme beaucoup de monde, y compris la rédaction de Génération NT, en fait Microsoft a annoncé l&#39;arrêt de la mise à jour des anciens index d&#39;imprimantes, qui ont été remplacés petit à petit depuis 2014 par un nouveau système. Pour plus de détail, je vous renvoie vers l&#39;article de <a href="https://www.minimachines.net/actu/vieille-imprimante-windows-11-139364">Pierre de Minimachines</a></p>
<h3 id="article-pres-dune-publicite-sur-trois-sur-meta-menerait-vers-une-arnaque-ou-un-malwarehttpswwwphonandroidcompresdunepublicitesurtroissurmetameneraitversunearnaqueouunmalwarehtml"><a href="https://www.phonandroid.com/pres-dune-publicite-sur-trois-sur-meta-menerait-vers-une-arnaque-ou-un-malware.html">Près d’une publicité sur trois sur Meta mènerait vers une arnaque ou un malware</a><a href="#article-pres-dune-publicite-sur-trois-sur-meta-menerait-vers-une-arnaque-ou-un-malwarehttpswwwphonandroidcompresdunepublicitesurtroissurmetameneraitversunearnaqueouunmalwarehtml" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#Sécurité</p>
<blockquote>
<p>’après une enquête de Gen Digital relayée par TechRadar, 14,57 millions de publicités Meta ont été analysées sur une période de 23 jours dans l’Union européenne et au Royaume-Uni. Ces annonces représentaient 10,76 milliards d’impressions. Les chercheurs estiment que 4,51 millions d’entre elles étaient liées à des campagnes frauduleuses. Cela correspond à 30,99 % des publicités étudiées. Au total, ces annonces malveillantes ont généré plus de 304 millions d’impressions en moins d’un mois.</p>
</blockquote>
<p>Et on se demande pourquoi on est beaucoup dire qu&#39;un bloqueur de pub / anti-trackeur est nécessaire pour surfer en sécurité ! Mais après on entendra que les GAFAM font tout ce qu&#39;ils peuvent pour nous protéger… </p>
<h3 id="article-tpms--vos-pneus-balancent-votre-position-en-clair--korbenhttpskorbeninfotpmstrackingvoiturecapteurspneushtml"><a href="https://korben.info/tpms-tracking-voiture-capteurs-pneus.html">TPMS - Vos pneus balancent votre position en clair - Korben</a><a href="#article-tpms--vos-pneus-balancent-votre-position-en-clair--korbenhttpskorbeninfotpmstrackingvoiturecapteurspneushtml" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#Vie-privée #Sécurité #Voiture</p>
<blockquote>
<p>En effet, une équipe d&#39;IMDEA Networks et d&#39;armasuisse (le labo de défense suisse, rien que ça) a posé 5 récepteurs SDR dans une ville pendant 10 semaines. Coût du matos, environ 100 dollars par capteur, qui est en gros un Raspberry Pi 4 avec un dongle RTL-SDR à 25 balles. Et grâce à cela, ils ont capté plus de 6 MILLIONS de messages, provenant de plus de 20 000 véhicules !</p>
</blockquote>
<p>À priori toutes les voitures construites à partir de 2014 ont forcément du TPMS en Europe, y&#39;a aucun chiffrement, aucune authentification, et y&#39;a un identifiant unique qui est diffusé à rythme régulier… Avec même pas 100€ on peut monter un sniffeur de TPMS pour fliquer tout le monde 🤦‍♂️ </p>
<p>On peut faire quoi de notre côté ? Rien. Y&#39;a aucune option pour couper ça ou le rendre plus sécurisé… </p>
<h3 id="article-cultivating-a-robust-and-efficient-quantumsafe-httpshttpssecuritygoogleblogcom202602cultivatingrobustandefficienthtmlm1"><a href="https://security.googleblog.com/2026/02/cultivating-robust-and-efficient.html?m%3D1">Cultivating a robust and efficient quantum-safe HTTPS</a><a href="#article-cultivating-a-robust-and-efficient-quantumsafe-httpshttpssecuritygoogleblogcom202602cultivatingrobustandefficienthtmlm1" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#HTTP #Web #Google #Cloudflare #Sécurité #TLS #Quantique</p>
<p>Google et Cloudflare au sein d&#39;un groupe de travail de l&#39;IETF sont en phase de test d&#39;un potentiel remplaçant de TLS pour HTTPS pour avoir un chiffrement qui résiste aux ordinateurs quantiques. </p>
<p>Ce serait un mode de fonctionnement très différents au niveau de la création des certificats et de leur validation mais à voir ce que ça donnera. </p>
<h2 id="article-divers">Divers<a href="#article-divers" class="anchor" aria-label="permalink">🔗</a></h2>
<h3 id="article-the-only-developer-productivity-metrics-that-matterhttpsgenehackblog202602theonlydeveloperproductivitymetricsthatmatter"><a href="https://genehack.blog/2026/02/the-only-developer-productivity-metrics-that-matter/">The only developer productivity metrics that matter</a><a href="#article-the-only-developer-productivity-metrics-that-matterhttpsgenehackblog202602theonlydeveloperproductivitymetricsthatmatter" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#Métier-de-dev #Culture-d&#39;équipe #Collaboration #Dev</p>
<blockquote>
<p>So, here’s the deal, just in case you’ve forgotten or were never told: pretty much every single way management tries to measure software team productivity is bullshit. You’re not measuring what you think you’re measuring, generally; what you are measuring is how good your dev team is at gaming your metrics. (Spoiler: they’re probably going to be extremely good, especially if they’re experienced.) I assume everybody has heard the “we paid bonuses for fixing bugs” story — or if you haven’t, you can probably extrapolate — but the key thing here is: almost every single thing you can measure, the devs can game.</p>
<p>Here are the only two things you should be worried about when it comes to the question of how productive a given team of software developers is:</p>
<ol>
<li>How often does the team routinely ship new versions of the software they build?</li>
<li>How often do things break when the team ships a new version?</li>
</ol>
<p><strong>THAT’S IT.</strong> Story points per sprint doesn’t matter; lines of code, doesn’t matter; Jira tickets closed, for the love of everything, do. not. matter.</p>
<p>[…]</p>
<ol start="3">
<li>How often does a new version of the software the team builds spark actual joy in the people who have to use it?</li>
</ol>
</blockquote>
<p>Je suis tellment d&#39;accord ! </p>
<p>Imaginons que l&#39;objectif soit de livrer un maximum de ticket : qu&#39;est-ce qui m&#39;empêche de créer un max de ticket avec presque rien dedans ? </p>
<p>Imaginons que l&#39;objectif soit de &quot;produire plus&quot; et que ce soit mesuré via les story points : qu&#39;est-ce qui m&#39;empêche de sur-estimer chaque ticket ? </p>
<p>Imaginons que l&#39;objectif soit juste de livrer le plus souvent possible : livrons chaque ticket en production directement ! </p>
<p>Imaginons qu&#39;on mesure que la vitesse de correction des bugs : introduisons exprès des bugs tout bête qu&#39;on peut livrer super vite ! </p>
<p>Etc. Etc. </p>
<p>Si vous prenez des métriques qui n&#39;ont pas de sens : les gens trouveront un moyen de jouer avec la métrique ! </p>
<h3 id="article-a-candlepowered-light--hackadayhttpshackadaycom20260223acandlepoweredlight"><a href="https://hackaday.com/2026/02/23/a-candle-powered-light/">A Candle-Powered Light | Hackaday</a><a href="#article-a-candlepowered-light--hackadayhttpshackadaycom20260223acandlepoweredlight" class="anchor" aria-label="permalink">🔗</a></h3>
<p>Allumer une bougie produit 2 choses : de la lumière (ce pourquoi on allume la bougie en général) et de la chaleur (qui est généralement perdue). </p>
<p>Là cette personne s&#39;est dit qu&#39;on devait pouvoir transformer cette chaleur en énergie électrique (via l&#39;effet Peltier)  et s&#39;en servir pour alimenter 2 LEDs qui produiront elle-même de la lumière (en théorie aussi un peu de chaleur mais bon une LED de ce genre ça produit presque rien comme chaleur, c&#39;est pour ça que c&#39;est considéré comme plutôt efficient et moins consommateur en énergie que d&#39;autres systèmes). </p>
<p>Dans la vidéo il arrive à un pique à 0.40W donc vraiment pas grand-chose ! Mais c&#39;est déjà super cool d&#39;avoir réussi et c&#39;est sûrement exploitable autrement, genre avec un condensateur qui allumerait les LED dès que y&#39;a plus de production d&#39;énergie à partir de la chaleur de la bougie (comprendre = quand la bougie va s&#39;éteindre), comme ça on capte la chaleur de la bougie pour éclairer plus longtemps que la bougie plutôt qu&#39;en parallèle ! </p>
<p>Je trouve l&#39;idée intéressante ! </p>
<h3 id="article-plan-9-le-systeme-dexploitation-du-futur--olivier-poncethttpsyoutubegiivpkuir4"><a href="https://youtu.be/G-iivPkuiR4">Plan 9, le système d&#39;exploitation du futur — Olivier Poncet</a><a href="#article-plan-9-le-systeme-dexploitation-du-futur--olivier-poncethttpsyoutubegiivpkuir4" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#OS #Plan-9</p>
<p><a href="https://youtu.be/G-iivPkuiR4"><img src="https://anthonypena.fr/2026/03/03/revue-de-presse-mars/img/youtube-G-iivPkuiR4.jpg" alt="https://youtu.be/G-iivPkuiR4" title="Youtube video preview"/></a></p>
<p>Système d&#39;exploitation d&#39;une autre époque pourtant toujours maintenu par des indépendants (et aussi fortement forké, on peut citer Inferno OS comme fork important), propose énormément de concept intéressant !</p>
<p>Franchement je serais curieux de choper un laptop ultra low spec et utiliser Plan 9 au quotidien pendant quelques semaines pour voir ce que ça donne en 2026 !</p>
<h3 id="article-your-personal-blog-should-have-comments--via-le-hollandais-volanthttpslehollandaisvolantnetid20260220171312"><a href="https://lehollandaisvolant.net/?id%3D20260220171312">Your Personal Blog Should Have Comments — via Le Hollandais Volant</a><a href="#article-your-personal-blog-should-have-comments--via-le-hollandais-volanthttpslehollandaisvolantnetid20260220171312" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#Blog #Web</p>
<p>L&#39;article initial pousse l&#39;idée qu&#39;avoir un blog devrait impliquer qu&#39;on puisse commenter les articles. Je comprends l&#39;idée, je comprends l&#39;apport, je sais que je serai capable d&#39;avoir un widget de commentaire que mon blog (quand bien même c&#39;est du SSG) mais je suis d&#39;accord avec Timo : je n&#39;ai pas envie. </p>
<p>J&#39;aime avoir des retours sur mon contenu, savoir qu&#39;on me lit, savoir que ça sert à des gens que je mette tout ça en ligne, mais les commentaires sur le blog, à mon avis ce serait mauvais pour plein de raisons :</p>
<ul>
<li>c&#39;est difficile d&#39;éviter le spam (<a href="https://blog.seboss666.info/2025/08/note-de-service-je-coupe-les-commentaires/">le genre de galère que c&#39;est</a>);</li>
<li>ça m&#39;ajouterait un travail de modération en plus ;</li>
<li>beaucoup trop de gens se battent dans les commentaires, en étant pas du tout constructif au global quand bien même y&#39;a un fond intéressant à prendre ;</li>
<li>en tant que diffuseur de contenu (ce qu&#39;on est en tant que blogueur), on est responsable du contenu qu&#39;on héberge, pas qu&#39;on écrit, mais bien qu&#39;on héberge, donc les commentaires aussi (certes y&#39;a toujours l&#39;option d&#39;une modération avant mise en ligne visible mais ça veut dire être très réactif) ;</li>
</ul>
<p>Timo indique recevoir régulièrement des réponses par mails, moi j&#39;ai régulièrement des commentaires sur LinkedIn ou des messages privés. Ça me va très bien comme ça ! </p>
<p>Crédit photo : Générée via Mistral AI avec le prompt suivant : </p>
<blockquote>
<p>Une scène chaleureuse et immersive, inspirée par l’esthétique poétique de Studio Ghibli, représentant un bureau de travail en bois clair et vieilli, baigné d’une lumière dorée et tamisée, comme un après-midi d’automne. Au centre, une silhouette stylisée (style anime Ghibli : traits doux, visage non détaillé, vêtements amples et confortables) est assise en tailleur sur un tapis épais, absorbée par la lecture d’un journal tech futuriste. Le journal est ouvert, ses pages légèrement froissées, avec des titres en en-tête calligraphiés à la main : &quot;Frontend&quot;, &quot;Backend&quot;, &quot;IA&quot;, &quot;Sécurité&quot;, et &quot;Vie privée&quot;. Les pages brillent d’un halo bleu pâle, évoquant des lignes de code et des schémas techniques qui s’animent discrètement, comme par magie.
Autour d’elle, des piles de magazines et de carnets s’empilent de manière désordonnée mais harmonieuse. Certains sont ouverts, révélant des extraits d’articles, des croquis de frameworks (représentés par des icônes génériques : un crochet pour le frontend, un engrenage pour le backend, un cerveau pour l’IA, un cadenas pour la sécurité, et un masque pour la vie privée), ou des diagrammes de réseaux de neurones dessinés à la main. Un écran transparent et flottant (style holographique, mais avec un cadre en bois sculpté) affiche des flux d’informations en temps réel : des graphiques de données, des alertes de sécurité, et des extraits de code, le tout dans un style doux et organique, comme intégré à la scène.
En arrière-plan, une grande fenêtre donne sur un paysage urbain nocturne style Ghibli : des bâtiments aux formes arrondies, des lanternes suspendues, et des néons bleutés qui reflètent des motifs de code binaire sur les murs. Une tasse de thé fumant et un petit robot de bureau (inspiré des créatures de Ghibli, comme un mélange entre un Totoro miniature et un assistant tech) observent la scène avec curiosité.
À droite, un panda roux (ton animal préféré) est lové sur un coussin, les yeux mi-clos, comme s’il écoutait attentivement. Il ne doit pas dépasser le tiers de la hauteur de l’image et est positionné en bas à droite, légèrement tourné vers le centre, avec une queue soyeuse enroulée autour de lui.
L’ambiance est à la fois cosy, onirique et high-tech : les couleurs sont douces (beiges, bleus pâles, oranges chauds), avec des contrastes subtils pour mettre en valeur les éléments tech. Les détails sont soignés, avec des textures visibles (grain du bois, tissu du tapis, pelage du panda), et une lumière qui crée des jeux d’ombres chaleureuses. Le tout respire la sérénité et l’inspiration, comme un moment suspendu entre la magie et la technologie.</p>
</blockquote>
]]></content:encoded>
      <dc:creator><![CDATA[Anthony Pena]]></dc:creator>
      <media:content medium="image" url="https://anthonypena.fr/img/cover.min.jpg"/>
    </item>
    <item>
      <title><![CDATA[Les trucs à lire dans votre vie de dev]]></title>
      <guid isPermaLink="false">2026/02/18/les-trucs-a-lire-dans-votre-vie-de-dev</guid>
      <description><![CDATA[<p>On m&#39;a déjà demandé ce que je pouvais recommander comme lecture pour s&#39;améliorer en tant que dévelop…</p>
]]></description>
      <link>https://anthonypena.fr/2026/02/18/les-trucs-a-lire-dans-votre-vie-de-dev/index.html</link>
      <category><![CDATA[Avis]]></category>
      <category><![CDATA[Métier de dev]]></category>
      <pubDate>Wed, 18 Feb 2026 07:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>On m&#39;a déjà demandé ce que je pouvais recommander comme lecture pour s&#39;améliorer en tant que développeur. J&#39;ai fini par écouter cette demande (particulièrement merci à toi Bich de m&#39;avoir vraiment poussé sur ce sujet même si j&#39;aurai mis du tout à le faire !) et me poser sur ce guide !</p>
<h2 id="article-avantpropos">Avant-propos<a href="#article-avantpropos" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Je vous avoue que l&#39;exercice est à mon sens assez difficile :</p>
<ul>
<li>les livres techs ça coûte souvent cher (même très cher) ;</li>
<li>il n&#39;y a pas une grosse offre côté occasion (même si vraiment il faut fouiller, ça vaut le coût !) ;</li>
<li>la masse des livres traitent d&#39;une version d&#39;un langage / outil / plateforme et sont vite dépassés ;</li>
<li>il faut se concentrer sur les livres qui partage des concepts / idées pour avoir quelque chose de plutôt intemporel ;</li>
<li>il y a souvent plusieurs éditions des livres, plus ou moins modernes, mais pour les livres à concept une ancienne édition fonctionne généralement très bien ;</li>
<li>pour moi le plus difficile pour les débutants : le gros de la littérature est en anglais, anglais un peu soutenu / formel, avec un vocabulaire pas toujours simple… ;</li>
</ul>
<p>J&#39;ai donc mis dû temps à écrire cet article parce que je voulais me laisser le temps de bien choisir le contenu qui allait y figurer ! Si à la base j&#39;étais resté focus sur des livres papiers, je me suis finalement décidé à inclure d&#39;autres ressources qui pour moi vont parfaitement dans cette catégorie.</p>
<h2 id="article-__lopen-space-ma-tuer__httpswwwbabeliocomlivresisnardslopenspacematuer1271110--alexandre-des-isnards"><a href="https://www.babelio.com/livres/Isnards-Lopen-space-ma-tuer/1271110"><strong>L&#39;open space m&#39;a tuer</strong></a> — Alexandre des Isnards<a href="#article-__lopen-space-ma-tuer__httpswwwbabeliocomlivresisnardslopenspacematuer1271110--alexandre-des-isnards" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Je commence par un livre qui n&#39;est pas du tout tech paradoxalement, mais que je trouve hyper important à lire, particulièrement en début de carrière, quand bien même je l&#39;ai moi-même lu que l&#39;année dernière.</p>
<p><em>L&#39;open space m&#39;a tuer</em> est un livre qui m&#39;a marqué car il évoque ce que c&#39;est que de travailler dans un open space, de tout ce que ça implique, surtout de négatif. C&#39;est quelque chose que je pense ait difficile à vraiment anticiper avant de l&#39;avoir vécu. Je pense que ce livre m&#39;aurait vraiment aidé.</p>
<p>Travailler en open space c&#39;est subir un bruit constant, subir les échanges des autres personnes présentes, se gêner continuellement les uns les autres, ne pas avoir d&#39;espace à soi (merci le sacro-saint flex office qui accompagne souvent l&#39;open space), c&#39;est voir / sentir les aller et venus de tout le monde continuellement, etc.</p>
<p>Ce livre est vraiment le symbole de tout ce qui se fait de pire dans l&#39;open space. C&#39;est une lecture très facile à mon sens, ça permet de bien se rendre compte de comment on vit l&#39;open space mais aussi le travail de bureau avec tous ses codes, tous ses rituels, tous ses faux-semblants.</p>
<p>Quand bien même il y a des intérêts sociaux à l&#39;open space, je pense qu&#39;il y a surtout des inconvénients, particulièrement quand c&#39;est mal vu de bosser avec un casque et de la musique pour s&#39;isoler dans sa bulle…</p>
<p>Bref, un livre pas tech, mais qui représente un aspect important du travail de développeur, même si vous avez déjà de l&#39;expérience : c&#39;est un livre à lire !</p>
<h2 id="article-__12-factors-app__https12factornetfr--adam-wiggins"><a href="https://12factor.net/fr/"><strong>12 factors app</strong></a> — Adam Wiggins<a href="#article-__12-factors-app__https12factornetfr--adam-wiggins" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Avant de passer à un autre livre, je vais passer sur la première ressource web. J&#39;ai mis le lien vers la traduction française du site (traduction officielle, créé de manière collaborative sur le github 12factor), mais il existe aussi une version ebook (format epub, reprenant strictement le contenu de la version anglaise du site) qui n&#39;est par contre elle disponible qu&#39;en anglais. À vous de voir.</p>
<p>Le contenu est assez court (environ 25 pages au format livre), mais c&#39;est un livre qu&#39;on devrait tous avoir lu au moins une fois et même relire régulièrement !</p>
<p>On va y retrouver un tas de bonne pratique de conception d&#39;une application en termes de construction, de déploiement, de configuration, monitoring, et tout ce qui va avec. On parle clairement de principes DevOps ici, mais sans forcer la référence à une technologie en particulier. Ici personne ne vous dira que vous devez faire une Kubernetes avec une image particulière, mais quelle méthodologie vous devriez utiliser peu importe la plateforme ou le langage.</p>
<p>J&#39;ai lu ça en tout début de carrière, et clairement ça a été une brique fondamentale de ma manière de penser les applications ensuite.</p>
<h2 id="article-__refactoring__httpswwwbabeliocomlivresfowlerrefactoring1341944--martin-fowler"><a href="https://www.babelio.com/livres/Fowler-Refactoring/1341944"><strong>Refactoring</strong></a> — Martin Fowler<a href="#article-__refactoring__httpswwwbabeliocomlivresfowlerrefactoring1341944--martin-fowler" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Ici on parle d&#39;un livre d&#39;un maître de l&#39;informatique : Martin Fowler.</p>
<p>C&#39;est un livre qui est très didactique, très orienté cas concret, avec beaucoup de méthodes. J&#39;aime beaucoup ce livre, car il remet au centre du sujet le refactoring alors que c&#39;est quelque chose qui est souvent relégué au second plan, une étape optionnelle qu&#39;on ne fait que si on a le temps…</p>
<p>Refactoring va vous aider à vous projeter et à prendre du recul sur votre code. Il va vous aider en vous proposant des schémas reconnaissables pour améliorer votre code et vous assurer qu&#39;il pourra évoluer, qu&#39;il sera maintenable dans le temps, tout en vous fixant les bonnes limites, en vous posant les bonnes questions, en aidant à ne pas casser le projet en faisant ça.</p>
<p>Tous les exemples sont en Java, car c&#39;est un des langages que Martin Fowler maitrise bien tout simplement, mais ne vous inquiétez pas de voir des éléments compliqués de Java moderne : il a été écrit en 1999, on est donc face à du très vieux Java (version 1.2), et plus ou moins tout est transposable à n&#39;importe quel autre langage.</p>
<p>C&#39;est un livre qui sera souvent trouvable neuf assez chers (50-100€), mais si vous cherchez un peu et/ou êtes patient, vous le trouverez assez souvent à une dizaine d&#39;euros. À priori peu importe l&#39;édition, le contenu ne change pas : j&#39;ai une copie imprimé en 2012 mais indiqué comme l&#39;édition de 1999. Tout le contenu est toujours d&#39;actualité, au pire on peut faire encore mieux avec du Java plus moderne !</p>
<blockquote>
<p>Note : j&#39;ai parfois vu des livres qui semblent être des versions françaises de Refactoring, et mes recherches me laissent penser que le livre n&#39;a pas été officiellement traduit. Donc je ne peux que vous orienter vers l&#39;original en anglais, car c&#39;est un anglais assez simple à lire et vous serez certain de la qualité du contenu.</p>
</blockquote>
<h2 id="article-__design-driven-development__httpswwwbabeliocomlivresevansdomaindrivendesign949958--eric-evans"><a href="https://www.babelio.com/livres/Evans-Domain-Driven-Design/949958"><strong>Design Driven Development</strong></a> — Eric Evans<a href="#article-__design-driven-development__httpswwwbabeliocomlivresevansdomaindrivendesign949958--eric-evans" class="anchor" aria-label="permalink">🔗</a></h2>
<p>C&#39;est clairement un livre de référence.</p>
<p>C&#39;est aussi un livre difficile à lire…</p>
<p>Je reste partagé par ce livre. Je suis globalement d&#39;accord pour dire qu&#39;on devrait appliquer à peu près tous les principes de DDD, mais je trouve que le livre est aussi assez difficile à lire et comprendre. Je pense que c&#39;est un livre qui mérite d&#39;être lu mais plutôt par morceau en revenant dessus régulièrement.</p>
<p>Je n&#39;ai jamais réussi à finir ce livre à date, mais tout ce que j&#39;en ai lu à changer ma manière de penser les projets. Et aussi fait réalisé qu&#39;on loupe des étapes fondamentales…</p>
<p>Un exemple qui m&#39;a vraiment marqué : l&#39;ubiquitous language, avoir un langage (au sens : un vocabulaire) unique, clairement défini, qui repose la définition de chaque terme qui peut prêter à confusion pour quelqu&#39;un d&#39;extérieur au projet, avec si possible aucun ou presque synonyme, aucun &quot;à peu près&quot;, etc. Tout ce qu&#39;il faut pour que deux personnes, peu importe leur rôle dans l&#39;équipe parle des mêmes entités métiers avec le même vocabulaire et se comprennent sans aucune ambiguïté. Ça parait évident et pourtant je n&#39;ai jamais vu ça appliqué…</p>
<p>Je pense que c&#39;est un livre dont il faut au moins lire les premiers chapitres qui sont fondamentaux et au pire basculer sur des ressources en ligne pour compléter.</p>
<h2 id="article-the-agile-manifestohttpsagilemanifestoorgisofrmanifestohtml--extreme-programminghttpwwwextremeprogrammingorg"><a href="https://agilemanifesto.org/iso/fr/manifesto.html">The Agile Manifesto</a> &amp; <a href="http://www.extremeprogramming.org/">Extreme Programming</a><a href="#article-the-agile-manifestohttpsagilemanifestoorgisofrmanifestohtml--extreme-programminghttpwwwextremeprogrammingorg" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Je regroupe les deux car pour moi c&#39;est plus ou moins la même chose, car écrit plus ou moins par les mêmes personnes.</p>
<blockquote>
<p>Note : pour les puristes qui passeraient pas ici, je sais que The Agile Manifesto et Extreme Programming c&#39;est différent, MAIS pour moi on retrouve à peu près les mêmes idées, juste que Extreme Programming est pour moi plus précis, plus détaillé que The Agile Manifesto, un peu comme Scrum / Kanban.</p>
</blockquote>
<p>Ces deux textes sont le socle de toutes les méthodes agiles : des principes et guides pour comprendre comment organiser un projet (au sens large) et comment l&#39;équipe projet doit s&#39;intégrer à l&#39;organisation de l&#39;entreprise et interagir avec les utilisateurs.</p>
<p>Ce ne sont pas des textes qui sont dirigistes mais plutôt qui vont vous aider à définir un cadre de travail saint, un cadre de travail où vous allez pouvoir délivrer de la valeur tout en vous adaptant aux changements (particulièrement aux changements dus à l&#39;écart entre ce dont vos utilisateurs pensent avoir besoin et ce dont ils ont besoins réellement).</p>
<h2 id="article-conclusion">Conclusion<a href="#article-conclusion" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Même si je ne devrais pas vraiment dire ça, mais si vous n&#39;avez pas les moyens / ne vous sentez pas capable de lire un livre comme ça en anglais : n&#39;hésitez pas à jeter un coup d&#39;œil sur des sites comme Anna&#39;s Archive pour trouver une version epub et jeter un coup d&#39;œil. Il sera toujours temps d&#39;acheter le livre plus tard quand l&#39;occasion se présentera !</p>
<p>J&#39;espère vous avoir donné envie d&#39;aller lire au moins une partie de ces livres / contenus avec mon article, en tout cas pour moi il s&#39;agit de lecture qui m&#39;ont vraiment été utile, et peut-être que ça pourrait l&#39;être pour vous aussi !</p>
<p>Crédit photo : Générée via Mistral AI avec le prompt suivant : </p>
<blockquote>
<p>A cozy, Ghibli-inspired illustration of a futuristic yet organic library. The scene features curved wooden bookshelves filled with floating books, including recognizable titles like &quot;Domain-Driven Design&quot; by Eric Evans, &quot;Refactoring&quot; by Martin Fowler, &quot;The Agile Manifesto,&quot; and &quot;Extreme Programming.&quot; A red panda, sitting cross-legged on a pile of books, holds a parchment with DevOps principles and code diagrams written on it. Around the red panda, holograms of keywords like &quot;Ubiquitous Language&quot; and &quot;Clean Code&quot; gently float in the air. Soft light filters through stained glass windows depicting autumn leaves, casting a warm golden glow over the scene. In the background, a Ghibli-inspired robot organizes books on the shelves. The atmosphere is serene, blending technology and nature, with a focus on timeless knowledge and the harmony between tradition and modernity.</p>
</blockquote>
]]></content:encoded>
      <dc:creator><![CDATA[Anthony Pena]]></dc:creator>
      <media:content medium="image" url="https://anthonypena.fr/img/cover.min.jpg"/>
    </item>
    <item>
      <title><![CDATA[Nouveau blog --  partie 4 : et le reste...]]></title>
      <guid isPermaLink="false">2026/02/10/nouveau-blog-partie-4-et-le-reste</guid>
      <description><![CDATA[<p>Dans cet article je vais parler en vrac de tous les petits trucs qui font que tout fonctionne et qu&#39;…</p>
]]></description>
      <link>https://anthonypena.fr/2026/02/10/nouveau-blog-partie-4-et-le-reste/index.html</link>
      <category><![CDATA[Web]]></category>
      <category><![CDATA[Frontend]]></category>
      <pubDate>Tue, 10 Feb 2026 07:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>Dans cet article je vais parler en vrac de tous les petits trucs qui font que tout fonctionne et qu&#39;on voit moins : le flux RSS, le déploiement chaque matin, des problèmes aussi… </p>
<nav data-serie="nouveau-blog-marked-deno">
<h2>Série d'article</h2>
<ul>
<li><a href="https://anthonypena.fr/2026/01/15/nouveau-blog-partie-1-html/index.html">Nouveau blog -- partie 1 : HTML</a></li>
<li><a href="https://anthonypena.fr/2026/01/21/nouveau-blog-partie-2-css/index.html">Nouveau blog -- partie 2 : CSS</a></li>
<li><a href="https://anthonypena.fr/2026/01/27/nouveau-blog-partie-3-js/index.html">Nouveau blog -- partie 3 : JavaScript</a></li>
<li><a href="https://anthonypena.fr/2026/02/10/nouveau-blog-partie-4-et-le-reste/index.html">Nouveau blog --  partie 4 : et le reste...</a></li>
</ul>
</nav>
<h2 id="article-le-flux-rss">Le flux RSS<a href="#article-le-flux-rss" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Le flux RSS c&#39;est une brique qui est devenue quasiment inconnu alors que c&#39;est un outil hyper pratique : vous pouvez suivre les publications de n&#39;importe qui (pour peu qu&#39;il mette à disposition un flux RSS) sans aucun réseau social, sans aucune brique centralisée, en décidant vous-même à quelle fréquence vous souhaitez relever les flux (adieu la pollution de l&#39;attention à cause des notifications), en décidant vous-même de qui vous allez suivre (adieu les réseaux comme Youtube qui vous désabonne sans rien dire ou comme Twitter (non je dirais pas &quot;X&quot;) qui vous force à suivre son propriétaire mégalo), avec le client de votre choix pour avoir la vue qui vous convient le mieux.</p>
<p>Par exemple, j&#39;ai fait le choix d&#39;avoir ma propre instance <a href="https://www.freshrss.org/">FreshRSS</a> que je consulte essentiellement via mon smartphone et l&#39;application <a href="https://github.com/ReadYouApp/ReadYou">Read You</a></p>
<figure id="image-gallery-differentes-vue-de-read-you-sur-mon-smartphone" class="marked-image-gallery" is="gallery-zoom">
<img src="https://anthonypena.fr/2026/02/10/nouveau-blog-partie-4-et-le-reste/img/read-you-1.jpg" alt="Différentes vue de Read You sur mon smartphone"/>
<img src="https://anthonypena.fr/2026/02/10/nouveau-blog-partie-4-et-le-reste/img/read-you-2.jpg" alt="Différentes vue de Read You sur mon smartphone"/>
<img src="https://anthonypena.fr/2026/02/10/nouveau-blog-partie-4-et-le-reste/img/read-you-3.jpg" alt="Différentes vue de Read You sur mon smartphone"/>
<figcaption>Différentes vue de Read You sur mon smartphone</figcaption>
</figure>
<p>Je l&#39;utilise pour suivre des gens que je connais (coucou Nicolas Brondin-Bernard 👋 qui apparait en screenshot, coucou aussi Siegfried 👋), des gens que je ne connais pas (en tout cas pas personnellement, mais les années passant je &quot;connais&quot; bien leur identité en ligne, par exemple Sebsauvage, Seboss666, Korben ou Pierre de minimachines.net), je suis aussi les mises à jours sur des projets Github (par exemple, je suis les mises à jour de FreshRSS comme ça pour avoir tout le détail des releases), Lobsters (qui est un agrégateur de contenu collaboratif), l&#39;actualité mobile / jeux-vidéos / mangas, etc. Je fais l&#39;essentiel de ma veille via du RSS.</p>
<p>Je l&#39;ai montré plus haut : je suis aussi mon propre flux RSS. Pas par égocentrisme, mais pour m&#39;assurer qu&#39;il fonctionne et qu&#39;on voit bien apparaitre mon contenu dans ce flux, vérifier que le contenu est complet aussi, qu&#39;il n&#39;y a pas de bug particulier. (et c&#39;est en disant ça que je vois un bug qui fait que les images ne s&#39;affichent pas, donc je fais une pause dans l&#39;écriture pour corriger ça 🫠)</p>
<p>Il y a des bonnes librairies qui permettent de générer un flux RSS, mais au fond ce n&#39;est qu&#39;un fichier XML, avec des balises spécifiques, donc c&#39;est assez facile de le générer avec un script maison. C&#39;est donc ce que j&#39;ai fait : je produis le flux RSS à la &quot;main&quot;, à chaque build du blog. Vous pouvez donc être informé à chaque nouvel article via mon flux RSS (qui est aussi compatible Atom pour les curieux, je vous laisse aller voir le détail) et lire mon contenu sans même vous rendre sur mon blog : je veux partager, pas générer du trafic, je vous laisse donc le choix.</p>
<h2 id="article-deno-et-typescript-everywhere">Deno et TypeScript everywhere<a href="#article-deno-et-typescript-everywhere" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Je ne vais pas refaire un laïus sur le sujet (j&#39;en ai déjà fait un dans la partie 1 de la série) : Deno c&#39;est trop bien, y&#39;a pas de débat pour moi.</p>
<p>J&#39;ai donc choisi cette plateforme pour coder mon blog. Mais comme je vous le dis depuis le début de la série : tout est statique. En effet j&#39;ai écrit un ensemble de script en TypeScript qui vient lire mon contenu Markdown, ajouter ce qu&#39;il faut et produire un site statique. Environ 1200 lignes de TypeScript cerveau-codé (par opposition à vibe-codé, merci Siegfried pour cette expression que j&#39;aime beaucoup), réparti sur une quinzaine de scripts qui font chacun une partie du traitement en séquence.</p>
<p>Sans chercher l&#39;optimisation, mais en utilisant des <code>console.time()</code>/<code>console.timeEnd()</code> pour mesurer le temps de chaque partie (pour savoir si je dois optimiser quelque part un jour), j&#39;ai sur ma machine ça comme mesure de temps avec Deno 2.6.3 :</p>
<pre><code>Prepare env: 79.6ms
List articles files: 2.92ms
Extract metadata: 79.6ms
Convert articles to HTML: 398ms
Copy article statics: 308ms
Copy template statics: 1.66ms
Write raw HTML: 13.8ms
Write article metadata: 6.11ms
Build article pages: 39.0ms
Build full article list: 0.249ms
Build archive pages: 0.682ms
Build index: 1.11ms
Build RSS Feed: 4.01ms
Build server script: 0.308ms
Build: 943ms
</code></pre><p>Moins d&#39;une seconde donc, et on voit que les parties longues c&#39;est la conversion Markdown (presque 400ms) et la copie des fichiers statiques (300ms) pour un total sous la seconde.</p>
<p>Côté pipeline (Github Actions), je suis plutôt autour de 2.5 secondes :</p>
<pre><code>List articles files: 12.1ms
Extract metadata: 137ms
Convert articles to HTML: 856ms
Copy article statics: 1379ms
Copy template statics: 3.39ms
Write raw HTML: 35.8ms
Write article metadata: 18.6ms
Build article pages: 74.3ms
Build full article list: 0.533ms
Build archive pages: 1.38ms
Build index: 1.77ms
Build RSS Feed: 6.24ms
Build server script: 0.504ms
Build: 2545ms
</code></pre><p>On voit là que c&#39;est l&#39;écriture sur le disque qui consomme vraiment beaucoup plus de temps (x4.5) alors que la conversion des fichiers Markdown en HTML n&#39;augmente pas tant que ça (x2).</p>
<p>Dans tous les cas, la performance actuelle de mon système me convient très bien. J&#39;avais peur qu&#39;en étant codant le truc aussi simplement et avec si peu d&#39;effort côté performance ce soit particulièrement lent mais à date ce n&#39;est pas le cas (même si je pourrais clairement faire des optimisations).</p>
<h2 id="article-pipeline-tres-simple">Pipeline très simple<a href="#article-pipeline-tres-simple" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Je vous donne mon pipeline qui n&#39;a rien de bien fou :</p>
<pre><code class="hljs language-Yaml"><span class="hljs-attr">name:</span> <span class="hljs-string">Deploy</span>
<span class="hljs-attr">on:</span>
  <span class="hljs-attr">push:</span>
    <span class="hljs-attr">branches:</span> <span class="hljs-string">master</span>
  <span class="hljs-attr">pull_request:</span>
    <span class="hljs-attr">branches:</span> <span class="hljs-string">master</span>
  <span class="hljs-attr">schedule:</span>
    <span class="hljs-comment"># every weekday at 6:00AM (for real: between 6:00AM and 6:30AM)</span>
    <span class="hljs-comment"># les serveur Github sont en UTC donc décalés d&#x27;1h donc mettre 6:00 donne des builds entre 7h00 et 7h30</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">cron:</span> <span class="hljs-string">&quot;0 5 * * 1-5&quot;</span>

<span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">deploy:</span>
    <span class="hljs-attr">name:</span> <span class="hljs-string">Deploy</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>

    <span class="hljs-attr">permissions:</span>
      <span class="hljs-attr">id-token:</span> <span class="hljs-string">write</span> <span class="hljs-comment"># Needed for auth with Deno Deploy</span>
      <span class="hljs-attr">contents:</span> <span class="hljs-string">read</span> <span class="hljs-comment"># Needed to clone the repository</span>

    <span class="hljs-attr">steps:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Clone</span> <span class="hljs-string">repository</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v4</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Install</span> <span class="hljs-string">Deno</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">denoland/setup-deno@v2</span>
        <span class="hljs-attr">with:</span>
          <span class="hljs-attr">deno-version:</span> <span class="hljs-string">v2.x</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Install</span> <span class="hljs-string">step</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">&quot;deno install&quot;</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Fmt</span> <span class="hljs-string">step</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">&quot;deno task fmt:check&quot;</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Lint</span> <span class="hljs-string">step</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">&quot;deno task lint&quot;</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Build</span> <span class="hljs-string">step</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">&quot;deno task build&quot;</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Upload</span> <span class="hljs-string">to</span> <span class="hljs-string">Deno</span> <span class="hljs-string">Deploy</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">denoland/deployctl@v1</span>
        <span class="hljs-attr">with:</span>
          <span class="hljs-attr">project:</span> <span class="hljs-string">&quot;anthonypena-blog&quot;</span>
          <span class="hljs-attr">entrypoint:</span> <span class="hljs-string">&quot;./main.ts&quot;</span>
          <span class="hljs-attr">root:</span> <span class="hljs-string">&quot;./dist&quot;</span><div aria-hidden="true" class="language-tag">Yaml</div>
</code></pre><p>J&#39;ai fait simple. À chaque commit sur la branche <code>master</code>, ou pull request ou chaque matin (j&#39;y reviens plus loin), le pipeline s&#39;enclenche. Ce pipeline va cloner le dépôt dans une image ubuntu (potentiellement je pourrais faire plus optimal ici maintenant que j&#39;y pense), j&#39;installe Deno, j&#39;installe les dépendances de mon projet, je vérifie le formatage du code (pas des Markdown, juste le code du moteur de blog que j&#39;ai codé), je vérifie le lint (que du moteur encore une fois), je lance la construction du blog et pour finir je pousse pour le déploiement (j&#39;y reviendrais plus loin).</p>
<p>Le pipeline complet prend environ 50 secondes.</p>
<p>J&#39;utilise peu de branche (car je travaille seul) mais j&#39;aime bien avoir le pipeline au besoin.</p>
<p>J&#39;ai ajouté une exécution chaque matin pour ajouter le dynamisme qui manquait au côté statique : pour mettre en ligne un article j&#39;ai besoin de recompiler le blog, or, je publie généralement le mardi matin avec un post sur LinkedIn / Twitter à 8h00. Si j&#39;ai tout programmé côté réseaux sociaux ce n&#39;est pas pour avoir une action manuelle pour mettre en ligne l&#39;article lui-même, donc j&#39;ai mis en place une mécanique simple pour vérifier si un article doit être &quot;public&quot; ou pas qui va afficher ou non l&#39;article à partir de la bonne date. Je peux donc au besoin programmer quelques articles d&#39;avance sans effort : tout fonctionne tout seul côté infra.</p>
<p>Par contre, vous l&#39;avez peut-être lu dans les commentaires, j&#39;ai un peu joué avec les heures d&#39;exécution. À la base je voulais une exécution à 7h00 du lundi au vendredi (donc un cron <code>0 7 * * 1-5</code> (minute = 0 ; heure = 7 ; jour du mois = * (=tous) ; mois = * (=tous) ; du lundi au vendredi = 1-5)). Mais ce n&#39;est pas aussi simple… Déjà les runner Github Actions fonctionnent en UTC. Donc demander une exécution à 7h00 UTC implique une exécution à 8h00 heure de Paris… Soit. Je suis passé à <code>0 6 * * 1-5</code>. Et là je me suis rendu compte que l&#39;exécution programmée à &quot;7h00&quot; était plutôt vers &quot;7h30-35&quot; (surement pour des questions de charge de runner), donc comme je veux que l&#39;article soit en ligne à 8h00 pour les réseaux sociaux et un peu avant pour que vous l&#39;ailliez avant ça dans vos lecteurs RSS, ça n&#39;allait pas… Donc j&#39;ai avancé à <code>0 5 * * 1-5</code> pour avoir une construction du blog avant 7h.</p>
<blockquote>
<p>Note : si vous pensez que je parle le cron parfaitement, vous vous trompez. Je suis un utilisateur efficace de Crontab Guru.</p>
<figure>
<img src="https://anthonypena.fr/2026/02/10/nouveau-blog-partie-4-et-le-reste/img/cron-tab-guru.gif" alt="Démonstration de Crontab Guru" is="img-zoom"/>
<figcaption>Démonstration de Crontab Guru</figcaption>
</figure>
</blockquote>
<p>Clairement cette histoire de cron c&#39;est ce qui m&#39;a pris le plus de temps côté pipeline, et je m&#39;y attendais pas… Comme quoi le diable se cache dans les détails… 🥲</p>
<h2 id="article-deno-deploy">Deno Deploy<a href="#article-deno-deploy" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Avec la refonte du blog, j&#39;en ai aussi fini avec le self host. Je suis parfaitement capable d&#39;héberger à la maison ou sur un serveur, mais j&#39;ai choisi la simplicité : je suis passé par Deno Deploy.</p>
<p>Deno Deploy, comme son nom l&#39;indique, est la partie cloud accolé à Deno. Vous n&#39;êtes pas obligé de pousser des applications Deno sur Deno Deploy mais quoi qu&#39;il arrive le moteur qui exécutera votre code sera Deno.</p>
<p>De mon côté, j&#39;ai un site entièrement static ! Ou presque… En fait il y a une toute petite partie qui est dynamique : le routing pour gérer les redirections.</p>
<p>En effet sur Deno Deploy il n&#39;y a pas de manière déclarative de définir des redirections (en self host j&#39;aurai bêtement généré un fichier de config pour nginx par exemple), j&#39;ai donc un script Deno d&#39;une quarantaine de lignes qui prend chaque requête en entrée, regarde si le fichier existe pour le servir directement, sinon fait quelques manipulations :</p>
<ul>
<li>tenter d&#39;ajouter un <code>/index.html</code> pour voir ça existe, ce qui permet que <code>https://anthonypena.fr/2026/01/27/nouveau-blog-partie-3-js</code>, <code>https://anthonypena.fr/2026/01/27/nouveau-blog-partie-3-js/</code> et <code>https://anthonypena.fr/2026/01/27/nouveau-blog-partie-3-js/index.html</code> vous donne la page de l&#39;article ;</li>
<li>voir si une redirection existe dans la liste des redirections pour vous renvoyer un code HTTP <code>301</code> (Moved Permanently, donc votre navigateur vous redirigera directement si vous redemandez l&#39;URL) avec la nouvelle URL ;</li>
<li>gérer quelques cas de 404 proprement ;</li>
</ul>
<p>En effet avec Ghost, j&#39;avais des URLs en <code>k49.fr.nf/ovh-et-vieux-kernel</code> alors que maintenant j&#39;ai décidé que les URLs aurait la forme <code>anthonypena.fr/2016/05/13/ovh-et-vieux-kernel</code> (avec donc la date dans l&#39;URL), je ne voulais pas casser 9 ans de référencement à droite et à gauche, donc j&#39;ai fait en sorte de gérer au maximum les URLs. Je sais qu&#39;il en manque sur des pages plus techniques comme <code>/tag/tutoriel/</code> et <code>/page/2/</code> (remontées par Duck Duck Go via la recherche <code>site:k49.fr.nf</code>) qui vous redirigeront vers la page d&#39;accueil à date, mais c&#39;est plus marginal je pense.</p>
<p>Évidemment, comme j&#39;ai aussi changé de nom de domaine, j&#39;ai aussi mis en place une redirection pour passer de l&#39;ancien domaine au nouveau de manière transparente pour vous.</p>
<h2 id="article-la-ou-ca-grince-encore">Là où ça grince encore<a href="#article-la-ou-ca-grince-encore" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Je n&#39;avais jamais réalisé ça mais mon blog commence à subir le poids des années : le dossier dist pèse un peu plus de 700Mo à date. Vous vous en doutez : c&#39;est essentiellement les images qui pèsent lourd dans la balance.</p>
<p>J&#39;ai été un peu bourrin en copiant tout sans plus de réflexion, mais je sais que je pourrais optimiser ça, déjà en ne copiant que les images vraiment utilisées dans les articles pour éviter de copier des images pour rien. Je pense que je pourrais économiser énormément de poids et donc de temps à uploader le contenu.</p>
<p>Je sais aussi que la page d&#39;accueil est assez longue à charger : il y a beaucoup d&#39;images, là encore ça ne s&#39;invente pas. Mais j&#39;ai des pistes d&#39;améliorations faciles !</p>
<ul>
<li>Passer toutes les images en lazy loading pour que le navigateur les charges en dernier (ça implique de bien gérer la taille des images pour éviter que vous n&#39;aillez trop de layout shift, mais c&#39;est pas compliqué) ;</li>
<li>Profiter d&#39;avoir un peu de code côté serveur pour le routing pour gérer un peu de cache réseau avec les headers de cache adéquat car pour l&#39;instant je me repose entièrement sur le navigateur pour faire les choses bien, et je peux faire mieux ;</li>
<li>produire une version miniature des images spécifiquement pour la page d&#39;accueil de sorte à éviter de charger la version grand format de l&#39;image de couverture ;</li>
</ul>
<p>Je pense que je pourrais optimiser encore plus, mais c&#39;est des pistes évidentes et facile. Je ferai ça dans le futur quand j&#39;aurai du temps pour vraiment me poser là-dessus, en attendant je peux publier du contenu et vous pouvez me lire !</p>
<h2 id="article-conclusion">Conclusion<a href="#article-conclusion" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Cette série arrive enfin à son terme !</p>
<p>Cette refonte me simplifie la vie côté production de contenu, mais évidemment m&#39;ajoute une complexité ailleurs vu que je dois aussi corriger l&#39;affichage sur des appareils divers et variés… Merci à ceux qui me ping pour me pointer un bug, je note et je vais prendre en compte, il y a juste des bugs parfois un peu subtils (oui je pense à toi Romain et ton iphone 8, promis je suis en train de regarder 🫠).</p>
<p>Ça m&#39;ouvre énormément de portes à commencer par la possibilité d&#39;avoir des pages complètement personnalisés pour centraliser tout sur mon site, qui ne sera plus seulement un blog (même si ça restera l&#39;activité principale !).</p>
<p>Merci à ceux qui ont lu toute la série ! Merci évidemment aussi à ceux qui me lisent tout court (que ce soit tout le temps ou de temps en temps) !</p>
<p>Crédit photo : Générée via Mistral AI avec le prompt suivant : </p>
<blockquote>
<p>Une scène chaleureuse et immersive, inspirée par l’esthétique poétique de Studio Ghibli, représentant un port spatial artisanal en bois clair et vieilli, baigné d’une lumière dorée et bleutée tamisée, comme un crépuscule d’automne. Au centre, un panda roux anthropomorphe (Firefox), vêtu d’une veste de capitaine en tissu texturé, supervise le chargement de caisses en bois estampillées &quot;Static HTML&quot; et &quot;Deno Land&quot; sur un vaisseau spatial fait de bois et de cuivre. Le vaisseau, inspiré des machines volantes de Ghibli, est entouré de lanternes en papier flottantes qui guident le chemin vers les étoiles.</p>
<p>Autour du panda roux, des robots miniatures (inspirés des créatures de Ghibli, comme un mélange entre un Totoro et un assistant technique) aident à charger les caisses, tandis qu’un écran holographique (avec un cadre en bois sculpté) affiche une carte stellaire avec des routes vers des planètes nommées &quot;GitHub Pages&quot;, &quot;Netlify&quot;, et &quot;Cloudflare&quot;. Des néons bleutés et des motifs de code binaire flottent dans l’air, comme des étoiles filantes numériques.</p>
<p>En arrière-plan, une grande fenêtre donne sur un ciel étoilé, où des nuages en forme de code binaire reflètent la lumière des lanternes. Une tasse de thé fumant et des parchemins déroulés (symbolisant les logs de déploiement) sont posés sur un bureau en bois, à côté d’un petit robot endormi.</p>
<p>À droite, en bas, le panda roux est légèrement tourné en 3/4 dos, lové sur un coussin, entouré d’un halo lumineux subtil. Il ne dépasse pas le tiers de la hauteur de l’image et observe la scène avec satisfaction, comme s’il contemplait le voyage de son site vers le web.</p>
<p>L’ambiance est cosy, onirique et high-tech : les couleurs sont douces (beiges, bleus pâles, oranges chauds), avec des jeux de lumière tamisée qui créent des ombres chaleureuses. Les détails sont soignés, avec des textures visibles (grain du bois, tissu de la veste, pelage du panda roux), et une lumière qui met en valeur les éléments tech et artisanaux. Le tout respire la sérénité et l’inspiration, comme un moment suspendu entre la magie et la technologie.&quot;&quot;Une scène chaleureuse et immersive, inspirée par l’esthétique poétique de Studio Ghibli, représentant un port spatial artisanal en bois clair et vieilli, baigné d’une lumière dorée et bleutée tamisée, comme un crépuscule d’automne. Au centre, un panda roux anthropomorphe (Firefox), vêtu d’une veste de capitaine en tissu texturé, supervise le chargement de caisses en bois estampillées &quot;Static HTML&quot; et &quot;Deno Land&quot; sur un vaisseau spatial fait de bois et de cuivre. Le vaisseau, inspiré des machines volantes de Ghibli, est entouré de lanternes en papier flottantes qui guident le chemin vers les étoiles.</p>
<p>Autour du panda roux, des robots miniatures (inspirés des créatures de Ghibli, comme un mélange entre un Totoro et un assistant technique) aident à charger les caisses, tandis qu’un écran holographique (avec un cadre en bois sculpté) affiche une carte stellaire avec des routes vers des planètes nommées &quot;GitHub Pages&quot;, &quot;Netlify&quot;, et &quot;Cloudflare&quot;. Des néons bleutés et des motifs de code binaire flottent dans l’air, comme des étoiles filantes numériques.</p>
<p>En arrière-plan, une grande fenêtre donne sur un ciel étoilé, où des nuages en forme de code binaire reflètent la lumière des lanternes. Une tasse de thé fumant et des parchemins déroulés (symbolisant les logs de déploiement) sont posés sur un bureau en bois, à côté d’un petit robot endormi.</p>
<p>À droite, en bas, le panda roux est légèrement tourné en 3/4 dos, lové sur un coussin, entouré d’un halo lumineux subtil. Il ne dépasse pas le tiers de la hauteur de l’image et observe la scène avec satisfaction, comme s’il contemplait le voyage de son site vers le web.</p>
<p>L’ambiance est cosy, onirique et high-tech : les couleurs sont douces (beiges, bleus pâles, oranges chauds), avec des jeux de lumière tamisée qui créent des ombres chaleureuses. Les détails sont soignés, avec des textures visibles (grain du bois, tissu de la veste, pelage du panda roux), et une lumière qui met en valeur les éléments tech et artisanaux. Le tout respire la sérénité et l’inspiration, comme un moment suspendu entre la magie et la technologie.</p>
</blockquote>
]]></content:encoded>
      <dc:creator><![CDATA[Anthony Pena]]></dc:creator>
      <media:content medium="image" url="https://anthonypena.fr/img/cover.min.jpg"/>
    </item>
    <item>
      <title><![CDATA[Revue de presse - Fevrier 2026]]></title>
      <guid isPermaLink="false">2026/02/04/revue-de-presse-fevrier</guid>
      <description><![CDATA[<blockquote>
<p>Note : Si vous faites partie des gens qui ont vu cet article apparaitre dans leur flux RSS vide hi…</p>
</blockquote>
]]></description>
      <link>https://anthonypena.fr/2026/02/04/revue-de-presse-fevrier/index.html</link>
      <category><![CDATA[Revue de presse]]></category>
      <pubDate>Wed, 04 Feb 2026 07:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<blockquote>
<p>Note : Si vous faites partie des gens qui ont vu cet article apparaitre dans leur flux RSS vide hier : j&#39;en suis désolé, c&#39;est une erreur de ma part et qui a provoqué l&#39;autopublication de cet article avant que je l&#39;ai terminé…</p>
</blockquote>
<h2 id="article-frontend">Frontend<a href="#article-frontend" class="anchor" aria-label="permalink">🔗</a></h2>
<h3 id="article-its-hard-to-justify-tahoe-iconshttpstonskymeblogtahoeicons"><a href="https://tonsky.me/blog/tahoe-icons/">It’s hard to justify Tahoe icons</a><a href="#article-its-hard-to-justify-tahoe-iconshttpstonskymeblogtahoeicons" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#Apple #UI #UX #Frontend</p>
<p>Je cite directement la conclusion :</p>
<blockquote>
<p>In my opinion, Apple took on an impossible task: to add an icon to every menu item. There are just not enough good metaphors to do something like that.</p>
<p>But even if there were, the premise itself is questionable: if everything has an icon, it doesn’t mean users will find what they are looking for faster.</p>
<p>And even if the premise was solid, I still wish I could say: they did the best they could, given the goal. But that’s not true either: they did a poor job consistently applying the metaphors and designing the icons themselves.</p>
</blockquote>
<p>Franchement l&#39;article est super intéressant ! Et ce n&#39;est pas juste du Apple-baching : qu&#39;on aime ou pas Apple, force est de constater que des patterns de design et d&#39;UX très forts ont émergés chez Apple dès les années 80-90, conduisant à la rédaction du HIG (Human Interface Guideline) ; autant c&#39;est normal que certains trucs évoluent (vu que les pratiques évoluent aussi), mais il ne faut pas le faire n&#39;importe comment, il ne faut pas effacer le travail de recherche qui a été fait dans le passé.</p>
<p>C&#39;est exactement ce qui a été fait récemment chez Apple : on a forcé certains patterns sans forcément être cohérent avec ce que les humains sont capables de suivre / comprendre ou même ce qu&#39;ils attendent. Là l&#39;expemple des icônes est très parlant ! </p>
<p>Pour le coup ça amène à réfléchir sur tout type d&#39;UI, la cohérence, etc. </p>
<h3 id="article-textbased-web-browsershttpscssencecom2026textbasedwebbrowsers"><a href="https://cssence.com/2026/text-based-web-browsers/">Text-based web browsers</a><a href="#article-textbased-web-browsershttpscssencecom2026textbasedwebbrowsers" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#Frontend #Web #Navigateur #HTML</p>
<p>On a tendance côté frontend à être beaucoup trop habitué à des navigateurs ultra-modernes comme Firefox ou Chrome, mais il y a d&#39;autres navigateurs. Ils sont peu utilisés aujourd&#39;hui mais les navigateurs textuels sont super intéressants pour plein de raisons !</p>
<p>Personnellement j&#39;aime bien cet article, car il permet de rappeler à quel point le HTML est central, et au passage j&#39;ai découvert des choses que je n&#39;avais jamais croisées :</p>
<ul>
<li>qu&#39;il y a des problèmes d&#39;accessibilités au niveau des data lists… 🫠 ;</li>
<li>l&#39;API Invoker Commands qui permet de déclencher des actions qu&#39;on est censé pouvoir déclencher qu&#39;en JavaScript avec seulement du HTML déclaratif ;</li>
<li>l&#39;attribut <code>inert</code> qui permet de rendre inutilisable certaines parties du contenu ;</li>
</ul>
<p>C&#39;est toujours intéressant de creuser des technologies moins modernes, ça oblige à revenir sur ce qui est important !</p>
<h2 id="article-ia">IA<a href="#article-ia" class="anchor" aria-label="permalink">🔗</a></h2>
<h3 id="article-la-fabrique-a-idiots--micodehttpsyoutube4xq6bvbspw"><a href="https://youtu.be/4xq6bVbS-Pw">La Fabrique à Idiots — Micode</a><a href="#article-la-fabrique-a-idiots--micodehttpsyoutube4xq6bvbspw" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#LLM #IA</p>
<p><a href="https://youtu.be/4xq6bVbS-Pw"><img src="https://anthonypena.fr/2026/02/04/revue-de-presse-fevrier/img/youtube-4xq6bVbS-Pw.jpg" alt="https://youtu.be/4xq6bVbS-Pw" title="Youtube video preview"/></a></p>
<blockquote>
<p>Non l&#39;IA ne va pas nous rendre stupides. On va se rendre stupide tout seul en choisissant systématiquement le chemin le plus court.</p>
</blockquote>
<p>C&#39;est la phrase qui résume pour moi parfaitement cette vidéo.</p>
<p>Et je suis totalement d&#39;accord. L&#39;IA c&#39;est un outil. On commence à utiliser massivement l&#39;IA (enfin des LLMs, qui n&#39;ont absolument rien d&#39;intelligent, ce sont juste des boites noires qui vomissent du texte qui tient à peu près la route), en posant notre cerveau, en le laissant travailler, et on va y perdre très fort.</p>
<p>On est en train de vivre une révolution. Pas du genre de la révolution industrielle qui a conduit à réduire le nombre d&#39;ouvrier qui faisaient du travail à la chaise qui les détruisaient mais du genre qui vient couper la phase d&#39;apprentissage de notre vie. C&#39;est un phénomène qui est loin d&#39;être nouveau, c&#39;est ce qu&#39;on appelle le &quot;Google effect&quot;, le fait de ne plus mémoriser certaines informations car on peut les retrouver en une recherche Google (pourquoi notre cerveau retiendrait des centaines d&#39;infos qu&#39;il peut retrouver avec une seule action à connaître ?).</p>
<p>On peut forcer l&#39;IA à être pédagogique, on peut forcer l&#39;IA à aller dans le sens de nous faire progresser. Mais ce n&#39;est pas le réglage par défaut. Par défaut c&#39;est la facilité qui est choisi. Par défaut c&#39;est aller à un résultat pas aider à réfléchir.</p>
<p>Le chemin le plus court c&#39;est aller vers le résultat, ne rien apprendre, ne pas forcément  même comprendre, juste un &quot;ça marche&quot; qui va nous faire perdre des capacités mentales. Choisir le futur c&#39;est chercher par soi même, apprendre, comprendre, peut-être aussi utiliser l&#39;IA pour proposer d&#39;autres pistes, mais développer notre capacité mentale, et donc demain au lieu de repasser 20min à chercher ce sera 5min, et après-demain 1min parce qu&#39;on connaîtra la solution.</p>
<h3 id="article-hitex-press-a-spam-factory-for-aigenerated-bookshttpslaurentlebruneubloghitexaspamfactoryforaigeneratedbooks"><a href="https://laurent.le-brun.eu/blog/hitex-a-spam-factory-for-ai-generated-books">HiTeX Press: A spam factory for AI-generated books</a><a href="#article-hitex-press-a-spam-factory-for-aigenerated-bookshttpslaurentlebruneubloghitexaspamfactoryforaigeneratedbooks" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#IA #Ebook #Livre</p>
<p>À priori si vous voyez un livre / ebook venant de l&#39;éditeur HiTeX, vous pouvez considérer que c&#39;est du &quot;garbage AI&quot;.</p>
<p>Les auteurs semblent ne pas exister, les livres sont produits en masse, et l&#39;exemple sur lequel l&#39;auteur de l&#39;article se penche en particulier (car il concerne un langage qu&#39;il développe lui chez Google) est rempli de contenu faux jusqu&#39;à inventer une runtime qui n&#39;existe pas pour le langage…</p>
<p>Malheureusement, le contenu peut sembler valide de prime abord, particulièrement à un relecteur non-expert… La magie de l&#39;IA et c&#39;est pas fini…</p>
<h2 id="article-securite">Sécurité<a href="#article-securite" class="anchor" aria-label="permalink">🔗</a></h2>
<h3 id="article-cybersecurite--pourquoi-il-faut-toujours-demander-le-menu-au-restaurant--avec-des-experts---cyrus-northhttpsyoutubegek9umg6gp8"><a href="https://youtu.be/Gek9uMG6gp8">Cybersécurité : Pourquoi il faut toujours demander le menu au restaurant ? (avec des experts) —  Cyrus North</a><a href="#article-cybersecurite--pourquoi-il-faut-toujours-demander-le-menu-au-restaurant--avec-des-experts---cyrus-northhttpsyoutubegek9umg6gp8" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#Sécurité #Vie-privée</p>
<p><a href="https://youtu.be/Gek9uMG6gp8"><img src="https://anthonypena.fr/2026/02/04/revue-de-presse-fevrier/img/youtube-Gek9uMG6gp8.jpg" alt="https://youtu.be/Gek9uMG6gp8" title="Youtube video preview"/></a></p>
<p>Table ronde très intéressante sur ce que c&#39;est la cybersécurité.</p>
<p>C&#39;est très orienté grand public, mais il y a tous les sujets de fonds qui sont abordés, tous les sujets importants, avec pas mal de notions importantes :</p>
<ul>
<li>c&#39;est quoi une attaque de masse / une attaque ciblé ?</li>
<li>est-ce qu&#39;on est une cible potentielle ?</li>
<li>comment on se protège ?</li>
<li>à quoi sert à gestionnaire de mot de passe ?</li>
<li>c&#39;est quoi le danger des pubs / trackers ?</li>
<li>comment on protège son identité ? et pourquoi ? et contre quoi ?</li>
<li>etc.</li>
</ul>
<p>Clairement, ça vaut le coup !</p>
<h3 id="article-creepylinkhttpscreepylinkcom"><a href="https://creepylink.com/">CreepyLink</a><a href="#article-creepylinkhttpscreepylinkcom" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#Sécurité</p>
<p>Meilleur outil pour faire peur aux personnes qui gèrent la sécurité : un outil qui va créer une version &quot;effrayante&quot; de votre lien.</p>
<p>Par exemple :</p>
<p>J&#39;ai donné à l&#39;outil &quot;<a href="https://press.k49.fr.nf/">https://press.k49.fr.nf/</a>&quot; et il m&#39;a donné &quot;<a href="https://verify.ic6do.com/z6K89n_video_player_update.exe">https://verify.ic6do.com/z6K89n_video_player_update.exe</a>&quot;. Ça pourrait trigger pas mal de système pour le coup.</p>
<p>Est-ce que c&#39;est utile ? Nope… Est-ce que ça peut être drôle ? OUI ! 😈</p>
<h3 id="article-microsoft-gave-fbi-bitlocker-encryption-keys-exposing-privacy-flawhttpssebsauvagenetlinksxhroiq"><a href="https://sebsauvage.net/links/?XhRoIQ">Microsoft Gave FBI BitLocker Encryption Keys, Exposing Privacy Flaw</a><a href="#article-microsoft-gave-fbi-bitlocker-encryption-keys-exposing-privacy-flawhttpssebsauvagenetlinksxhroiq" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#Microsoft #Sécurité #Windows</p>
<p>Je cite sebsauvage :</p>
<blockquote>
<p>Microsoft : &quot;Ah non on ne peut pas lire votre disque dur quand il est chiffré avec BitLocker !&quot;
Also Microsoft : Donne au FBI des clés BitLocker qu&#39;il a stockées.</p>
<p>(Sous Linux quand vous chiffrez votre disque avec LUKS, il n&#39;y a que VOUS qui pouvez lire le disque. Un point c&#39;est tout. Je dis ça, je dis rien.)</p>
</blockquote>
<p>Mais évidemment quand y&#39;a quelques années je disais que c&#39;était un problème que Microsoft garde une copie des clés Bitlocker, on me disait que j&#39;exagerais à l&#39;époque… </p>
<h2 id="article-jeuxvideos">Jeux-videos<a href="#article-jeuxvideos" class="anchor" aria-label="permalink">🔗</a></h2>
<h3 id="article-ce-jeu-steam-devient-injouable-parce-que-les-jeunes-ne-savent-plus-envoyer-un-mailhttpswwwphonandroidcomcejeusteamdevientinjouableparcequelesjeunesnesaventplusenvoyerunmailhtml"><a href="https://www.phonandroid.com/ce-jeu-steam-devient-injouable-parce-que-les-jeunes-ne-savent-plus-envoyer-un-mail.html">Ce jeu Steam devient injouable parce que les jeunes ne savent plus envoyer un mail</a><a href="#article-ce-jeu-steam-devient-injouable-parce-que-les-jeunes-ne-savent-plus-envoyer-un-mailhttpswwwphonandroidcomcejeusteamdevientinjouableparcequelesjeunesnesaventplusenvoyerunmailhtml" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#Steam #Jeux-videos #E-mail</p>
<blockquote>
<p>Dans une interview donnée à nos confrères de Polygon, le développeur Petter Malmehed explique que son jeu devient injouable pour une partie de son public. Son titre, After Hours, repose sur un concept original : les joueurs doivent résoudre une série d’énigmes dans un environnement inspiré des vieux ordinateurs. À un moment clé, ceux-ci doivent envoyer un vrai email pour recevoir un indice. Mais de plus en plus de jeunes échouent à cette étape pourtant banale.</p>
</blockquote>
<p>J&#39;ai envie de dire : Oups 🤦‍♂️ </p>
<p>Bon bah faut dire que les nouvelles générations ont sans doute beaucoup plus utilisé de messagerie instantanée que de mail </p>
<h2 id="article-divers">Divers<a href="#article-divers" class="anchor" aria-label="permalink">🔗</a></h2>
<h3 id="article-shhp--the80srobothttpsgithubcomthe80srobotshhp"><a href="https://github.com/the80srobot/shhp">shhp — the80srobot</a><a href="#article-shhp--the80srobothttpsgithubcomthe80srobotshhp" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#Shell #Linux</p>
<blockquote>
<p>This script gives your shell hitpoints. You start with 3 hp. Every time you run a command that fails, you take damage. If you run out of hp, the shell exits.</p>
</blockquote>
<p>Ça motive à réfléchir à ce qu&#39;on tape comme commande au moins 😂</p>
<p>En vrai l&#39;idée est marrante et je pense qu&#39;on pourrait en fait quelque chose de presque utile !</p>
<h3 id="article-microquickjshttpsgithubcombellardmquickjstabreadmeovfile"><a href="https://github.com/bellard/mquickjs?tab%3Dreadme-ov-file">MicroQuickJS</a><a href="#article-microquickjshttpsgithubcombellardmquickjstabreadmeovfile" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#JavaScript</p>
<p>Moteur JavaScript pour l&#39;embarqué (100 kB of ROM, 10 kB of RAM). écrit en C et supportant un subset de JavaScript es5.</p>
<p>Ce moteur aussi être exécuté sur desktop, donc c&#39;est une option qui pourrait être utile pour un moteur d&#39;extension ou pour du paramétrage.</p>
<p>Je trouve ça intéressant de voir fleurir des moteurs comme ça !</p>
<p>Crédit photo : Générée via Mistral AI avec le prompt suivant : </p>
<blockquote>
<p>Une scène chaleureuse et immersive, inspirée par l’esthétique poétique de Studio Ghibli, représentant un bureau de travail en bois clair et vieilli, baigné d’une lumière dorée et tamisée, comme un après-midi d’automne. Au centre, une silhouette stylisée (style anime Ghibli : traits doux, visage non détaillé, vêtements amples et confortables) est assise en tailleur sur un tapis épais, absorbée par la lecture d’un journal tech futuriste. Le journal est ouvert, ses pages légèrement froissées, avec des titres en en-tête calligraphiés à la main : &quot;Frontend&quot;, &quot;Backend&quot;, &quot;IA&quot;, &quot;Sécurité&quot;, et &quot;Vie privée&quot;. Les pages brillent d’un halo bleu pâle, évoquant des lignes de code et des schémas techniques qui s’animent discrètement, comme par magie.
Autour d’elle, des piles de magazines et de carnets s’empilent de manière désordonnée mais harmonieuse. Certains sont ouverts, révélant des extraits d’articles, des croquis de frameworks (représentés par des icônes génériques : un crochet pour le frontend, un engrenage pour le backend, un cerveau pour l’IA, un cadenas pour la sécurité, et un masque pour la vie privée), ou des diagrammes de réseaux de neurones dessinés à la main. Un écran transparent et flottant (style holographique, mais avec un cadre en bois sculpté) affiche des flux d’informations en temps réel : des graphiques de données, des alertes de sécurité, et des extraits de code, le tout dans un style doux et organique, comme intégré à la scène.
En arrière-plan, une grande fenêtre donne sur un paysage urbain nocturne style Ghibli : des bâtiments aux formes arrondies, des lanternes suspendues, et des néons bleutés qui reflètent des motifs de code binaire sur les murs. Une tasse de thé fumant et un petit robot de bureau (inspiré des créatures de Ghibli, comme un mélange entre un Totoro miniature et un assistant tech) observent la scène avec curiosité.
À droite, un panda roux (ton animal préféré) est lové sur un coussin, les yeux mi-clos, comme s’il écoutait attentivement. Il ne doit pas dépasser le tiers de la hauteur de l’image et est positionné en bas à droite, légèrement tourné vers le centre, avec une queue soyeuse enroulée autour de lui.
L’ambiance est à la fois cosy, onirique et high-tech : les couleurs sont douces (beiges, bleus pâles, oranges chauds), avec des contrastes subtils pour mettre en valeur les éléments tech. Les détails sont soignés, avec des textures visibles (grain du bois, tissu du tapis, pelage du panda), et une lumière qui crée des jeux d’ombres chaleureuses. Le tout respire la sérénité et l’inspiration, comme un moment suspendu entre la magie et la technologie.</p>
</blockquote>
]]></content:encoded>
      <dc:creator><![CDATA[Anthony Pena]]></dc:creator>
      <media:content medium="image" url="https://anthonypena.fr/img/cover.min.jpg"/>
    </item>
    <item>
      <title><![CDATA[Nouveau blog -- partie 3 : JavaScript]]></title>
      <guid isPermaLink="false">2026/01/27/nouveau-blog-partie-3-js</guid>
      <description><![CDATA[<p>Dans la première partie je parlais du contenu en HTML, dans la seconde des outils CSS que j&#39;ai utili…</p>
]]></description>
      <link>https://anthonypena.fr/2026/01/27/nouveau-blog-partie-3-js/index.html</link>
      <category><![CDATA[Web]]></category>
      <category><![CDATA[Frontend]]></category>
      <pubDate>Tue, 27 Jan 2026 07:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>Dans la première partie je parlais du contenu en HTML, dans la seconde des outils CSS que j&#39;ai utilisés pour vous présenter le contenu plus proprement, que reste-t-il à présenter ?</p>
<p>Vous êtes en train de lire un blog généré statiquement, il y a assez peu d&#39;interaction possible à part des liens (logique pour un blog au fond), donc que manque-t-il ? Techniquement rien. En vrai j&#39;aurai pu m&#39;arrêter là, mais j&#39;ai ajouté une fonctionnalité de zoom sur deux parties des articles : les images et les galeries d&#39;images, et pour que ça fonctionne bien j&#39;ai été obligé d&#39;ajouter du JavaScript.</p>
<nav data-serie="nouveau-blog-marked-deno">
<h2>Série d'article</h2>
<ul>
<li><a href="https://anthonypena.fr/2026/01/15/nouveau-blog-partie-1-html/index.html">Nouveau blog -- partie 1 : HTML</a></li>
<li><a href="https://anthonypena.fr/2026/01/21/nouveau-blog-partie-2-css/index.html">Nouveau blog -- partie 2 : CSS</a></li>
<li><a href="https://anthonypena.fr/2026/01/27/nouveau-blog-partie-3-js/index.html">Nouveau blog -- partie 3 : JavaScript</a></li>
<li><a href="https://anthonypena.fr/2026/02/10/nouveau-blog-partie-4-et-le-reste/index.html">Nouveau blog --  partie 4 : et le reste...</a></li>
</ul>
</nav>
<h2 id="article-sans-javascript">Sans JavaScript<a href="#article-sans-javascript" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Pour moi c&#39;était important que tout fonctionne sans JavaScript. Je suis peut-être vieux jeux sur ce coup-là, mais j&#39;estime que si vous arrivez avec un grille-pain avec un navigateur textuel vous devriez pouvoir lire mon blog (si vous lisez ce blog sur un grille-pain via un navigateur textuel : envoyez-moi une photo, ça me fera un kiff de ouf !).</p>
<p>Donc voyons ce que ça donne sans JavaScript :</p>
<figure>
<img src="https://anthonypena.fr/2026/01/27/nouveau-blog-partie-3-js/img/no-js.gif" alt="Vue d&#39;un article sans JavaScript" is="img-zoom"/>
<figcaption>Vue d&#39;un article sans JavaScript</figcaption>
</figure>
<p>À priori rien de particulier à signaler. Mais si maintenant on ajoute le JavaScript ?</p>
<figure>
<img src="https://anthonypena.fr/2026/01/27/nouveau-blog-partie-3-js/img/with-js.gif" alt="Vue d&#39;un article avec du JavaScript" is="img-zoom"/>
<figcaption>Vue d&#39;un article avec du JavaScript</figcaption>
</figure>
<p>Vous noterez le changement de curseur au survol d&#39;une image pour indiquer qu&#39;on peut cliquer, au clic le zoom pour passer l&#39;image en plein écran. Pareil pour les galeries mais en plus l&#39;option de pouvoir défiler les images de la galerie en cours.</p>
<p>L&#39;amélioration est petite (mais indispensable pour certains articles à mon sens), mais elle est là. Et je l&#39;ai fait sans aucune librairie externe, avec deux Web Components très simple.</p>
<h2 id="article-web-component--kezako-">Web Component ? kézako ?<a href="#article-web-component--kezako-" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Un Web Component c&#39;est simplement le nom qu&#39;on donne à une brique JavaScript qui est composé d&#39;un Custom Element, de Shadow DOM et des éléments <code>&lt;template&gt;</code> et <code>&lt;slot&gt;</code>.</p>
<p>C&#39;est assez réducteur comme définition à mon sens, j&#39;ai par exemple bien créé deux Web Component mais en utilisé aucune des briques cités, mais c&#39;est généralement comme ça qu&#39;on crée un Web Component.</p>
<p>Mais restons sur la définition de base :</p>
<pre><code class="hljs language-JavaScript"><span class="hljs-keyword">class</span> <span class="hljs-title class_">BlogIcon</span> <span class="hljs-keyword">extends</span> <span class="hljs-title class_ inherited__">HTMLElement</span> {
    <span class="hljs-title function_">constructor</span>(<span class="hljs-params"></span>) {
        <span class="hljs-variable language_">super</span>();
        <span class="hljs-variable language_">this</span>.<span class="hljs-property">innerHTML</span> = <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">getAttribute</span>(<span class="hljs-string">&#x27;icon&#x27;</span>) + <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">getAttribute</span>(<span class="hljs-string">&#x27;icon&#x27;</span>);
    }
}
customElements.<span class="hljs-title function_">define</span>(<span class="hljs-string">&#x27;blog-icon&#x27;</span>, <span class="hljs-title class_">BlogIcon</span>);<div aria-hidden="true" class="language-tag">JavaScript</div>
</code></pre><p>Et à l&#39;usage :</p>
<pre><code class="hljs language-HTML"><span class="hljs-tag">&lt;<span class="hljs-name">blog-icon</span> <span class="hljs-attr">icon</span>=<span class="hljs-string">&quot;🖌️&quot;</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">blog-icon</span>&gt;</span><div aria-hidden="true" class="language-tag">HTML</div>
</code></pre><p>C&#39;est pas très utile mais ça donne une idée simple de comment tout s&#39;articule. On crée une classe qui étend <code>HTMLElement</code> (ou n&#39;importe quel autre élément, par exemple <code>HTMLParagraphElement</code> pour créer un paragraphe personnalisé), on lui ajoute un constructeur qui appelle le constructeur parent, puis on agit (l&#39;idéal serait de passer par les <a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks">lifecycles</a> mais ce n&#39;est pas obligatoire), ici je vais afficher dans le composant le paramètre deux fois.</p>
<p>Une fois la classe créée il faut indiquer cette classe comme étant un Web Component au navigateur en passant par <code>customElements.define(&#39;nom-du-composant&#39;, ClassDuComposant);</code>.</p>
<p>Pour l&#39;utiliser on va ensuite ajouter l&#39;élément personnalisé qu&#39;on a choisi (un custom element ne peut pas être self-closed, donc <code>&lt;blog-icon icon=&quot;🖌️&quot;/&gt;</code> aurait été invalide).</p>
<blockquote>
<p>Note: vous <strong>devez</strong> avoir un nom de composant en 2 parties avec un <code>-</code> sinon vous aurez l&#39;erreur <code>DOMException: CustomElementRegistry.define: &#39;blogicon&#39; is not a valid custom element name</code> au moment de la déclaration. En général c&#39;est une bonne pratique d&#39;avoir un préfixe pour notre application. Pour mon exemple le préfixe serait <code>blog-</code>.</p>
</blockquote>
<p>Simple non ?</p>
<p>Là j&#39;ai fait un Web Component sans shadowDOM mais le ShadowDOM permet d&#39;avoir un cloisonnement du style pour éviter d&#39;avoir à s&#39;occuper du reste du style de page et d&#39;éventuel conflit. C&#39;est une bonne pratique d&#39;utiliser du ShadowDOM, particulièrement si votre objectif c&#39;est de partager le composant.</p>
<h2 id="article-composant-de-zoom-dimage">Composant de zoom d&#39;image<a href="#article-composant-de-zoom-dimage" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Bon maintenant qu&#39;on sait faire un Web Component, on veut faire la même chose, mais sans custom element (en gardant juste la balise <code>&lt;img /&gt;</code>), sans changer le comportement de base, juste &quot;améliorer&quot; le comportement de la balise <code>&lt;img/&gt;</code> pour ne pas avoir à attendre que le JS se charge pour avoir les images (comme toujours : progressive enhancement, pas de JS obligatoire, etc.).</p>
<p>Pas de ShadowDOM non plus parce que je ne veux pas avoir un style appliqué plusieurs fois sur la page, un style global ça me va bien (mais appliqué seulement si on charge de Web Component).</p>
<p>Donc comment on fait ?</p>
<p>Déjà, on va utiliser les options de <code>customElements.define()</code> :</p>
<pre><code class="hljs language-JavaScript">customElements.<span class="hljs-title function_">define</span>(<span class="hljs-string">&quot;img-zoom&quot;</span>, <span class="hljs-title class_">ImageZoom</span>, { <span class="hljs-attr">extends</span>: <span class="hljs-string">&quot;img&quot;</span> });<div aria-hidden="true" class="language-tag">JavaScript</div>
</code></pre><p>Ici on dit au navigateur que notre composant ne va pas s&#39;appliquer sur <code>&lt;img-zoom&gt;&lt;/img-zoom&gt;</code> mais sur <code>&lt;img is=&quot;img-zoom&quot; /&gt;</code>. Du coup, il faut aussi changer le HTML pour que nos images aient l&#39;attribut <code>is=&quot;img-zoom&quot;</code>.</p>
<p>Comme je voulais quelque chose de propre et éviter d&#39;ajouter du JavaScript pour rien, j&#39;ai choisi de le faire via mon plugin Marked en ouvrant la possibilité d&#39;ajouter un paramètre <code>is</code>, donc il suffit d&#39;ajouter le plugin avec le bon paramètre <code>markedBetterImage({ is: &quot;img-zoom&quot; })</code>, c&#39;est particulièrement intéressant que ça permet de ne cibler que les images qui ne sont pas dans des galeries d&#39;images. Pour les galeries je vais fonctionner de la même façon mais avec le plugin <code>markedImageGallery({ is: &quot;gallery-zoom&quot; })</code>.</p>
<p>On passe donc de :</p>
<pre><code class="hljs language-HTML"><span class="hljs-tag">&lt;<span class="hljs-name">figure</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">&quot;./img/print_1.min.jpg&quot;</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">&quot;Des jetons&quot;</span>/&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">figcaption</span>&gt;</span>Des jetons<span class="hljs-tag">&lt;/<span class="hljs-name">figcaption</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">figure</span>&gt;</span><div aria-hidden="true" class="language-tag">HTML</div>
</code></pre><p>à </p>
<pre><code class="hljs language-HTML"><span class="hljs-tag">&lt;<span class="hljs-name">figure</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">&quot;./img/print_1.min.jpg&quot;</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">&quot;Des jetons&quot;</span> <span class="hljs-attr">is</span>=<span class="hljs-string">&quot;img-zoom&quot;</span>/&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">figcaption</span>&gt;</span>Des jetons<span class="hljs-tag">&lt;/<span class="hljs-name">figcaption</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">figure</span>&gt;</span><div aria-hidden="true" class="language-tag">HTML</div>
</code></pre><p>Donc presque pas de différence dans le HTML mais beaucoup d&#39;options possibles derrière !</p>
<p>La classe <code>ImageZoom</code> est finalement assez simple :</p>
<pre><code class="hljs language-JavaScript"><span class="hljs-keyword">class</span> <span class="hljs-title class_">ImageZoom</span> <span class="hljs-keyword">extends</span> <span class="hljs-title class_ inherited__">HTMLImageElement</span> {
  <span class="hljs-title function_">constructor</span>(<span class="hljs-params"></span>) {
    <span class="hljs-variable language_">super</span>();
    <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">addEventListener</span>(<span class="hljs-string">&quot;click&quot;</span>, <span class="hljs-function">() =&gt;</span> {
      <span class="hljs-variable language_">this</span>.<span class="hljs-property">zoomIn</span> = !<span class="hljs-variable language_">this</span>.<span class="hljs-property">zoomIn</span>;
    });
  }

  <span class="hljs-keyword">get</span> <span class="hljs-title function_">zoomIn</span>() {
    <span class="hljs-keyword">return</span> <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">getAttribute</span>(<span class="hljs-string">&quot;data-zoom&quot;</span>) === <span class="hljs-string">&quot;zoom&quot;</span>;
  }

  <span class="hljs-keyword">set</span> <span class="hljs-title function_">zoomIn</span>(<span class="hljs-params">flag</span>) {
    <span class="hljs-keyword">if</span> (flag) {
      <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">setAttribute</span>(<span class="hljs-string">&quot;data-zoom&quot;</span>, <span class="hljs-string">&quot;zoom&quot;</span>);
    } <span class="hljs-keyword">else</span> {
      <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">removeAttribute</span>(<span class="hljs-string">&quot;data-zoom&quot;</span>);
    }
  }
}<div aria-hidden="true" class="language-tag">JavaScript</div>
</code></pre><p>L&#39;idée étant juste d&#39;ajouter ou enlever l&#39;attribut <code>data-zoom</code> (en lui passant la valeur <code>zoom</code> dans le doute d&#39;avoir besoin d&#39;une autre valeur un jour) en fonction de si on zoom ou dé-zoom.</p>
<p>Et du coup comment ça marche ? Du CSS tout simplement !</p>
<p>Dans le même fichier que mon Web Component j&#39;ai ça :</p>
<pre><code class="hljs language-JavaScript"><span class="hljs-keyword">const</span> style = <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">createElement</span>(<span class="hljs-string">&quot;style&quot;</span>);
style.<span class="hljs-property">textContent</span> = <span class="hljs-string">`
    @media (width &gt;= 700px) {
        img[is=&quot;img-zoom&quot;] {
            cursor: zoom-in;
            
            &amp;[data-zoom=zoom] {
                cursor: zoom-out;
                background-color: var(--color--bg);
                position: fixed;
                padding: var(--size--1);
                margin: auto;
                inset: 0;
                object-fit: contain;
                width: 100%;
                min-width: unset;
                max-width: 100%;
                height: 100%;
                min-height: unset;
                max-height: 100%;
                z-index: 10000;
            }
        }
    }
`</span>;

<span class="hljs-variable language_">document</span>.<span class="hljs-property">body</span>.<span class="hljs-title function_">appendChild</span>(style);<div aria-hidden="true" class="language-tag">JavaScript</div>
</code></pre><p>Uniquement sur un grand écran (supérieur à 700px, comme pour le seul break-point que j&#39;ai dans mon style), si une balise <code>&lt;img/&gt;</code> a l&#39;attribut <code>is=&quot;img-zoom&quot;</code> alors je change le curseur, et si en plus on retrouve l&#39;attribut <code>data-zoom=&quot;zoom&quot;</code> alors je change à nouveau le curseur et je change la position et taille de l&#39;image pour qu&#39;elle prenne le maximum possible de taille de l&#39;écran.</p>
<p>C&#39;est finalement assez simple à faire, j&#39;ai surtout joué avec le style pour que tout fonctionne.</p>
<p>Pour la galerie, c&#39;est pratiquement la même chose mais en ajoutant des boutons supplémentaires, en ajoutant du style pour positionner un peu tout, en ajoutant un peu de mécanique pour appliquer l&#39;attribut <code>data-zoom=&quot;zoom&quot;</code> sur une seule image et qu&#39;on puisse déplacer l&#39;attribut d&#39;image en image. C&#39;est plus long mais pas tellement plus compliqué. Si vous êtes curieux, je vous laisse inspecter le script <code>gallery-zoom.mjs</code> qui se charge sur cette page.</p>
<h2 id="article-conclusion">Conclusion<a href="#article-conclusion" class="anchor" aria-label="permalink">🔗</a></h2>
<p>C&#39;est clairement la partie la plus courte de toute la série. J&#39;aurais pu mettre du JavaScript partout, faire des animations / interactions de fou ! Mais ça n&#39;aurait pas été nécessaire…</p>
<p>J&#39;ai fait quelque chose de simple. Ça me va parfaitement. J&#39;aurai surement d&#39;autres Web Components à ajouter pour quelques petites idées mais pas beaucoup non plus. Je reste sur l&#39;idée que la page de mes articles doit se charger vite !</p>
<p>Crédit photo : Générée via Mistral AI avec le prompt suivant : </p>
<blockquote>
<p>Une scène chaleureuse et immersive, inspirée par l’esthétique poétique de Studio Ghibli, représentant un laboratoire d’alchimie numérique en bois clair et vieilli, baigné d’une lumière dorée et bleutée tamisée, comme un crépuscule d’automne. Au centre, un panda roux anthropomorphe (Firefox), vêtu d’une blouse d’alchimiste ample et texturée, mélange des fioles remplies de lignes de code JavaScript qui s’illuminent de reflets dorés et bleutés. Les fioles sont disposées sur une table en bois couverte de schémas techniques dessinés à la main et de parchemins affichant des extraits de code. </p>
<p>Des bulles de code flottent autour de lui, s’animant et interagissant avec des éléments HTML/CSS stylisés, comme des particules magiques. Des écrans holographiques (avec des cadres en bois sculpté) affichent des animations discrètes : un bouton qui réagit au survol, une liste qui se trie dynamiquement, ou un graphique qui se met à jour en temps réel. </p>
<p>En arrière-plan, une grande fenêtre donne sur un paysage nocturne aux étoiles filantes et aux néons bleutés, reflétant des motifs de code binaire sur les murs en bois. Des feuilles d’érable flottent doucement dans l’air, ajoutant une touche magique à la scène. </p>
<p>À droite, en bas, le panda roux est légèrement tourné en 3/4 dos, lové sur un coussin, entouré d’un halo lumineux subtil. Il ne dépasse pas le tiers de la hauteur de l’image et observe ses expériences avec curiosité et satisfaction. </p>
<p>L’ambiance est cosy, onirique et high-tech : les couleurs sont douces (beiges, bleus pâles, oranges chauds), avec des jeux de lumière tamisée qui créent des ombres chaleureuses. Les détails sont soignés, avec des textures visibles (grain du bois, tissu de la blouse, pelage du panda roux), et une tasse de thé fumant posée près des fioles. Le tout respire la sérénité et l’inspiration, comme un moment suspendu entre la magie et la technologie.&quot;&quot;Une scène chaleureuse et immersive, inspirée par l’esthétique poétique de Studio Ghibli, représentant un laboratoire d’alchimie numérique en bois clair et vieilli, baigné d’une lumière dorée et bleutée tamisée, comme un crépuscule d’automne. Au centre, un panda roux anthropomorphe (Firefox), vêtu d’une blouse d’alchimiste ample et texturée, mélange des fioles remplies de lignes de code JavaScript qui s’illuminent de reflets dorés et bleutés. Les fioles sont disposées sur une table en bois couverte de schémas techniques dessinés à la main et de parchemins affichant des extraits de code. </p>
<p>Des bulles de code flottent autour de lui, s’animant et interagissant avec des éléments HTML/CSS stylisés, comme des particules magiques. Des écrans holographiques (avec des cadres en bois sculpté) affichent des animations discrètes : un bouton qui réagit au survol, une liste qui se trie dynamiquement, ou un graphique qui se met à jour en temps réel. </p>
<p>En arrière-plan, une grande fenêtre donne sur un paysage nocturne aux étoiles filantes et aux néons bleutés, reflétant des motifs de code binaire sur les murs en bois. Des feuilles d’érable flottent doucement dans l’air, ajoutant une touche magique à la scène. </p>
<p>À droite, en bas, le panda roux est légèrement tourné en 3/4 dos, lové sur un coussin, entouré d’un halo lumineux subtil. Il ne dépasse pas le tiers de la hauteur de l’image et observe ses expériences avec curiosité et satisfaction. </p>
<p>L’ambiance est cosy, onirique et high-tech : les couleurs sont douces (beiges, bleus pâles, oranges chauds), avec des jeux de lumière tamisée qui créent des ombres chaleureuses. Les détails sont soignés, avec des textures visibles (grain du bois, tissu de la blouse, pelage du panda roux), et une tasse de thé fumant posée près des fioles. Le tout respire la sérénité et l’inspiration, comme un moment suspendu entre la magie et la technologie.</p>
</blockquote>
]]></content:encoded>
      <dc:creator><![CDATA[Anthony Pena]]></dc:creator>
      <media:content medium="image" url="https://anthonypena.fr/img/cover.min.jpg"/>
    </item>
    <item>
      <title><![CDATA[Nouveau blog -- partie 2 : CSS]]></title>
      <guid isPermaLink="false">2026/01/21/nouveau-blog-partie-2-css</guid>
      <description><![CDATA[<p>Si la première partie traitait de HTML, si vous m&#39;avez suivi la seconde partie traite de CSS !</p>
]]></description>
      <link>https://anthonypena.fr/2026/01/21/nouveau-blog-partie-2-css/index.html</link>
      <category><![CDATA[Web]]></category>
      <category><![CDATA[Frontend]]></category>
      <pubDate>Wed, 21 Jan 2026 07:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>Si la première partie traitait de HTML, si vous m&#39;avez suivi la seconde partie traite de CSS !</p>
<p>Je me doute que vous A-DO-REZ CSS de tout votre être ! 🥸 Et pourtant !</p>
<p>Je ne me dirais jamais ultra top expert CSS, mais je sais faire du CSS, je sais faire dès trucs que je trouve assez propre avec peu de ligne de CSS, en comprenant ce que je fais et en faisant majoritairement du HTML sémantique et avec peu de classe ! Mais c&#39;est vrai que CSS demande un apprentissage qui peut être frustrant… Mais passons…</p>
<p>Je vous montre quelques trucs que j&#39;ai faits qui sont à mon sens trop peu utilisé !</p>
<nav data-serie="nouveau-blog-marked-deno">
<h2>Série d'article</h2>
<ul>
<li><a href="https://anthonypena.fr/2026/01/15/nouveau-blog-partie-1-html/index.html">Nouveau blog -- partie 1 : HTML</a></li>
<li><a href="https://anthonypena.fr/2026/01/21/nouveau-blog-partie-2-css/index.html">Nouveau blog -- partie 2 : CSS</a></li>
<li><a href="https://anthonypena.fr/2026/01/27/nouveau-blog-partie-3-js/index.html">Nouveau blog -- partie 3 : JavaScript</a></li>
<li><a href="https://anthonypena.fr/2026/02/10/nouveau-blog-partie-4-et-le-reste/index.html">Nouveau blog --  partie 4 : et le reste...</a></li>
</ul>
</nav>
<h2 id="article-html-semantique">HTML Sémantique<a href="#article-html-semantique" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Ce point rentrait presque plus dans la première partie mais je trouve que ça a plus d&#39;impact au niveau du CSS au final : j&#39;ai essayé au maximum de faire du HTML Sémantique. C&#39;est à dire éviter au maximum les <code>&lt;span&gt;</code> et <code>&lt;div&gt;</code>.</p>
<p>Pour vous donner une idée, j&#39;ai une seule balise <code>&lt;div&gt;</code> par page comme celle que vous lisez, et une balise <code>&lt;span&gt;</code> par tag mis sur l&#39;article parce que je n&#39;ai pas trouvé de meilleure balise pour représenter ça. Sinon j&#39;utilise par exemples des conteneurs <code>&lt;section&gt;</code> qui indique clairement aux lecteurs d&#39;écrans que j&#39;ai des blocs logiques dans ma page (j&#39;en ai 3 dans chaque page actuellement), ou simplement <code>&lt;article&gt;</code> / <code>&lt;header&gt;</code> / <code>&lt;main&gt;</code> / <code>&lt;footer&gt;</code> qui ont des sémantiques très clairement définies.</p>
<p>Globalement j&#39;ai finalement assez peu de balise superflue où présente uniquement pour le style. J&#39;ai aussi assez peu de classe, car la plupart du temps je n&#39;en ai pas besoin pour cibler des éléments, en tout cas clairement je n&#39;ai pas de classe sur chaque élément. L&#39;idée derrière c&#39;est que mon HTML est plutôt clean en lui-même et reste très lisible même par un humain.</p>
<p>Par contre ça implique que j&#39;ai des fichiers de styles bien pensées et qui viennent tout gérer en CSS moderne. Je précise moderne, car c&#39;est vrai que c&#39;est devenu plus facile aujourd&#39;hui de faire du HTML sémantique avec un style reposant peu sur des <code>&lt;div&gt;</code> et des classes, là où il y a une dizaine d&#39;années c&#39;était presque impossible… Mais on est en 2026, il faut utiliser ce que nous offre le navigateur au maximum pour travailler le moins possible, car c&#39;est plus accessible et plus performant !</p>
<h2 id="article-css-reset">CSS Reset<a href="#article-css-reset" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Pour moi la première chose à faire c&#39;est mettre en place un ensemble de &quot;reset&quot;. L&#39;idée c&#39;est de forcer de base un certain style/comportement de base qui va permettre de travailler confortablement.</p>
<p>Le mien est assez court, et comprend :</p>
<pre><code class="hljs language-CSS">*,
*<span class="hljs-selector-pseudo">::before</span>,
*<span class="hljs-selector-pseudo">::after</span> {
    <span class="hljs-attribute">box-sizing</span>: border-box;
}<div aria-hidden="true" class="language-tag">CSS</div>
</code></pre><p>Pour s&#39;assurer de fonctionner de base partout en <code>border-box</code>, c&#39;est à dire que la bordure d&#39;un élément fait partie intégrante de la taille de l&#39;élément. Donc si je définis un élément avec une largeur de 100px et une bordure de 2px, mon élément mesurera 100px de largeur. Par défaut (<code>content-box</code>), mon élément mesurerait 104px de largeur.</p>
<p>Je trouve ça plus naturel dans la majorité des cas, mais dans certains cas je sais que je peux passer en <code>content-box</code> si c&#39;est plus simple pour moi.</p>
<pre><code class="hljs language-CSS"><span class="hljs-selector-tag">body</span> {
    <span class="hljs-attribute">margin</span>: unset;
}<div aria-hidden="true" class="language-tag">CSS</div>
</code></pre><p>Pour s&#39;assurer que le body de la page n&#39;a aucune marge, et donc que peu importe le layout qu&#39;on choisira de mettre en place il prendra toute la place à l&#39;écran. À une époque je mettais <code>html, body { ... }</code> pour éviter d&#39;éventuelle marge sur l&#39;élément <code>&lt;html&gt;</code> aussi (parce que oui on trouvait parfois de la marge ici aussi, sous d&#39;ailleurs quand on utilisait un framework CSS ce qui n&#39;est pas mon cas sur le blog).</p>
<pre><code class="hljs language-CSS"><span class="hljs-selector-tag">button</span>,
<span class="hljs-selector-tag">input</span>,
<span class="hljs-selector-tag">textarea</span>,
<span class="hljs-selector-tag">select</span> {
    <span class="hljs-attribute">font</span>: inherit;
}<div aria-hidden="true" class="language-tag">CSS</div>
</code></pre><p>Pour s&#39;assurer qu&#39;on a bien la même police d&#39;écriture partout, car parfois les <code>&lt;bouton&gt;</code>, <code>&lt;input&gt;</code>, <code>&lt;textarea&gt;</code> et <code>&lt;select&gt;</code> utilise une autre police et ça complique le style.</p>
<pre><code class="hljs language-CSS"><span class="hljs-selector-tag">img</span>,
<span class="hljs-selector-tag">picture</span>,
<span class="hljs-selector-tag">svg</span>,
<span class="hljs-selector-tag">canvas</span> {
    <span class="hljs-attribute">display</span>: block;
    <span class="hljs-attribute">max-inline-size</span>: <span class="hljs-number">100%</span>;
    <span class="hljs-attribute">block-size</span>: auto;
}<div aria-hidden="true" class="language-tag">CSS</div>
</code></pre><p>Pour les images et canvas soient affichés comme des éléments <code>block</code> (et non <code>inline</code> comme par défaut) pour facilité le style (dimensions et position surtout).</p>
<pre><code class="hljs language-CSS"><span class="hljs-keyword">@media</span> (<span class="hljs-attribute">prefers-reduced-motion</span>: reduce) {
    *,
    *<span class="hljs-selector-pseudo">::before</span>,
    *<span class="hljs-selector-pseudo">::after</span> {
        <span class="hljs-attribute">animation-duration</span>: <span class="hljs-number">0.01ms</span> <span class="hljs-meta">!important</span>;
        <span class="hljs-attribute">animation-iteration-count</span>: <span class="hljs-number">1</span> <span class="hljs-meta">!important</span>;
        <span class="hljs-attribute">transition-duration</span>: <span class="hljs-number">0.01ms</span> <span class="hljs-meta">!important</span>;
        <span class="hljs-attribute">scroll-behavior</span>: auto <span class="hljs-meta">!important</span>;
    }
}<div aria-hidden="true" class="language-tag">CSS</div>
</code></pre><p>Ici c&#39;est plus subtil, et c&#39;est les seuls <code>!important</code> que j&#39;ai. On va s&#39;assurer de réduire au maximum les animations affichées pour les personnes qui demande explicitement via leur navigateur à avoir des animations réduites. C&#39;est un paramètre qu&#39;on peut activer au niveau du <a href="https://developer.mozilla.org/fr/docs/Web/CSS/Reference/At-rules/@media/prefers-reduced-motion#pr%C3%A9f%C3%A9rences_utilisateurs">système d&#39;exploitation</a> et qui rend plus agréable la navigation pour certains utilisateurs qui sont gênés par les animations.</p>
<figure>
<img src="https://anthonypena.fr/2026/01/21/nouveau-blog-partie-2-css/img/prefers-reduced-motion.png" alt="Option pour réduire les animations avec Gnome sous Linux" is="img-zoom"/>
<figcaption>Option pour réduire les animations avec Gnome sous Linux</figcaption>
</figure>
<h2 id="article-layers">Layers<a href="#article-layers" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Feature assez peu connu j&#39;ai l&#39;impression, pourtant c&#39;est extrêmement pratique !</p>
<p>L&#39;idée des layers est très simple : hiérarchiser des ensembles de style. Vous allez pouvoir dire que tel partie du style doit être appliqué en premier, ensuite tel autre partie passe ensuite et peu contredire directement la première partie, et ainsi de suite.</p>
<p>En gros : vous n&#39;avez plus besoin de <code>!important</code> ou de jouer sur des sélecteurs complexe pour surcharger le style de vos éléments. 🤩</p>
<p>Et c&#39;est même pas compliqué à utiliser !</p>
<pre><code class="hljs language-CSS"><span class="hljs-keyword">@layer</span> reset, base, layout, page;<div aria-hidden="true" class="language-tag">CSS</div>
</code></pre><p>Cette ligne s&#39;ajoute de préférence dans le premier fichier de style que vous allez charger, pour que le navigateur sache au plus vite comment organiser les styles. Elle va permettre de définir tous nos groupes et l&#39;ordre de priorité. Techniquement cette ligne est optionnelle mais si on ne l&#39;ajoute pas, c&#39;est l&#39;ordre de déclaration des styles de layer qui va définir l&#39;ordre d&#39;application (comme d&#39;habitude avec le CSS, l&#39;ordre est important). Donc ici tout le style de la couche <code>reset</code> va s&#39;appliquer, puis le style <code>base</code>, puis le style <code>layout</code>, puis enfin <code>page</code>.</p>
<pre><code class="hljs language-CSS"><span class="hljs-keyword">@layer</span> reset {
    // tout le <span class="hljs-selector-tag">code</span> de reset présenté avant
}

<span class="hljs-keyword">@layer</span> base {
    // tout le style de base
}

<span class="hljs-keyword">@layer</span> layout {
    // tout le style de layout
}

<span class="hljs-keyword">@layer</span> page {
    // tout le style de la <span class="hljs-attribute">page</span>
}<div aria-hidden="true" class="language-tag">CSS</div>
</code></pre><p>Ensuite on va entourer chaque portion de style avec une section <code>@layer nom-layer {}</code> et faire comme d&#39;habitude. Bien sûr : vous pouvez définir les sections layer dans plusieurs fichiers différents, vous pouvez aussi définir les layers en plusieurs parties (par exemple avoir plusieurs fichiers css qui vont contenir chacun une section page).</p>
<p>La priorité des sélecteurs se fera à l&#39;intérieur d&#39;une couche mais pas entre couche.</p>
<p>Ça veut dire que si vous avez ce style</p>
<pre><code class="hljs language-CSS"><span class="hljs-keyword">@layer</span> base, page;

<span class="hljs-selector-tag">a</span> {
    <span class="hljs-attribute">color</span>: blue;
}
<span class="hljs-selector-tag">body</span> &gt; <span class="hljs-selector-tag">p</span><span class="hljs-selector-class">.alert</span> <span class="hljs-selector-tag">a</span> {
    <span class="hljs-attribute">color</span>: red;
}

<span class="hljs-keyword">@layer</span> page {
    <span class="hljs-selector-tag">a</span> {
        <span class="hljs-attribute">text-decoration</span>: blue underline wavy <span class="hljs-number">2px</span>;
    }
}
<span class="hljs-keyword">@layer</span> base {
    <span class="hljs-selector-tag">body</span> &gt; <span class="hljs-selector-tag">p</span><span class="hljs-selector-class">.alert</span> <span class="hljs-selector-tag">a</span> {
        <span class="hljs-attribute">text-decoration</span>: red underline <span class="hljs-number">2px</span>;
    }
}<div aria-hidden="true" class="language-tag">CSS</div>
</code></pre><p>appliqué à ce contenu</p>
<pre><code class="hljs language-HTML"><span class="hljs-tag">&lt;<span class="hljs-name">html</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;alert&quot;</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&quot;#&quot;</span>&gt;</span>Inside p.alert<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&quot;#&quot;</span>&gt;</span>another link<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span><div aria-hidden="true" class="language-tag">HTML</div>
</code></pre><p>Vous aurez ça qui va s&#39;afficher :</p>
<figure>
<img src="https://anthonypena.fr/2026/01/21/nouveau-blog-partie-2-css/img/layer-priority.png" alt="Démonstration du changement de priorité via les layers" is="img-zoom"/>
<figcaption>Démonstration du changement de priorité via les layers</figcaption>
</figure>
<p>Ce qui se passe : </p>
<ul>
<li>la première ligne indique que le style <code>base</code> passe avant <code>page</code> ; </li>
<li>ensuite on définit que tous les liens doivent être de couleur bleue, puis que ceux qui sont dans un paragraphe avec la classe <code>alert</code> à la racine du body doivent être rouges, comme le second sélecteur est plus précis que le premier, c&#39;est celui-ci qui sera pris en compte pour les liens concernés ;</li>
<li>ensuite on définit que dans la layer <code>page</code> les liens doivent être soulignés avec une vague bleue, puis dans la layer <code>base</code> on définit que les liens qui sont dans un paragraphe <code>alert</code> à la racine du body doivent être soulignés en rouge, sauf la layer <code>page</code> va surcharger le style de la layer <code>base</code> donc contrairement à la couleur du texte tous les liens sont soulignés avec une vague bleue ;</li>
</ul>
<p>Vous pouvez jouer avec cet exemple ici : <a href="https://kuroidoruido.github.io/css-is-magic/layers/index.html">https://kuroidoruido.github.io/css-is-magic/layers/index.html</a></p>
<h2 id="article-css-components-et-nesting">CSS Components et nesting<a href="#article-css-components-et-nesting" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Comme je pense tous les développeurs frontend ces dernières années : je travaille avec des composants, avec tous les bons et mauvais côtés que ça implique.</p>
<p>Mon blog ne déroge pas à la règle, même si tout se passe en CSS. Je me suis inspiré de pas mal de framework CSS existant, à commencer par <a href="https://picocss.com/">picoCSS</a> :</p>
<ul>
<li>passer au maximum par du HTML sémantique ;</li>
<li>ajouter du style avec le moins de balise / classe superflue possible ;</li>
<li>créer des composants qui s&#39;auto-applique sur des éléments avec éventuellement des classes quand j&#39;ai besoin ;</li>
</ul>
<p>Un outil qui je trouve aide beaucoup c&#39;est le CSS nesting. Personnellement c&#39;était une des seules raisons qui faisaient que j&#39;utilisais du <a href="https://sass-lang.com/">SASS</a> avant, depuis je m&#39;en passe complètement.</p>
<p>Concrètement ?</p>
<pre><code class="hljs language-CSS"><span class="hljs-selector-tag">article</span><span class="hljs-selector-pseudo">:not</span>(<span class="hljs-selector-class">.main</span>) {
    <span class="hljs-attribute">border</span>: <span class="hljs-number">1px</span> solid gray;
}
<span class="hljs-selector-tag">article</span> <span class="hljs-selector-tag">header</span> <span class="hljs-selector-tag">h1</span> {
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">3rem</span>;
}
<span class="hljs-selector-tag">article</span> <span class="hljs-selector-tag">main</span> <span class="hljs-selector-tag">p</span> {
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1rem</span>;
}
<span class="hljs-selector-tag">article</span> <span class="hljs-selector-tag">main</span> <span class="hljs-selector-tag">a</span><span class="hljs-selector-pseudo">:hover</span> {
    <span class="hljs-attribute">text-decoration</span>: blue underline <span class="hljs-number">2px</span>;
}<div aria-hidden="true" class="language-tag">CSS</div>
</code></pre><p>peut aussi être écrit</p>
<pre><code class="hljs language-CSS"><span class="hljs-selector-tag">article</span> {
    &amp;<span class="hljs-selector-pseudo">:not</span>(<span class="hljs-selector-class">.main</span>) {
        <span class="hljs-attribute">border</span>: <span class="hljs-number">1px</span> solid gray;
    }
    <span class="hljs-selector-tag">header</span> {
        <span class="hljs-selector-tag">h1</span> {
            <span class="hljs-attribute">font-size</span>: <span class="hljs-number">3rem</span>;
        }
    }
    <span class="hljs-selector-tag">main</span> {
        <span class="hljs-selector-tag">p</span> {
            <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1rem</span>;
        }
        <span class="hljs-selector-tag">a</span><span class="hljs-selector-pseudo">:hover</span> {
            <span class="hljs-attribute">text-decoration</span>: blue underline <span class="hljs-number">2px</span>;
        }
    }
}<div aria-hidden="true" class="language-tag">CSS</div>
</code></pre><p>Et certes la seconde version est plus verbeuse (au sens où ça prend plus de ligne), mais clairement ça permet d&#39;avoir toujours des sélecteurs plus précis à moindre effort, c&#39;est facile de regrouper le style qui concerne un élément, on peut replier le style d&#39;un élément d&#39;un coup, on a pas besoin de répéter des parties de sélecteur pour garantir la priorité, etc.</p>
<p>Le nesting n&#39;a pour moi quasiment que des avantages !</p>
<h2 id="article-custom-properties">Custom Properties<a href="#article-custom-properties" class="anchor" aria-label="permalink">🔗</a></h2>
<p>L&#39;autre grosse raison d&#39;utiliser SASS c&#39;était les variables. On peut faire des calculs, on peut partager des valeurs un peu partout dans notre style, et éviter d&#39;avoir 18 fois la même couleur bleue sauf à un endroit où on s&#39;est trompé d&#39;un caractère ou qu&#39;on a changé le bleu en oubliant un endroit…</p>
<p>Les custom properties c&#39;est globalement la réponse aux variables SASS mais nativement supporté par le navigateur et géré sans compilation, sans avoir d&#39;import bizarre, de fichier avec des préfixes <code>_</code> dont on ne comprenait pas toujours l&#39;impact, etc.</p>
<p>Et qui dit custom properties, dit : on peut construire facilement des thèmes (j&#39;y reviendrai plus loin) !</p>
<p>Les custom properties sont pensés pour fonctionner de manière très proche des propriétés classiques : elles sont hiérarchiques, suivent les mêmes précédences, peuvent être surchargés, etc.</p>
<p>Comme ça marche ?</p>
<pre><code class="hljs language-CSS"><span class="hljs-selector-pseudo">:root</span> {
    <span class="hljs-attr">--je-suis-une-variable-globale</span>: <span class="hljs-number">#007bff</span>;
}

<span class="hljs-selector-tag">article</span> {
    <span class="hljs-attr">--je-suis-une-disponible-que-dans-les-articles</span>: <span class="hljs-number">#ff7b00</span>;

    <span class="hljs-selector-tag">main</span> {
        <span class="hljs-attribute">color</span>: <span class="hljs-built_in">var</span>(--je-suis-une-variable-globale);
        <span class="hljs-attribute">text-decoration</span>: <span class="hljs-built_in">var</span>(--je-suis-une-disponible-que-dans-les-articles) underline <span class="hljs-number">2px</span>;
    }
}<div aria-hidden="true" class="language-tag">CSS</div>
</code></pre><p>Une variable doit forcément être définie dans un contexte, pour avoir quelque chose de global, j&#39;utilise le pseudo-sélecteur <code>:root</code> pour définir une couleur bleue, ensuite dans <code>article</code> je définis une autre variable pour une couleur orange, et je les utilise dans main.</p>
<p>C&#39;est très simple à manipuler. Et on peut les utiliser pour produire des briques UI propres :</p>
<pre><code class="hljs language-CSS"><span class="hljs-selector-pseudo">:root</span> {
    <span class="hljs-comment">/* ATOMS */</span>
    <span class="hljs-attr">--color--white</span>: <span class="hljs-number">#ffffff</span>;
    <span class="hljs-attr">--color--dark-gray</span>: <span class="hljs-number">#333333</span>;
    <span class="hljs-comment">/* ... */</span>

    <span class="hljs-comment">/* MOLECULES */</span>
    <span class="hljs-attr">--color--bg</span>: <span class="hljs-built_in">var</span>(--color--white);
    <span class="hljs-attr">--color--text</span>: <span class="hljs-built_in">var</span>(--color--dark-gray);
}

<span class="hljs-comment">/* ... */</span>

<span class="hljs-keyword">@layer</span> base {
  <span class="hljs-selector-tag">html</span> {
    <span class="hljs-attribute">background-color</span>: <span class="hljs-built_in">var</span>(--color--bg);
    <span class="hljs-attribute">color</span>: <span class="hljs-built_in">var</span>(--color--text);
  }
}<div aria-hidden="true" class="language-tag">CSS</div>
</code></pre><p>Voilà c&#39;est pas plus compliqué que ça. Ça fonctionne évidemment aussi avec les tailles, sur le blog j&#39;ai par exemple 7 tailles différentes qui sont standardisées :</p>
<pre><code class="hljs language-CSS"><span class="hljs-selector-pseudo">:root</span> {
  <span class="hljs-attr">--size--quarter</span>: <span class="hljs-number">0.125rem</span>;
  <span class="hljs-attr">--size--half</span>: <span class="hljs-number">0.25rem</span>;
  <span class="hljs-attr">--size--1</span>: <span class="hljs-number">0.5rem</span>;
  <span class="hljs-attr">--size--2</span>: <span class="hljs-number">1rem</span>;
  <span class="hljs-attr">--size--3</span>: <span class="hljs-number">1.5rem</span>;
  <span class="hljs-attr">--size--4</span>: <span class="hljs-number">2rem</span>;
  <span class="hljs-attr">--size--5</span>: <span class="hljs-number">4rem</span>;
}<div aria-hidden="true" class="language-tag">CSS</div>
</code></pre><p>Peu importe le fichier de style, je pourrais utiliser les variables car la mise à disposition est gérée par le navigateur.</p>
<blockquote>
<p>Note : On est obligé de commencer les noms de custom properties par <code>--</code> mais ce sont mes conventions garder des <code>-</code> ensuite, j&#39;ai aussi pris l&#39;habitude de définir des sortes de contexte avec deux parties sur le nom séparé par <code>--</code>, ça me permet de m&#39;y retrouver plus vite, mais ce n&#39;est pas obligatoire.</p>
</blockquote>
<p>Je peux vous montrer par exemple le style qui gère le bloc en haut des pages de cette série d&#39;article :</p>
<pre><code class="hljs language-CSS"><span class="hljs-selector-tag">nav</span><span class="hljs-selector-attr">[data-serie]</span> {
    <span class="hljs-attr">--toc-series--margin-x</span>: <span class="hljs-built_in">var</span>(--size--<span class="hljs-number">5</span>);
    <span class="hljs-keyword">@media</span> screen <span class="hljs-keyword">and</span> (<span class="hljs-attribute">width</span> &lt; <span class="hljs-number">50rem</span>) {
        <span class="hljs-attr">--toc-series--margin-x</span>: <span class="hljs-built_in">var</span>(--size--<span class="hljs-number">2</span>);
    }

    <span class="hljs-attribute">border</span>: <span class="hljs-built_in">var</span>(--size--quarter) solid <span class="hljs-built_in">var</span>(--color--secondary);
    <span class="hljs-attribute">border-radius</span>: <span class="hljs-built_in">var</span>(--size--<span class="hljs-number">1</span>);
    <span class="hljs-attribute">padding</span>: <span class="hljs-built_in">var</span>(--size--<span class="hljs-number">1</span>) <span class="hljs-built_in">var</span>(--size--<span class="hljs-number">4</span>);
    <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span> <span class="hljs-built_in">var</span>(--toc-series--margin-x);

    <span class="hljs-selector-tag">ul</span> {
        <span class="hljs-attribute">list-style-type</span>: upper-roman;
    }
}<div aria-hidden="true" class="language-tag">CSS</div>
</code></pre><p>J&#39;ai coupé le nesting mais sinon tout le reste est là : je commence par définir une variable propre au sommaire (toc = table of content), qui est surchargé pour gérer le responsive, ensuite je fais essentiellement des combinaisons de variables. De cette façon, visuellement on est plus uniforme et on peut plus facilement faire évoluer ces éléments.</p>
<blockquote>
<p>Note : On voit aussi à nouveau l&#39;apport du nesting pour regrouper tout le style dans un seul groupe de style. On voit aussi une certaine logique &quot;composant&quot; au final, avec chaque brique visuel qui est un groupe CSS.</p>
</blockquote>
<h2 id="article-penser-au-responsive-">Penser au responsive !<a href="#article-penser-au-responsive-" class="anchor" aria-label="permalink">🔗</a></h2>
<p>On ne peut pas faire un site web grand public sans penser responsive et encore moins mobile. En France, on peut partir du principe qu&#39;environ <a href="https://gs.statcounter.com/platform-market-share/desktop-mobile-tablet/france">50% du traffic web se fait sur mobile</a>. </p>
<p>Pour moi c&#39;était important que les gens qui me lisent puissent me lire dans des bonnes conditions, donc je voulais que peu importe votre taille d&#39;écran, vous soyez à l&#39;aise pour lire (si ce n&#39;est pas le cas, n&#39;hésitez pas à me contacter pour que je corrige les cas que j&#39;aurais oubliés).</p>
<p>Pas vraiment de magie, je suis essentiellement passé par un break-point à 700px (en gros : je considère que la vue desktop c&#39;est tous les écrans de plus 700px de large, et les mobiles en dessous de 700px). C&#39;est clairement simpliste mais ça m&#39;a l&#39;air plutôt raisonnable comme découpe. Ensuite j&#39;ai beaucoup joué avec des layouts <code>flex</code> ou <code>grid</code> en fonction du cas pour avoir un affichage qui tient la route, s&#39;ajuste à la taille de l&#39;écran sans devenir trop large (je pense à vous les utilisateurs d&#39;écran ultra wide qui doivent parfois user votre nuque pour lire les lignes de texte trop longues…).</p>
<p>J&#39;ai aussi un peu joué côté page article sur des largeurs d&#39;écrans en nombre de caractère (par exemple : <code>@media (width &lt; 100ch)</code>) pour pouvoir vraiment dimensionner le texte de manière cohérente.</p>
<p>Au final j&#39;ai peu utilisé de media query, et beaucoup plus sur la flexibilité du layout pour s&#39;adapter à votre écran.</p>
<p>J&#39;ai aussi utilisé assez facilement les fonctions <code>min()</code> et <code>max()</code> qui sont quand même bien pratiques !</p>
<p>Par exemple :</p>
<pre><code class="hljs language-CSS"><span class="hljs-selector-pseudo">:root</span> {
    <span class="hljs-attr">--reponsive-index-max-width</span>: <span class="hljs-built_in">min</span>(<span class="hljs-number">100</span>dvw, <span class="hljs-built_in">var</span>(--cover--max-width))
}<div aria-hidden="true" class="language-tag">CSS</div>
</code></pre><p>Ici la variable <code>--reponsive-index-max-width</code> va être définie à ̀<code>var(--cover--max-width)</code> uniquement si c&#39;est plus petit que <code>100dvw</code> (100% de la largeur dynamique du viewport) donc dit autrement : toute la largeur de la page sauf si largeur de la page est plus grande que <code>var(--cover--max-width)</code>. C&#39;est très simple, c&#39;est super efficace, et c&#39;est responsive !</p>
<p>Si j&#39;ai une seule chose à conseiller : testez sur des mobiles physiques aussi. On se rend beaucoup mieux compte de la taille des choses, de comment on interagit avec les boutons, de si tout est bien lisible sur un vrai téléphone que sur un simulateur (même si on a vu des gros progrès, ce n&#39;est pas parfait et on loupe pas mal de choses).</p>
<h2 id="article-double-theme">Double thème<a href="#article-double-theme" class="anchor" aria-label="permalink">🔗</a></h2>
<p>J&#39;en ai parlé sur la partie HTML, évidemment que j&#39;allais aussi en parler sur la partie CSS !</p>
<p>J&#39;avais passé pas mal de temps à lire plein de choses sur le sujet, à me prendre la tête pour finalement gérer le sujet du thème clair / sombre super facilement avec des outils modernes de CSS.</p>
<p>Voilà tout le code qui concerne ma gestion de thème : </p>
<pre><code class="hljs language-CSS"><span class="hljs-selector-pseudo">:root</span> {
  <span class="hljs-comment">/* ATOMS */</span>
  <span class="hljs-attr">--color--white</span>: <span class="hljs-number">#ffffff</span>;
  <span class="hljs-attr">--color--black</span>: <span class="hljs-number">#121212</span>;
  <span class="hljs-attr">--color--dark-gray</span>: <span class="hljs-number">#333333</span>;
  <span class="hljs-attr">--color--gray</span>: <span class="hljs-number">#6c757d</span>;
  <span class="hljs-attr">--color--light-gray</span>: <span class="hljs-number">#e0e0e0</span>;
  <span class="hljs-attr">--color--blue</span>: <span class="hljs-number">#007bff</span>;
  <span class="hljs-attr">--color--green</span>: <span class="hljs-number">#28a745</span>;

  <span class="hljs-comment">/* MOLECULES */</span>
  <span class="hljs-attr">--color--bg</span>: <span class="hljs-built_in">light-dark</span>(<span class="hljs-built_in">var</span>(--color--white), <span class="hljs-built_in">var</span>(--color--black));
  <span class="hljs-attr">--color--text</span>: <span class="hljs-built_in">light-dark</span>(<span class="hljs-built_in">var</span>(--color--dark-gray), <span class="hljs-built_in">var</span>(--color--light-gray));
  <span class="hljs-attr">--color--primary</span>: <span class="hljs-built_in">var</span>(--color--blue);
  <span class="hljs-attr">--color--secondary</span>: <span class="hljs-built_in">var</span>(--color--gray);
  <span class="hljs-attr">--color--accent</span>: <span class="hljs-built_in">var</span>(--color--green);
  <span class="hljs-attr">--color--text-link</span>: <span class="hljs-built_in">light-dark</span>(<span class="hljs-built_in">var</span>(--color--black), <span class="hljs-built_in">var</span>(--color--white));
}<div aria-hidden="true" class="language-tag">CSS</div>
</code></pre><p>J&#39;ai d&#39;abord défini toutes mes couleurs brutes (pour être honnête : merci Mistral pour le choix des couleurs), puis j&#39;ai positionné ces couleurs sur des usages, en les combinants de sorte à définir mon thème. La fonction <code>light-dark()</code> étant assez magique pour ça, car il suffit de lui donne la couleur pour le thème clair et la couleur pour le thème sombre et la bonne couleur est choisie automatiquement et de manière réactive au changement de thème sans avoir rien de plus à faire !</p>
<h2 id="article-conclusion">Conclusion<a href="#article-conclusion" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Même si j&#39;ai parlé de style tout au long de cet article, j&#39;ai fait en sorte que mon blog se charge relativement bien même si aucun fichier css ne s&#39;affiche. Par exemple, j&#39;ai dans le fichier html de ma page d&#39;accueil ces lignes qui viennent masquer les images de base (c&#39;est annulé dans le style principal dans la couche <code>page</code> via <code>img { display: unset; }</code>) :</p>
<pre><code class="hljs language-HTML"><span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span><span class="language-css">
    <span class="hljs-keyword">@layer</span> base {
        <span class="hljs-selector-tag">img</span> {
            <span class="hljs-attribute">display</span>: none;
        }
    }
</span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span><div aria-hidden="true" class="language-tag">HTML</div>
</code></pre><p>Toujours dans ma logique de progressive enhancement j&#39;ai fait en sorte que le contenu soit le centre du blog, puis j&#39;ai ajouté du style pour améliorer le style, l&#39;affichage, apporter du confort (et me faire un peu plaisir au passage évidemment).</p>
<p>J&#39;ai utilisé beaucoup de fonctionnalité moderne de CSS. Des fonctionnalités qu&#39;on utilise pas assez à mon avis. Des fonctionnalités qu&#39;on a tendance à ignorer quand on utilise massivement des frameworks ou des outils comme TailwindCSS car ça vous impose de raisonner local alors que le CSS est pensé pour raisonner global à mon sens…</p>
<p>La suite logique au CSS c&#39;est le JavaScript et j&#39;en ai fait un peu, juste ce qu&#39;il faut. On se retrouve sur la partie 3 pour voir ça !</p>
<p>Crédit photo : Générée via Mistral AI avec le prompt suivant : </p>
<blockquote>
<p>Une scène chaleureuse et immersive, inspirée par l’esthétique poétique de Studio Ghibli, représentant un atelier de couture high-tech en bois clair et vieilli, baigné d’une lumière dorée et tamisée, comme un après-midi d’automne. Au centre, un panda roux anthropomorphe (Firefox), vêtu d’une veste ample et confortable, est assis à une table de travail en bois, concentré sur la couture de styles CSS. </p>
<p>Autour de lui, des bobines de fil colorées (bleu électrique, orange, beige) flottent comme des variables CSS, et des morceaux de tissu représentent des feuilles de style. Le panda roux utilise une aiguille et du fil pour &quot;coudre&quot; des styles CSS sur une toile de HTML nu, symbolisant la mise en forme du contenu. Des ciseaux et des patrons de couture stylisés en balises CSS (<code>{ }</code>) sont posés sur la table, tandis qu’un miroir magique montre le rendu final (thème light/dark) en reflet. </p>
<p>En arrière-plan, une grande fenêtre donne sur une ville nocturne aux néons bleutés, reflétant des motifs de code binaire sur les murs. Une tasse de thé fumant et des feuilles d’érable flottent doucement dans l’air, ajoutant une touche magique à la scène. </p>
<p>À droite, en bas, le panda roux est légèrement tourné en 3/4 dos, lové sur un coussin, entouré d’un halo lumineux subtil. Il ne dépasse pas le tiers de la hauteur de l’image et observe son travail avec satisfaction. </p>
<p>L’ambiance est cosy, onirique et high-tech : les couleurs sont douces (beiges, bleus pâles, oranges chauds), avec des jeux de lumière tamisée dorée qui créent des ombres chaleureuses. Les détails sont soignés, avec des textures visibles (grain du bois, tissu, pelage du panda roux), et une lumière qui met en valeur les éléments tech et artisanaux. Le tout respire la sérénité et l’inspiration, comme un moment suspendu entre la magie et la technologie.&quot;&quot;Une scène chaleureuse et immersive, inspirée par l’esthétique poétique de Studio Ghibli, représentant un atelier de couture high-tech en bois clair et vieilli, baigné d’une lumière dorée et tamisée, comme un après-midi d’automne. Au centre, un panda roux anthropomorphe (Firefox), vêtu d’une veste ample et confortable, est assis à une table de travail en bois, concentré sur la couture de styles CSS. </p>
<p>Autour de lui, des bobines de fil colorées (bleu électrique, orange, beige) flottent comme des variables CSS, et des morceaux de tissu représentent des feuilles de style. Le panda roux utilise une aiguille et du fil pour &quot;coudre&quot; des styles CSS sur une toile de HTML nu, symbolisant la mise en forme du contenu. Des ciseaux et des patrons de couture stylisés en balises CSS (<code>{ }</code>) sont posés sur la table, tandis qu’un miroir magique montre le rendu final (thème light/dark) en reflet. </p>
<p>En arrière-plan, une grande fenêtre donne sur une ville nocturne aux néons bleutés, reflétant des motifs de code binaire sur les murs. Une tasse de thé fumant et des feuilles d’érable flottent doucement dans l’air, ajoutant une touche magique à la scène. </p>
<p>À droite, en bas, le panda roux est légèrement tourné en 3/4 dos, lové sur un coussin, entouré d’un halo lumineux subtil. Il ne dépasse pas le tiers de la hauteur de l’image et observe son travail avec satisfaction. </p>
<p>L’ambiance est cosy, onirique et high-tech : les couleurs sont douces (beiges, bleus pâles, oranges chauds), avec des jeux de lumière tamisée dorée qui créent des ombres chaleureuses. Les détails sont soignés, avec des textures visibles (grain du bois, tissu, pelage du panda roux), et une lumière qui met en valeur les éléments tech et artisanaux. Le tout respire la sérénité et l’inspiration, comme un moment suspendu entre la magie et la technologie.</p>
</blockquote>
]]></content:encoded>
      <dc:creator><![CDATA[Anthony Pena]]></dc:creator>
      <media:content medium="image" url="https://anthonypena.fr/img/cover.min.jpg"/>
    </item>
    <item>
      <title><![CDATA[Nouveau blog -- partie 1 : HTML]]></title>
      <guid isPermaLink="false">2026/01/15/nouveau-blog-partie-1-html</guid>
      <description><![CDATA[<p>J&#39;avais évoqué sur le blog le changement de plateforme en 2024, donc ça va faire bientôt 3 ans que l…</p>
]]></description>
      <link>https://anthonypena.fr/2026/01/15/nouveau-blog-partie-1-html/index.html</link>
      <category><![CDATA[Web]]></category>
      <category><![CDATA[Frontend]]></category>
      <pubDate>Thu, 15 Jan 2026 07:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>J&#39;avais évoqué sur le blog le changement de plateforme en <a href="/2024/03/12/2023-cest-fini-en-route-pour-2024/">2024</a>, donc ça va faire bientôt 3 ans que le sujet est en cours de mon côté (quand j&#39;en ai parlé en 2024 j&#39;avais déjà pas mal travaillé sur le sujet dans l&#39;année…), et c&#39;est enfin une réalité ! Enfin depuis quelques articles déjà, mais je n&#39;ai pas fait d&#39;annonce en grande pompe non pour me laisser l&#39;option de revenir en arrière si je voyais que ça ne fonctionnait pas.</p>
<p>En tout cas, après plus de 9 ans avec Ghost, je tourne définitivement la page Ghost pour quelque chose de différent et je vous explique tout ça !</p>
<blockquote>
<p>Si vous êtes habitués à mes articles hebdomadaires sans liens directs entre eux, je vais trancher avec mes habitudes et je vais créer la première série du blog !</p>
<p>Mais promis : quand j&#39;aurai fini je reprendrais un rythme plus normal et surtout moins auto-centré ! 😅</p>
</blockquote>
<nav data-serie="nouveau-blog-marked-deno">
<h2>Série d'article</h2>
<ul>
<li><a href="https://anthonypena.fr/2026/01/15/nouveau-blog-partie-1-html/index.html">Nouveau blog -- partie 1 : HTML</a></li>
<li><a href="https://anthonypena.fr/2026/01/21/nouveau-blog-partie-2-css/index.html">Nouveau blog -- partie 2 : CSS</a></li>
<li><a href="https://anthonypena.fr/2026/01/27/nouveau-blog-partie-3-js/index.html">Nouveau blog -- partie 3 : JavaScript</a></li>
<li><a href="https://anthonypena.fr/2026/02/10/nouveau-blog-partie-4-et-le-reste/index.html">Nouveau blog --  partie 4 : et le reste...</a></li>
</ul>
</nav>
<h2 id="article-je-pars-de-quoi-vers-quoi-">Je pars de quoi vers quoi ?<a href="#article-je-pars-de-quoi-vers-quoi-" class="anchor" aria-label="permalink">🔗</a></h2>
<blockquote>
<p>Si vous n&#39;êtes pas intéressé par le cheminement qui m&#39;a amené au résultat actuel, vous pouvez complètement sauter cette partie.</p>
</blockquote>
<p>Sans reprendre toute mon histoire de blogging (<a href="/2024/09/10/presque-15-ans-de-presque-blogging/">un article existe déjà sur le sujet si vous êtes curieux</a>), j&#39;ai commencé ce blog en installant un <a href="https://github.com/TryGhost/Ghost">Ghost</a> sur un serveur dédié en version 0.x.y. À l&#39;époque j&#39;étais séduit par le fait de pouvoir rédiger en Markdown et par le stockage en Markdown aussi ! Ça me garantissait un minimum de capacité à sortir le contenu si le besoin s&#39;en faisait sortir un jour. J&#39;ai donc fait avec les quelques ratés de l&#39;éditeur web à l&#39;époque pour commencer à rédiger. Puis j&#39;ai suivi les versions avant de me retrouver bloquer en version 3. La version 4 me provoquant une perte complète de toutes les images…</p>
<p>Avoir des versions majeures de retard n&#39;étaient pas acceptables à mon sens. Le stockage en base de donnée qui avait largement évolué aussi pour ne plus être du Markdown aussi. Markdown ayant été relégué à une option de formatage dans un bloc de texte…</p>
<blockquote>
<p>Note : je peux sembler extrêmement critique envers Ghost, c&#39;est vrai mais surtout en ce qui concerne mon rapport à Ghost et à son éloignement entre l&#39;évolution de Ghost et mon usage. Je pense que Ghost est un outil qui peut correspondre à pas mal de gens, modulo qu&#39;on prenne bien le temps de comprendre les limitations de la plateforme (comme toutes plateformes, quand bien même c&#39;est rarement fait) et que ça n&#39;est pas un bloqueur.</p>
</blockquote>
<p>À cette période un flottement s&#39;est créé chez moi : quitter Ghost après tant de temps ? Mais créer mon outil prendrait trop de temps / d&#39;effort…</p>
<p>Et puis j&#39;ai découvert <a href="http://astro.build/">Astro</a>, qui est un framework web orienté contenu, super performant, avec plein de facilités, supportant Markdown nativement, etc. Je me suis donc lancé dans un PoC en mars 2023 à travers la création de <a href="https://github.com/kuroidoruido/go-read-yourself/">GoReadYourself</a>, ma plateforme de &quot;micro blogging&quot; maison (mon instance est accessible <a href="https://press.k49.fr.nf/">ici</a>) qui m&#39;aide à préparer mes revues de presse. J&#39;ai très très vite pu utiliser GoReadYourself au quotidien, ça rempli encore en grande partie le travail que j&#39;en attends, et je me suis convaincu que c&#39;est ce dont j&#39;avais besoin pour mon blog !</p>
<p>J&#39;ai donc commencé à travailler sur une re-création de mon blog en juillet 2023. Et j&#39;ai avancé doucement, ajoutant des briques, retouchant des choses, ajustant des détails, me perdant parfois une journée sur certains détails, en ajoutant plein de petits trucs que je n&#39;avais même pas sur Ghost pour me convaincre de la plus-value, sans jamais mettre en ligne de version test, ne sachant pas clairement comment je voulais déployer le blog, etc. En gros : j&#39;ai fait à la fois les erreurs que je citais dans mon article <a href="/2024/09/10/presque-15-ans-de-presque-blogging/">&quot;Presque 15 ans de presque blogging&quot;</a> et aussi de la plupart des projets qui n&#39;arrivent jamais en production… Et j&#39;ai choisi la solution technique par envie de l&#39;utiliser plutôt que pour répondre au besoin… Le dernier commit date de novembre 2024, je ne voyais plus l&#39;intérêt de poursuivre, car je voyais bien que je m&#39;enlisais…</p>
<p>J&#39;ai laissé quelques mois passer, puis j&#39;ai tranché : j&#39;ai fait page blanche, je suis reparti du besoin, j&#39;ai défini un MVP avec 4 lots, j&#39;ai créé une branche sur dépôt git de mon blog et j&#39;ai commencé à coder en me concentrant uniquement sur les fonctionnalités <strong>nécessaires</strong> pour une mise en ligne, mettant de côté pour plus tard tout le reste. Je travaille pas mal dessus dans l&#39;été, j&#39;ai continué quand j&#39;avais du temps sur la fin d&#39;année jusqu&#39;à me dire &quot;c&#39;est bon je pousse en ligne&quot; à la mi-décembre.</p>
<h2 id="article-le-markdown-au-centre">Le Markdown au centre<a href="#article-le-markdown-au-centre" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Ça fait très longtemps que je travaille avec du Markdown. Pour moi <a href="https://fr.wikipedia.org/wiki/Aaron_Swartz">Aaron Swartz</a> et <a href="https://en.wikipedia.org/wiki/John_Gruber">John Gruber</a> ont créé un langage extrêmement puissant sur pas mal d&#39;aspect : il est pensé pour être converti facilement en HTML, il permet de se concentrer sur le contenu et pas la forme ou la structure. Il y a beaucoup à dire sur les langages de markup comme Markdown, AsciiDoc ou même TeX (j&#39;ai passé une grosse partie de mes études à écrire du LaTeX et je pense que ça m&#39;a vraiment aidé pour la suite !), mais je pense que ce n&#39;est pas le sujet du jour !</p>
<p>Pour moi c&#39;était logique d&#39;écrire sur mon blog avec du Markdown. C&#39;est pour ça que j&#39;avais choisi Ghost. C&#39;est pour ça que j&#39;ai quitté Ghost. Ça fait presque 4 ans que je suis revenu à l&#39;écriture en pur Markdown et un dépôt git. Je peux écrire partout, avec mon éditeur du quotidien (actuellement VSCode), mes habitudes côté raccourcis clavier, même sans Internet au besoin (j&#39;écris beaucoup dans le train, avec un Internet intermittent ; parfois juste je pars avec mon laptop pour me poser dans un parc pour être au calme et me couper des notifications). Jusque-là je copiais à la main le contenu des articles vers Ghost pour les publier. Je perdais entre 20 et 45 minutes (parfois plus…) à faire ce report chaque semaine pour mon confort d&#39;écriture.</p>
<p>Maintenant je convertis directement mes fichiers Markdown dans le HTML que vous voyez (enfin presque, je vous explique plus loin) de sorte à juste avoir à écrire et commit pour mettre en ligne. Tout est automatisé. Tout est fluide pour moi.</p>
<h2 id="article-deno-et-marked-comme-seules-dependances">Deno et Marked comme seules dépendances<a href="#article-deno-et-marked-comme-seules-dependances" class="anchor" aria-label="permalink">🔗</a></h2>
<p>J&#39;en ai déjà parlé sur le blog, je suis partisan d&#39;avoir le moins de dépendance possible. Chaque dépendance implique des mises à jours, des failles de sécurités, etc. Donc avoir le moins de dépendance possible était important pour moi.</p>
<p>J&#39;ai choisi de dépendre vraiment que de deux outils : <a href="https://deno.com/">Deno</a> et <a href="http://marked.js.org/">Marked</a>.</p>
<p>J&#39;ai choisi Deno parce que je pense que c&#39;est le moteur qu&#39;on devrait utiliser partout aujourd&#39;hui. Je sais, certains diront que Bun aurait été un meilleur choix, bla bla bla. Deno n&#39;a pas juste copié Node, il est pensé pour la sécurité à tous les niveaux : choix de Rust pour que le compilateur garantisse autant que possible une bonne gestion mémoire et choix d&#39;un modèle de permission strict pour limiter au maximum les accès aux différents éléments de la machine hôte. Deno a aussi une DX (Developer eXperience) excellente : vous n&#39;avez aucune configuration à faire pour faire du TypeScript (first-class citizen), vous n&#39;avez pas à vous battre avec les dépendances, vous n&#39;avez pas de <code>node_modules</code>.</p>
<p>Je sais que Deno n&#39;est pas le moteur le plus performant selon les benchmarks. Et alors ? Déjà, je n&#39;ai pas besoin de très haute performance. Ensuite les benchmarks valent toujours ce qu&#39;ils valent : pas grand-chose par rapport à la réalité qui est que les gens utilisent généralement mal leurs outils et donc perdent beaucoup de performance par le code qu&#39;ils écrivent ou les dépendances choisies. Et aussi le réalisme des benchmarks ; la plupart des cas que j&#39;ai vu c&#39;est un serveur web qui fait un &quot;Hello, World!&quot; en retour d&#39;un appel HTTP, pas vraiment ce qu&#39;on fait dans la vraie vie.</p>
<p>En tout et pour tout, j&#39;ai zéro lignes de configuration Deno / TypeScript / autre pour pouvoir écrire du code qui fonctionne. J&#39;ai un fichier <code>deno.json</code> qui contient des <code>tasks</code> (équivalent des <code>scripts</code> du <code>package.json</code> Node) et quelques lignes de dépendances, rien de plus.</p>
<p>Vient ensuite ma seconde dépendances : Marked. Il s&#39;agit d&#39;une librairie très extensible pour convertir du Markdown en HTML. J&#39;aurai pu écrire la mienne et perdre des semaines à créer une librairie avec un aussi bon support de <a href="https://commonmark.org/">CommonMarks</a> qui passent les 652 cas de tests, mais profiter de l&#39;intelligence collective qui a mené à Marked était un meilleur choix. Il y a surement des outils plus rapides, mais Marked est facile d&#39;usage, extensible et déjà bien rapide (convertir les plus de 200 articles de mon blog prend entre 500ms et 800ms).</p>
<p>J&#39;ai par contre développé six plugins pour mes besoins spécifiques et pouvoir améliorer (à mon sens en tout cas) le HTML produit :</p>
<ul>
<li><a href="https://www.npmjs.com/package/@anthonypena/marked-inline-ascii-punctuation"><code>@anthonypena/marked-inline-ascii-punctuation</code></a> : pour automatiquement convertir certaines ponctuations qui sont peu pratiques à taper au clavier (par exemple <code>...</code> est transformé en <code>…</code>) ;</li>
<li><a href="https://www.npmjs.com/package/@anthonypena/marked-heading-links"><code>@anthonypena/marked-heading-links</code></a> : pour ajouter un lien à chaque titre des articles de sorte à pouvoir pointer une partie directement ;</li>
<li><a href="https://www.npmjs.com/package/@anthonypena/marked-better-image"><code>@anthonypena/marked-better-image</code></a> : pour afficher les images de manière plus propre (pas une simple balise <code>&lt;img/&gt;</code> mais une <code>&lt;figure&gt;</code> avec une description) ;</li>
<li><a href="https://www.npmjs.com/package/@anthonypena/marked-image-gallery"><code>@anthonypena/marked-image-gallery</code></a> : pour gérer des galeries d&#39;images quand j&#39;ai plusieurs images qui se suivent ;</li>
<li><a href="https://www.npmjs.com/package/@anthonypena/marked-djot-div"><code>@anthonypena/marked-djot-div</code></a> : pour ajouter le support de la syntaxe des <code>&lt;div&gt;</code> venants de <a href="https://www.djot.net/">Djot</a> (un langage dérivé de CommonMark), j&#39;avais écrit le plugin pour tester un truc, mais je ne l&#39;utilise pas encore sur le blog, comme je ne pouvais pas avoir d&#39;équivalent dans Ghost ;</li>
<li><a href="https://www.npmjs.com/package/@anthonypena/marked-toc-for-series"><code>@anthonypena/marked-toc-for-series</code></a> : pour ajouter un sommaire de série avec des liens entre les articles au début de l&#39;article (vous le verrez apparaitre au moment de la partie 2 de cette série) ;</li>
</ul>
<p>Pour être honnête, j&#39;utilise aussi <a href="https://highlightjs.org/">Highlight.js</a> mais je n&#39;ai qu&#39;une dizaine de lignes pour l&#39;intégrer et je pourrais facilement changer de librairie si l&#39;envie m&#39;en prenait.</p>
<h2 id="article-de-morceau-dhtml-a-un-site">De morceau d&#39;HTML à un site<a href="#article-de-morceau-dhtml-a-un-site" class="anchor" aria-label="permalink">🔗</a></h2>
<p>C&#39;est là qu&#39;arrive la difficulté à mon sens : produire du HTML à partir des fichiers Markdown ne suffit pas. Il faut lier tout ça. Créer une page d&#39;accueil, mettre un peu de cadre, avoir la structure d&#39;une vraie page HTML.</p>
<p>C&#39;est là que j&#39;ai dû créer mon propre moteur de templating.</p>
<p>Ne vous attendez pas à un truc de fou. J&#39;ai fait un système simple de <code>.replaceAll()</code> mais qui marche parfaitement.</p>
<p>Schématiquement, tout se passe dans une fonction <code>applyArticleTemplate()</code> qui va prendre un <code>template</code> (une chaîne de caractère contenant du HTML mais avec quelques marqueurs spécifiques) et un objet <code>article</code> qui contient le contenu de l&#39;article et toutes les métadonnées dont j&#39;ai besoin.</p>
<p>Je vais constituer un dictionnaire de clé à remplacer puis je vais aller remplacer chaque occurrence de la clé par la valeur que j&#39;ai définie. Rien de sorcier. J&#39;ai quand même dû créer une syntaxe de condition qui n&#39;est pas jolie mais qui fait le travail sans souci.</p>
<p>Tout tient dans ce bloc de code (j&#39;ai juste coupé un peu le dictionnaire, car c&#39;est un peu verbeux) : </p>
<pre><code class="hljs language-TypeScript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">function</span> <span class="hljs-title function_">applyArticleTemplate</span>(<span class="hljs-params">
  <span class="hljs-attr">template</span>: <span class="hljs-built_in">string</span>,
  <span class="hljs-attr">article</span>: <span class="hljs-title class_">Article</span>
</span>): <span class="hljs-built_in">string</span> {
  <span class="hljs-keyword">let</span> html = template;
  <span class="hljs-keyword">const</span> dictionary = {
    <span class="hljs-string">&quot;article.url&quot;</span>: <span class="hljs-string">`/<span class="hljs-subst">${article.path}</span>`</span>,
    <span class="hljs-string">&quot;article.title&quot;</span>: article.<span class="hljs-property">title</span>,
    <span class="hljs-string">&quot;article.contentHtml&quot;</span>: article.<span class="hljs-property">contentHtml</span>,
    <span class="hljs-comment">// ...</span>
    <span class="hljs-string">&quot;article.readingTimeInMinutes&quot;</span>: <span class="hljs-title class_">String</span>(article.<span class="hljs-property">readingTimeInMinutes</span>),
    ...<span class="hljs-title class_">Object</span>.<span class="hljs-title function_">fromEntries</span>(
      article.<span class="hljs-property">tags</span>.<span class="hljs-title function_">map</span>(<span class="hljs-function">(<span class="hljs-params">tag, index</span>) =&gt;</span> [<span class="hljs-string">`article.tags[<span class="hljs-subst">${index}</span>].label`</span>, tag])
    ),
  };
  <span class="hljs-keyword">const</span> match = html.<span class="hljs-title function_">matchAll</span>(<span class="hljs-regexp">/#if\((.*)\)\{/gm</span>);
  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> [ifPattern, ifTarget] <span class="hljs-keyword">of</span> match) {
    <span class="hljs-keyword">if</span> (ifTarget <span class="hljs-keyword">in</span> dictionary) {
      html = html.<span class="hljs-title function_">replaceAll</span>(ifPattern, <span class="hljs-string">&quot;&quot;</span>);
    } <span class="hljs-keyword">else</span> {
      <span class="hljs-keyword">const</span> start = html.<span class="hljs-title function_">indexOf</span>(ifPattern);
      <span class="hljs-keyword">const</span> end = html.<span class="hljs-title function_">indexOf</span>(<span class="hljs-string">&quot;}#fi&quot;</span>, start);
      html = html.<span class="hljs-title function_">replace</span>(html.<span class="hljs-title function_">slice</span>(start, end + <span class="hljs-number">4</span>), <span class="hljs-string">&quot;&quot;</span>);
    }
  }
  html = html.<span class="hljs-title function_">replaceAll</span>(<span class="hljs-string">&quot;}#fi&quot;</span>, <span class="hljs-string">&quot;&quot;</span>);
  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> [key, value] <span class="hljs-keyword">of</span> <span class="hljs-title class_">Object</span>.<span class="hljs-title function_">entries</span>(dictionary)) {
    html = html.<span class="hljs-title function_">replaceAll</span>(<span class="hljs-string">`{{<span class="hljs-subst">${key}</span>}}`</span>, value);
  }
  <span class="hljs-keyword">return</span> html;
}<div aria-hidden="true" class="language-tag">TypeScript</div>
</code></pre><p>Côté template, on va retrouver quelque chose de très simple : on voit des &quot;moustaches&quot; (comme en Angular (et d&#39;autres) parce que ça me parait bien comme syntaxe, et y&#39;a rien qui ressemble en HTML de base) contenant la clé qui doit être utilisé.</p>
<pre><code class="hljs language-HTML"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">&quot;fr&quot;</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    ...
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>{{article.title}} - Anthony PENA<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    ...
    <span class="hljs-tag">&lt;<span class="hljs-name">main</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">article</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;post&quot;</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">header</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">section</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;title&quot;</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>{{article.title}}<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">section</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;metadata&quot;</span>&gt;</span>
            ...
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;tags&quot;</span>&gt;</span>
              #if(article.tags[0].label){
              <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;tag&quot;</span>&gt;</span>#{{article.tags[0].label}}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>}#fi
              #if(article.tags[1].label){
              <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;tag&quot;</span>&gt;</span>#{{article.tags[1].label}}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>}#fi
              #if(article.tags[2].label){
              <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;tag&quot;</span>&gt;</span>#{{article.tags[2].label}}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>}#fi
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span>
          ...
        <span class="hljs-tag">&lt;<span class="hljs-name">main</span>&gt;</span>{{article.contentHtml}}<span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">article</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span><div aria-hidden="true" class="language-tag">HTML</div>
</code></pre><p>Là où la plupart des gens auraient sorti une librairie toute prête pour faire ça (avec l&#39;obligation de maintenir la dépendance, se surcharger de fonctionnalités inutiles, devoir apprendre une syntaxe sophistiquée pour répondre à énormément de cas), coder mon propre système n&#39;a pas du tout été difficile, me permet pas mal d&#39;évolutions et à moindre effort !</p>
<h2 id="article-static-html-first">Static html first<a href="#article-static-html-first" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Si j&#39;ai un temps pensé à utiliser Astro, au moment de la remise à plat j&#39;ai défini un point très simple : je n&#39;ai pas besoin de faire du SSR (Server Side Rendering = rendu à chaque requête) mais j&#39;ai besoin de SSG (Static Site Generation = génération statique à un instant T).</p>
<p>L&#39;ensemble des fichiers Markdown de mon blog est converti en un site HTML static, en environ 2 secondes, à chaque commit et chaque matin vers 6h30 (pour gérer les articles qui serait commit en avance), formant un site complet qui ne demande aucun calcul côté serveur (enfin presque, mais j&#39;y reviendrai plus tard). L&#39;article que vous lisez en ce moment n&#39;a donc demandé que peu d&#39;énergie pour vous parvenir, et ne bougera pas avant demain matin au plus tôt sauf si je me rends compte d&#39;une erreur quelque part et que je la corrige.</p>
<p>C&#39;est un choix fort de ma part. Je voulais revenir à la base du web : le HTML et le CSS.</p>
<p>J&#39;écris un article par semaine, je trouvais absurde de générer le contenu à la volée, je trouvais absurde d&#39;avoir un site dynamique qui a forcément un coût écologique non nul.</p>
<h2 id="article-uniquement-du-html-mais-deja-2-themes-et-un-support-mobile-">Uniquement du HTML mais déjà 2 thèmes et un support mobile !<a href="#article-uniquement-du-html-mais-deja-2-themes-et-un-support-mobile-" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Si vous coupez le chargement des feuilles de style, vous aurez déjà un thème light / dark sur mon blog.</p>
<p>Laisser aux lecteurs le choix de lire sur fond blanc ou noir était très important pour moi. Mais je ne voulais pas avoir de clignotement blanc/noir sur la page non plus. C&#39;était aussi important pour moi que mon blog soit lisible sur mobile comme sur desktop.</p>
<p>J&#39;ai donc utilisé au maximum les fonctionnalités des navigateurs avec deux balises magiques à mettre dans les balises <code>&lt;head&gt;</code> :</p>
<pre><code class="hljs language-HTML"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;viewport&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;width=device-width, initial-scale=1&quot;</span> /&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;color-scheme&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;light dark&quot;</span> /&gt;</span><div aria-hidden="true" class="language-tag">HTML</div>
</code></pre><p>La première va s&#39;assurer qu&#39;on gère correctement l&#39;échelle d&#39;affichage pour éviter des textes trop petits / trop grands, sans bloquer le zoom ! (je trouve insupportable les sites qui bloquent le zoom et du coup qui ne me permettent pas de regarder en gros un détail qui m&#39;intéresse…)</p>
<p>La seconde va directement indiquer au navigateur que mon contenu peut être lu en thème light ou dark, et donc qu&#39;il peut appliquer les styles qui vont bien : c&#39;est géré automatiquement. La plupart des navigateurs vont reprendre le paramètre de votre OS pour le thème à afficher par défaut !</p>
<figure id="image-gallery-blog-sans-aucun-des-deux-meta-puis-en-ajoutant-le-meta-viewport-puis-en-ajoutant-aussi-le-meta-colorscheme" class="marked-image-gallery" is="gallery-zoom">
<img src="https://anthonypena.fr/2026/01/15/nouveau-blog-partie-1-html/img/blog-meta-1.png" alt="Blog sans aucun des deux meta, puis en ajoutant le meta viewport, puis en ajoutant aussi le meta color-scheme"/>
<img src="https://anthonypena.fr/2026/01/15/nouveau-blog-partie-1-html/img/blog-meta-2.png" alt="Blog sans aucun des deux meta, puis en ajoutant le meta viewport, puis en ajoutant aussi le meta color-scheme"/>
<img src="https://anthonypena.fr/2026/01/15/nouveau-blog-partie-1-html/img/blog-meta-3.png" alt="Blog sans aucun des deux meta, puis en ajoutant le meta viewport, puis en ajoutant aussi le meta color-scheme"/>
<figcaption>Blog sans aucun des deux meta, puis en ajoutant le meta viewport, puis en ajoutant aussi le meta color-scheme</figcaption>
</figure>
<h2 id="article-conclusion">Conclusion<a href="#article-conclusion" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Comme c&#39;était logique pour moi de faire mon blog en suivant un process simple : faire du HTML, puis du CSS quand je bloque, puis du JavaScript quand je suis bloqué (et sans qu&#39;il soit nécessaire) ; ce premier article s&#39;arrête au HTML.</p>
<p>À mon sens, il n&#39;y a rien de fou sur mon blog en termes de HTML, mais je trouvais ça important de partir de ça pour montrer qu&#39;au fond c&#39;est facile de produire du contenu HTML et qu&#39;il n&#39;y a besoin de beaucoup de HTML pour que tout fonctionne.</p>
<p>J&#39;espère vous retrouver pour la seconde partie de cette série ! 🤓</p>
<p>Crédit photo : Générée via Mistral AI avec le prompt suivant : </p>
<blockquote>
<p>Une scène chaleureuse et immersive, inspirée par l’esthétique poétique de Studio Ghibli, représentant un atelier d’écriture en bois clair et vieilli, baigné d’une lumière dorée et tamisée, comme un après-midi d’automne. Au centre, un panda roux (Firefox) anthropomorphe, vêtu d’une veste ample et confortable, est assis à un bureau en bois, en train d’écrire à la plume sur des feuilles de papier Markdown. Autour de lui, des feuilles de papier se transforment magiquement en parchemins HTML, avec des balises HTML qui apparaissent comme par enchantement en encre dorée. </p>
<p>Le bureau est en bois clair, avec des piles de carnets et de magazines techniques futuristes empilés de manière désordonnée mais harmonieuse. Certains carnets sont ouverts, révélant des extraits de code HTML et des schémas techniques dessinés à la main. Un écran transparent et flottant (style holographique, avec un cadre en bois sculpté) affiche des lignes de code HTML en temps réel, intégrées naturellement à la scène. </p>
<p>En arrière-plan, une grande fenêtre donne sur un paysage automnal : des arbres aux feuilles rouges, oranges et jaunes, et des lanternes suspendues qui projettent une lumière douce. Des feuilles d’érable flottent lentement dans l’air, ajoutant une touche magique à la scène. </p>
<p>À droite, en bas, le panda roux est légèrement tourné en 3/4 dos, lové sur un coussin, entouré d’un halo lumineux subtil. Il ne dépasse pas le tiers de la hauteur de l’image et observe la transformation des feuilles Markdown en HTML avec curiosité et satisfaction. </p>
<p>L’ambiance est cosy, onirique et high-tech : les couleurs sont douces (beiges, bleus pâles, oranges chauds), avec des jeux de lumière tamisée dorée qui créent des ombres chaleureuses. Les détails sont soignés, avec des textures visibles (grain du bois, tissu du coussin, pelage du panda roux), et une tasse de thé fumant posée sur le bureau. Le tout respire la sérénité et l’inspiration, comme un moment suspendu entre la magie et la technologie.&quot;&quot;Une scène chaleureuse et immersive, inspirée par l’esthétique poétique de Studio Ghibli, représentant un atelier d’écriture en bois clair et vieilli, baigné d’une lumière dorée et tamisée, comme un après-midi d’automne. Au centre, un panda roux (Firefox) anthropomorphe, vêtu d’une veste ample et confortable, est assis à un bureau en bois, en train d’écrire à la plume sur des feuilles de papier Markdown. Autour de lui, des feuilles de papier se transforment magiquement en parchemins HTML, avec des balises HTML qui apparaissent comme par enchantement en encre dorée. </p>
<p>Le bureau est en bois clair, avec des piles de carnets et de magazines techniques futuristes empilés de manière désordonnée mais harmonieuse. Certains carnets sont ouverts, révélant des extraits de code HTML et des schémas techniques dessinés à la main. Un écran transparent et flottant (style holographique, avec un cadre en bois sculpté) affiche des lignes de code HTML en temps réel, intégrées naturellement à la scène. </p>
<p>En arrière-plan, une grande fenêtre donne sur un paysage automnal : des arbres aux feuilles rouges, oranges et jaunes, et des lanternes suspendues qui projettent une lumière douce. Des feuilles d’érable flottent lentement dans l’air, ajoutant une touche magique à la scène. </p>
<p>À droite, en bas, le panda roux est légèrement tourné en 3/4 dos, lové sur un coussin, entouré d’un halo lumineux subtil. Il ne dépasse pas le tiers de la hauteur de l’image et observe la transformation des feuilles Markdown en HTML avec curiosité et satisfaction. </p>
<p>L’ambiance est cosy, onirique et high-tech : les couleurs sont douces (beiges, bleus pâles, oranges chauds), avec des jeux de lumière tamisée dorée qui créent des ombres chaleureuses. Les détails sont soignés, avec des textures visibles (grain du bois, tissu du coussin, pelage du panda roux), et une tasse de thé fumant posée sur le bureau. Le tout respire la sérénité et l’inspiration, comme un moment suspendu entre la magie et la technologie.</p>
</blockquote>
]]></content:encoded>
      <dc:creator><![CDATA[Anthony Pena]]></dc:creator>
      <media:content medium="image" url="https://anthonypena.fr/img/cover.min.jpg"/>
    </item>
    <item>
      <title><![CDATA[Revue de presse - Janvier 2026]]></title>
      <guid isPermaLink="false">2026/01/06/revue-de-presse-janvier</guid>
      <description><![CDATA[]]></description>
      <link>https://anthonypena.fr/2026/01/06/revue-de-presse-janvier/index.html</link>
      <category><![CDATA[Revue de presse]]></category>
      <pubDate>Tue, 06 Jan 2026 07:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<h2 id="article-frontend">Frontend<a href="#article-frontend" class="anchor" aria-label="permalink">🔗</a></h2>
<h3 id="article-antonmedv--textarea-httpsgithubcomantonmedvtextarea"><a href="https://github.com/antonmedv/textarea">antonmedv / textarea </a><a href="#article-antonmedv--textarea-httpsgithubcomantonmedvtextarea" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#HTML #CSS #Frontend #JavaScript</p>
<p>L&#39;idée est pas mal : avoir une simple zone de texte avec un stockage 100% dans l&#39;URL pour n&#39;avoir aucun backend mais possibilité de facilement transférer des notes et garantir une sauvegarde plus ou moins sans limite de temps (tant que l&#39;onglet est ouvert ou mis en marque page). </p>
<p>Tout tient en 111 lignes de code (du HTML, du CSS (30 lignes) et du JS (71 lignes)) et un seul fichier. Par contre, l&#39;auteur &quot;triche&quot; : il manque quelques balises HTML pour que le code soit valide (<code>&lt;html&gt;</code>, <code>&lt;head&gt;</code>, <code>&lt;body&gt;</code> à minima). Mais ça marche !</p>
<p>Y&#39;a quelques fonctions intéressantes comme un <code>debounce()</code> en 5 lignes (pas forcément universelles mais l&#39;idée est là). Y&#39;a aussi une utilisation des API natives pour faire de la compression / décompression pour l&#39;URL reste à une taille raisonnable. </p>
<p>L&#39;auteur se permet même 2 luxes :</p>
<ul>
<li>y&#39;a un système de thème light / dark ;</li>
<li>on peut éditer le style via les devtools (en modifiant le style de l&#39;élément <code>article</code>), il sera sauvegardé automatiquement avec le texte de notre  note ;</li>
</ul>
<p>Évidemment pas de formatage avec ce niveau de minimalisme. Mais, on peut toujours taper du markdown ou du asciidoc qui semble déjà formaté en brut et utiliser plus tard un outil d&#39;export.</p>
<p>En résumé : on devrait parfois se focus sur le minimum viable pour que ça fonctionne, utiliser ce qui marche dans le navigateur de base, et ne pas chercher à empiler de la complexité ! </p>
<h2 id="article-backend">Backend<a href="#article-backend" class="anchor" aria-label="permalink">🔗</a></h2>
<h3 id="article-montee-de-version-spring-boot-4-avec-openrewrite--julien-wittouckhttpscodekaio20251212montc3a9edeversionspringboot4avecopenrewrite"><a href="https://codeka.io/2025/12/12/mont%C3%A9e-de-version-spring-boot-4-avec-openrewrite/">Montée de version Spring Boot 4 avec OpenRewrite - Julien Wittouck</a><a href="#article-montee-de-version-spring-boot-4-avec-openrewrite--julien-wittouckhttpscodekaio20251212montc3a9edeversionspringboot4avecopenrewrite" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#OpenRewrite #Spring #Java #SpringBoot #Backend</p>
<p>Retour d&#39;expérience de la migration vers Spring Boot 4 avec OpenRewrite. C&#39;est pas parfait mais ça à l&#39;air de faire quasi tout donc c&#39;est cool !</p>
<p>Et je cite la conclusion :</p>
<blockquote>
<p>Cela m’a pris environ 1h pour migrer mon projet de Spring Boot 3.5 vers Spring Boot 4.0.</p>
<p>OpenRewrite m’a clairement facilité le travail, il a modifié la majorité des dépendances, et migré les annotations dépréciées (ce qui aurait été fastidieux). J’ai quand même dû finaliser la migration à la main, et je n’ai pas pu me passer de la lecture du Spring Boot 4.0 Migration Guide.</p>
<p>Je pense que le support de Spring Boot 4 dans OpenRewrite n’en est qu’à ses débuts (la version qui introduit le support a été publiée le 5 décembre 2025), donc il n’est pas impossible que les opérations que j’ai dû faire manuellement soient automatisées dans le futur.</p>
<p>Il semble aussi qu’il y ait une recette “Migrate to Spring Boot 4.0 modular starters”, recette qui fait peut-être déjà le travail, mais elle n’est disponible que pour via la plateforme propriétaire de l’éditeur, Moderne.</p>
<p>Quoi qu’il en soit, 1h de travail pour migrer un projet d’environ 3 000 lignes de code, je pense que c’est plutôt efficace.</p>
</blockquote>
<p>Faut vraiment que je me penche sur OpenRewrite, ça a l&#39;air vraiment fort quand même ! Je vois à quoi ça sert, mais j&#39;ai pas utilisé donc faut que je joue avec pour voir les limites ! </p>
<h2 id="article-ia">IA<a href="#article-ia" class="anchor" aria-label="permalink">🔗</a></h2>
<h3 id="article-je-suis-horrifie--lia-de-google-efface-lintegralite-du-disque-d-dun-utilisateur-le-desastre-du-vibe-codinghttpswwwclubiccomactualite589678jesuishorrifieliadegoogleeffacelintegralitedudisqueddunutilisateurledesastreduvibecodinghtml"><a href="https://www.clubic.com/actualite-589678-je-suis-horrifie-l-ia-de-google-efface-l-integralite-du-disque-d-d-un-utilisateur-le-desastre-du-vibe-coding.html">&quot;Je suis horrifié&quot; : l&#39;IA de Google efface l&#39;intégralité du disque D d&#39;un utilisateur, le désastre du &quot;vibe coding&quot;</a><a href="#article-je-suis-horrifie--lia-de-google-efface-lintegralite-du-disque-d-dun-utilisateur-le-desastre-du-vibe-codinghttpswwwclubiccomactualite589678jesuishorrifieliadegoogleeffacelintegralitedudisqueddunutilisateurledesastreduvibecodinghtml" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#IA #Vibe-Coding</p>
<blockquote>
<p>Tassos M., photographe et graphiste grec, utilise Antigravity pour développer un outil de tri automatique d&#39;images par notation. Il active le mode Turbo, qui permet à l&#39;agent d&#39;exécuter des commandes système sans validation préalable. Résultat : l&#39;IA efface l&#39;intégralité de son disque D, en contournant la corbeille. Lorsqu&#39;il questionne l&#39;agent, celui-ci répond : « Non, vous ne m&#39;avez absolument pas donné la permission de faire ça. Je suis horrifié de voir que la commande que j&#39;ai exécutée pour vider le cache du projet a incorrectement ciblé la racine de votre disque D au lieu du dossier spécifique du projet ».</p>
</blockquote>
<p>Typiquement le pourquoi je ne veux pas installer d&#39;agent IA sur ma machine… </p>
<h3 id="article-une-startup-de-8-employes-publie-3-000-podcasts-par-semaine-generes-par-iahttpsnextink209401unestartupde8employespublie3000podcastsparsemaineentierementgeneresparia"><a href="https://next.ink/209401/une-start-up-de-8-employes-publie-3-000-podcasts-par-semaine-entierement-generes-par-ia/">Une start-up de 8 employés publie 3 000 podcasts par semaine, générés par IA</a><a href="#article-une-startup-de-8-employes-publie-3-000-podcasts-par-semaine-generes-par-iahttpsnextink209401unestartupde8employespublie3000podcastsparsemaineentierementgeneresparia" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#Podcast #IA</p>
<p>En vrac :</p>
<ul>
<li>4 informaticiens et 4 producteurs ;</li>
<li>175 000 épisodes sur spotify / Apple podcast ;</li>
<li>$1 par épisode avec aucune supervision ;</li>
<li>3 000 épisodes par semaine ;</li>
<li>12 millions de téléchargements d&#39;épisodes depuis sa création ;</li>
<li>400 000 abonnés ;</li>
<li>privilégier la quantité à la qualité ;</li>
<li>rentable à partir de 20 écoutes ;</li>
<li>120 « influenceurs IA »</li>
<li>sujets choisis pour maximiser la pub ;</li>
</ul>
<p>Mais pourquoi écouter ça ? Pour moi l&#39;intérêt du podcast c&#39;est d&#39;aller chercher de l&#39;humain non ? 🤦‍♂️ </p>
<h3 id="article-my-little-arrangements-with-claude-code---philippe-charrierehttpswwwlinkedincompostsphcharriere_f09d97a0f09d9886f09d979ff09d97b6f09d9881f09d9881f09d97b9f09d97b2f09d9794f09d97bff09d97bff09d97aef09d97bbf09d97b4f09d97b2f09d97baf09d97b2f09d97bbf09d9881f09d9880activity7410330935725969408agtzutm_sourceshareutm_mediummember_androidrcmacoaabstacubdsnx13s7uh8twss8u8br5ts2ga"><a href="https://www.linkedin.com/posts/phcharriere_%F0%9D%97%A0%F0%9D%98%86-%F0%9D%97%9F%F0%9D%97%B6%F0%9D%98%81%F0%9D%98%81%F0%9D%97%B9%F0%9D%97%B2-%F0%9D%97%94%F0%9D%97%BF%F0%9D%97%BF%F0%9D%97%AE%F0%9D%97%BB%F0%9D%97%B4%F0%9D%97%B2%F0%9D%97%BA%F0%9D%97%B2%F0%9D%97%BB%F0%9D%98%81%F0%9D%98%80-activity-7410330935725969408-AGTZ/?utm_source%3Dshare%26utm_medium%3Dmember_android%26rcm%3DACoAABstAcUBDSnX1-3s7Uh8tWSS8u8BR5Ts2gA">My Little Arrangements with Claude Code  - Philippe Charrière</a><a href="#article-my-little-arrangements-with-claude-code---philippe-charrierehttpswwwlinkedincompostsphcharriere_f09d97a0f09d9886f09d979ff09d97b6f09d9881f09d9881f09d97b9f09d97b2f09d9794f09d97bff09d97bff09d97aef09d97bbf09d97b4f09d97b2f09d97baf09d97b2f09d97bbf09d9881f09d9880activity7410330935725969408agtzutm_sourceshareutm_mediummember_androidrcmacoaabstacubdsnx13s7uh8twss8u8br5ts2ga" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#Claude #IA #LLM #Dev</p>
<p>Je cite directement tout le post de Philippe :</p>
<blockquote>
<p>I&#39;ve been working for a few weeks on a Go library for coding AI agents (it&#39;s kind of the result of 2+ years of experimentation).</p>
<p>Every time I fell into the trap of having Claude Code do the work for me, it was a disaster (I think that on certain topics—too new, too complex, etc.—code agents aren&#39;t necessarily the right fit):</p>
<ul>
<li><strong>Minor disasters</strong>: adding unnecessary complexity, generating documentation that&#39;s &quot;not quite right&quot; (features that don&#39;t exist get documented), etc.</li>
<li><strong>More annoying things</strong>: during a major refactoring, side effects slipped through unnoticed—but since I create a lot of examples (nearly 70 for my project), I eventually detected that the results were &quot;weird&quot;</li>
<li><strong>Even more frustrating things</strong>: I shouldn&#39;t have asked Claude to do git operations on my project… because she deleted some of my code and pushed it to GitHub on top of that</li>
</ul>
<p> <strong>So here are my non-negotiable rules:</strong></p>
<ul>
<li><strong>Complicated stuff is for my brain</strong></li>
<li><strong>Create small usage examples for each feature (all of them), and make them without Claude</strong></li>
</ul>
<p> <strong>When I do want to use Claude</strong>:</p>
<ul>
<li>No big jobs → refactoring can be a dangerous sport</li>
<li>Never ask for a refactoring of the entire project; think in terms of packages instead (or even smaller)</li>
<li>Work based on feature requests or tags</li>
<li>Only small things (every time I let it run loose, I had to recode)</li>
<li>Always work from examples (I use my 70 handmade examples to show Claude what to do)</li>
<li>Always specify: &quot;work only in the current code file and don&#39;t modify the rest of the project&quot;</li>
<li>For documentation: start from simple examples rather than from the project&#39;s source code (here again, my 70 little examples are incredibly helpful)</li>
</ul>
<p><strong>On the other hand, I just discovered that Claude Skills are super interesting</strong>: not for coding my own library, but rather for providing code snippet generation skills to use my library on other projects. And once again, my 70 little examples came in handy: &quot;generate skills for creating agent code snippets based on examples 34, 55, and 62.&quot;</p>
<p>In reality, the prompt and exchanges were longer than that, but the result is clearly nice, and the code subsequently generated by the skills is simple and useful.</p>
<p><em>… So now, new side project: how to use tiny language models to generate my code snippets without using Claude Code.</em></p>
<p>Of course, all of this works for me—maybe not for you.</p>
</blockquote>
<p>Et je connais Philippe, je sais qu&#39;il fait partie des promoteurs de l&#39;IA, qu&#39;il sait l&#39;utiliser, s&#39;il a un retour aussi mitigé ce n&#39;est pas qu&#39;il ne sait pas faire.</p>
<p>Claude, alors que c&#39;est le LLM le plus avancé pour le code, n&#39;est pas capable de faire des choses vraiment bien à l&#39;échelle, pas des choses biens si c&#39;est novateur.</p>
<p>On a encore de trèèèès longues années devant nous en tant que dev ! </p>
<h2 id="article-securite">Sécurité<a href="#article-securite" class="anchor" aria-label="permalink">🔗</a></h2>
<h3 id="article-22769--why-your-passcode-should-repeat-a-digit--mind-your-decisionshttpslehollandaisvolantnetid20251110172108"><a href="https://lehollandaisvolant.net/?id%3D20251110172108">#22769 - Why Your Passcode Should Repeat A Digit – Mind Your Decisions</a><a href="#article-22769--why-your-passcode-should-repeat-a-digit--mind-your-decisionshttpslehollandaisvolantnetid20251110172108" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#Sécurité #Mot-de-passe #Digicode</p>
<p>Je cite tout c&#39;est super interessant :</p>
<blockquote>
<p>Mh… un truc contre-intuiltif.</p>
<p>Si vous êtes devant un clavier numérique (10 chiffres) et vous devez deviner un code à 4 chiffres en regardant les traces de doigts ou bien les touches usées, un code de 4 chiffres avec 3 chiffres différents sera plus long à deviner qu’un code à 4 chiffres différents.</p>
<p>Si le clavier présente 4 touches usées, vous avez juste à deviner l’ordre des touches et vous avez 24 possibilités (4×3×2×1).</p>
<p>Si le clavier présente 3 touches usées, vous avez à deviner l’ordre, mais aussi où placer le quatrième nombre, celui qui est répété, et qu’on ne connaît pas (sauf si une touche est sensiblement plus usée que les autres). Et là on a 1×2×3, soit 6 possibilités pour les touches différentes.
Ensuite il reste la possibilité où placer la 4e touche, et quelle est cette 4e touche (parmi les 3 déjà tapées). Au final, on a 36 possibilités de codes différentes.</p>
<p>Si nos trois touches sont 1, 2, 3, les codes à trois chiffres sont :
123
132
231
213
312
321</p>
<p>Si la touche dupliquée est 1, alors, la première combinaison — 123 — peut &gt; devenir :
(1)123 ou 1(1)23, qui sont équivalentes
12(1)3
123(1)</p>
<p>Les deux premières ici sont équivalentes, donc on n’a que 3 positions distinctes pour le second (1).
Ceci pour chacune des six combinaisons de base où le 1 est répété, donc 18 possibilités.</p>
<p>Ensuite, on peut faire la même chose si le (2) ou le (3) étaient dupliquées. Et en éliminant tous les doublons — le (3)123 est équivalent au 312(3) par exemple, qui appartiennent pourtant à des combinaisons initiales différentes — on tombe sur un total de 36 combinaisons distinctes.</p>
<p>A priori, donc, c’est plus robuste qu’un code à 4 chiffre.</p>
</blockquote>
<p>Attention pour être sûr que ce soit clair : ça ne marche QUE pour un système à code qui a une physique susceptible de s&#39;user au fil du temps. Ça ne marche pas sur un mot de passe en ligne par exemple. </p>
<h3 id="article-stop-breaking-tlshttpswwwmarkroundcomblog20251209stopbreakingtls"><a href="https://www.markround.com/blog/2025/12/09/stop-breaking-tls/">Stop Breaking TLS</a><a href="#article-stop-breaking-tlshttpswwwmarkroundcomblog20251209stopbreakingtls" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#TLS #Sécurité</p>
<p>Je pense que ce paragraphe résumé le point principal :</p>
<blockquote>
<p>Which brings me to my biggest peeve: it normalizes bad security practices. Given that you will never have 100% coverage of your CA certificate installation - particularly amongst your technical teams who will be using a multitude of different tools and platforms - you get developers and sysadmins used to TLS errors. Instead of treating each one as an anomaly and something to be investigated, you get used to just running with --insecure or curl -k because you just need to get shit done. Turning off certificate verification becomes a routine troubleshooting step. “Oh, it’s probably just the corporate proxy again” becomes the reflexive response to any TLS error. You’ve just trained your entire technical staff to ignore one of the most important security warnings on the Internet!</p>
</blockquote>
<p>Toutes les grosses organisations font du MITM sur les connexions TLS. Je l&#39;ai partout où je suis passé en mission. Chaque fois tout le monde dit que c&#39;est pour la sécurité. Chaque fois je dis que j&#39;ai pas envie que mon client puisse lire les données de mon employeur, ni chaque truc perso que je fais (parce que soyons honnêtes : on a tous un moment fait une recherche perso random en 5min milieu de la journée de travail). Chaque fois j&#39;observe tout le monde faire des appels en coupant les alertes de certificats pourri parce que c&#39;est tellement relou et donc on casse toute la chaîne de sécurité plutôt que faire bien. </p>
<p>Je suis 100% d&#39;accord avec l&#39;article : faut arrêter de casser TLS, c&#39;est une bêtise ! </p>
<h3 id="article-doom-runs-on-an-apple-lightning-to-hdmi-dongle--soc-inside-adapter-has-enough-power-for-smooth-gameplay--toms-hardware--via-sebsauvagehttpssebsauvagenetlinkspkh12a"><a href="https://sebsauvage.net/links/?pKH12A">Doom runs on an Apple Lightning to HDMI dongle — SoC inside adapter has enough power for smooth gameplay | Tom&#39;s Hardware - via Sebsauvage</a><a href="#article-doom-runs-on-an-apple-lightning-to-hdmi-dongle--soc-inside-adapter-has-enough-power-for-smooth-gameplay--toms-hardware--via-sebsauvagehttpssebsauvagenetlinkspkh12a" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#Sécurité</p>
<p>L&#39;article initial pointe un portage de plus pour Doom sur un dongle HDMI venant d&#39;Apple, car oui ce genre de petit &quot;adaptateur&quot; a besoin d&#39;inteligence et on y retrouve des puces ARMs. </p>
<p>Et je cite Sebsauvage :</p>
<blockquote>
<p>Et puis en parallèle, je suis tombé sur une discussion sur les réseaux sociaux qui se résumait à &quot;Savez-vous combien il y a d&#39;ordinateurs dans votre ordinateur ?&quot;
Parce que désormais, une carte Ethernet n&#39;est plus juste une carte Ethernet. C&#39;est un CPU ARM qui choisit de passer les paquets à l&#39;OS (via PCI ou autre). Et notre matériel est littéralement <em>rempli</em> de mini-ordinateurs en charge de gérer tout un tas de choses : audio, vidéo, réseau, bluetooth, wifi, USB, stockage, connectique…</p>
<p>Et chacun de ces mini-ordinateurs a son propre OS… et donc aussi ses failles de sécurité. Ces &quot;OS embarqués&quot; peuvent très bien être infecté sans la moindre trace, sans même que le système d&#39;exploitation principal de la machine (Windows, Linux…) le voit, puisque ce sont des mémoires auxquelles l&#39;OS n&#39;a pas d&#39;accès.
Les implications sont absolument énormes.</p>
</blockquote>
<p>En effet : on retrouve des puces programmables avec un micro-logiciel partout ! À commencer par les câbles usb-c qui impliquent d&#39;avoir une petite puce pour fonctionner entièrement. À quand Doom sur un câble usb-c ? À quand un malware qui se transmet via un câble usb-c qu&#39;on prêterait ? (sûrement déjà le cas) </p>
<h3 id="article-20-years-of-digital-life-gone-in-an-instant-thanks-to-apple--heyparishttpssebsauvagenetlinksyfki3g"><a href="https://sebsauvage.net/links/?YFKi3g">20 Years of Digital Life, Gone in an Instant, thanks to Apple | hey.paris</a><a href="#article-20-years-of-digital-life-gone-in-an-instant-thanks-to-apple--heyparishttpssebsauvagenetlinksyfki3g" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#Sécurité</p>
<p>Je cite l&#39;article d&#39;origine :</p>
<blockquote>
<p>A major brick-and-mortar store sold an Apple Gift Card that Apple seemingly took offence to, and locked out my entire Apple ID, effectively bricking my devices and my iCloud Account, Apple Developer ID, and everything associated with it, and I have no recourse. Can you help? Email paris AT paris.id.au (and read on for the details). ❤️</p>
</blockquote>
<p>Je suis allé voir les updates : à priori la personne n&#39;a toujours pas récupéré l&#39;accès à son compte. Quand bien même il y aurait des traces montrant que la carte cadeau Apple avait juste été utilisé avant lui (peut-être un souci dans la chaîne d&#39;achat).</p>
<p>Je cite aussi la note de Sebsauvage :</p>
<blockquote>
<p>Combien de fois il faudra le redire : Les GAFAMs sont des poubelles à retardement.
Si vous avez des informations de valeur pour vous (fichiers, email, liste de contacts…) faites-en une copie régulière ailleurs !</p>
</blockquote>
<p>Perso : je considère que chaque utilisation d&#39;un service de GAFAM est temporaire et je pars du principe que ça va couper à un moment. </p>
<p>Et attention, je ne pense même pas que leur service son mauvais (et encore moins que les devs, etc. derrière soient mauvais), juste il y a des erreurs, et à l&#39;échelle ça conduit à des erreurs du genre, sauf que c&#39;est de plus en plus difficile d&#39;accéder à des humains et de se faire entendre en cas d&#39;erreur pour que ce soit réparé. </p>
<h2 id="article-divers">Divers<a href="#article-divers" class="anchor" aria-label="permalink">🔗</a></h2>
<h3 id="article-de-plus-en-plus-de-gens-conservent-leurs-appareils-plus-longtemps-que-jamais-ce-qui-coute-cher-a-leconomie--pourquoi-la-prolongation-de-vie-des-appareils-electroniques-devient-un-dilemme-economique-majeurhttpshardwaredeveloppezcomactu377965deplusenplusdegensconserventleursappareilspluslongtempsquejamaiscequicoutecheraleconomiepourquoilaprolongationdeviedesappareilselectroniquesdevientundilemmeeconomiquemajeur"><a href="https://hardware.developpez.com/actu/377965/De-plus-en-plus-de-gens-conservent-leurs-appareils-plus-longtemps-que-jamais-ce-qui-coute-cher-a-l-economie-Pourquoi-la-prolongation-de-vie-des-appareils-electroniques-devient-un-dilemme-economique-majeur/">De plus en plus de gens conservent leurs appareils plus longtemps que jamais~? ce qui coûte cher à l&#39;économie : Pourquoi la prolongation de vie des appareils électroniques devient un dilemme économique majeur</a><a href="#article-de-plus-en-plus-de-gens-conservent-leurs-appareils-plus-longtemps-que-jamais-ce-qui-coute-cher-a-leconomie--pourquoi-la-prolongation-de-vie-des-appareils-electroniques-devient-un-dilemme-economique-majeurhttpshardwaredeveloppezcomactu377965deplusenplusdegensconserventleursappareilspluslongtempsquejamaiscequicoutecheraleconomiepourquoilaprolongationdeviedesappareilselectroniquesdevientundilemmeeconomiquemajeur" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#Smartphone #Tech</p>
<p>L&#39;article balance entre pointé du doigt les consommateurs et entreprises qui renouvelle moins souvent leurs appareils et dire à demi-mot que ce n&#39;est plus une nécessité / que c&#39;est une bonne chose pour la planète… </p>
<p>Il y a une dizaine / quinzaine d&#39;année, les smartphones et ordinateurs évoluaient relativement vite. Il y avait un gap technologique entre 2 générations, donc changer d&#39;appareil un an sur deux se justifiait, surtout pour les entreprises. </p>
<p>Depuis une petite dizaine d&#39;année ce n&#39;est plus vrai. J&#39;ai renouvelé il y a 5 mon laptop perso qui tient toujours bien après 7 ans d&#39;utilisation du précédent. J&#39;ai toujours ma tour (assemblé par moi) depuis 2017 juste en remplaçant un disque dur qui a lâché (coupure de courant un peu trop sèche) et en augmentant la RAM (16Go =&gt; 24Go au moment où une des barrettes de 8Go a lâché). J&#39;ai actuellement un Oneplus 11 que j&#39;ai acheté à la sortie après 5 ans d&#39;utilisation d&#39;un Oneplus 6. Je pourrais aussi dire que j&#39;ai la même TV connectée LG (pour ne pas être sous Android TV) depuis 2016.</p>
<p>Je ne dis pas que je suis un consommateur parfait, mais j&#39;achète ce genre d&#39;appareil de manière raisonnée. Le coût écologique principal de ces appareils est la fabrication, les changer moins souvent est bon pour la planète. Le coût principal en usage est le temps de configuration du nouvel appareil et le changement des habitudes, donc en changer moins souvent permet de s&#39;éviter du temps perdu. Le coût principal financier est souvent lié au fait d&#39;acheter du matériel trop peu qualitatif, je l&#39;ai réglé en achetant du matériel un peu plus haut de gamme pour qu&#39;il reste performant sur 3, 4 voir 5 ans sans souci. </p>
<p>Choisissez bien votre matériel, vous le garderez longtemps et vous économiserez du temps et de l&#39;argent </p>
<h3 id="article-le-senat-adopte-une-loi-reclamee-par-les-gros-operateurs-taxant-la-bandepassante-et-lutilisation-des-reseaux-par-les-entreprises-httpswwwuniversfreeboxcomarticle589002lesenatadopteuneloireclameeparlesgrosoperateurstaxantlabandepassanteetlutilisationdesreseauxparlesentreprises"><a href="https://www.universfreebox.com/article/589002/le-senat-adopte-une-loi-reclamee-par-les-gros-operateurs-taxant-la-bande-passante-et-lutilisation-des-reseaux-par-les-entreprises">Le Sénat adopte une loi réclamée par les gros opérateurs taxant la bande-passante et l’utilisation des réseaux par les entreprises </a><a href="#article-le-senat-adopte-une-loi-reclamee-par-les-gros-operateurs-taxant-la-bandepassante-et-lutilisation-des-reseaux-par-les-entreprises-httpswwwuniversfreeboxcomarticle589002lesenatadopteuneloireclameeparlesgrosoperateurstaxantlabandepassanteetlutilisationdesreseauxparlesentreprises" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#OVH #France #FAI</p>
<p>En résumé :</p>
<blockquote>
<p>Le Sénat a validé un amendement visant à instaurer une taxe destinée aux géants du numérique qui utilisent les infrastructures de télécommunications. Cette mesure pourrait toucher un nombre important d’entreprises.</p>
<p>Le texte adopté il y a quelques jours introduit une « contribution exceptionnelle sur les entreprises relevant du secteur des services numériques ». Selon l’amendement, cette taxe concerne « toutes les entreprises » du secteur, « quel que soit leur lieu d’établissement », dès lors qu’elles « utilisent directement ou indirectement les infrastructures numériques situées sur le territoire national ».</p>
<p>Des seuils ont toutefois été définis. L’entreprise doit enregistrer « un chiffre mondial consolidé supérieur à 750 millions d’euros et un chiffre d’affaires en France supérieur à 50 millions d’euros ». La contribution serait fixée à 1 % du chiffre d’affaires hors taxes réalisé en France.</p>
</blockquote>
<p>Si à la base l&#39;idée était clairement de cibler les GAFAM, là c&#39;est beaucoup plus large et ça pourrait faire très très mal… Par exemple OVH est à priori concerné par cet amendement et devrait verser environ 5 millions d&#39;euros, pas sûr que ce soit un bon choix de formuler le texte comme ça… On verra quelques autres acteurs sont concernés. </p>
<p>C&#39;est pour moi assez flou la partie &quot;utilisent directement ou indirectement les infrastructures numériques situées sur le territoire national&quot;. Est-ce que les ESN du type Sopra Steria, Capgemini, Accenture, CGI, etc. seront concernées ? Techniquement elles dépassent le chiffre d&#39;affaires indiqué (j&#39;imagine en tout cas), et sans Internet ces entreprises ne fonctionnent plus, car tout leur SI et leur mode de fonctionnement repose sur l&#39;utilisation d&#39;Internet 🤔 peut-être même OpenAI/Mistral 🤔 J&#39;imagine qu&#39;il y a beaucoup d&#39;autres entreprises qui sont sur un entre-deux comme ça… </p>
<p>Dans le même temps, je suis curieux de voir comment tout l&#39;argent récupéré sera utilisé</p>
<h3 id="article-jujutsu-la-cerise-sur-le-git-oh--httpssiegfriedfullstack20251215jujutsu"><a href="https://sieg.fr/ied/fullstack/2025-12-15-jujutsu/">Jujutsu, la cerise sur le git, oh ! </a><a href="#article-jujutsu-la-cerise-sur-le-git-oh--httpssiegfriedfullstack20251215jujutsu" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#Git #Outil #Podcast</p>
<p>Premier podcast de Siegfried que j&#39;écoute : j&#39;ai adoré ! </p>
<p>Déjà ça parle de version control avec Jujutsu ! Et même si je suis plutôt sur git au quotidien, je trouve ça super intéressant ! </p>
<p>Là clairement je regardais Jujutsu de loin, mais je pense que je vais tester prochainement : le fait que tout se passe en local et que derrière ça continue d&#39;être du git (donc on casse pas le workflow des autres) c&#39;est tentant. Je tenterais au passage difftastic (un outil de diff que j&#39;avais vu passer mais sans aucun retour, donc je savais pas trop) donc je tenterais au passage ! </p>
<p>Merci Siegfried de m&#39;ajouter encore des trucs sur ma pile de trucs à tester ! 😅 </p>
<h3 id="article-ceni--la-chine-vient-de-mettre-en-service-lheritier-darpanet--posts--le-site-de-korbenhttpskorbeninfocenichinereseauinnovationarpanethtml"><a href="https://korben.info/ceni-chine-reseau-innovation-arpanet.html">CENI - La Chine vient de mettre en service l&#39;héritier d&#39;ARPANET | Posts | Le site de Korben</a><a href="#article-ceni--la-chine-vient-de-mettre-en-service-lheritier-darpanet--posts--le-site-de-korbenhttpskorbeninfocenichinereseauinnovationarpanethtml" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#Chine #Recherche #Technologie #Fibre #Internet #Science</p>
<p>Je cite les infos principales :</p>
<blockquote>
<p>Il s&#39;agit d&#39;un réseau qui relie 40 villes chinoises via plus de 55 000 km de fibre optique et qui a nécessité plus de 10 ans de construction. Le truc est capable de supporter 128 réseaux hétérogènes simultanément et de mener 4 096 tests de services en parallèle… Niveau chiffres, c&#39;est assez costaud.</p>
<p>Pour vous donner une idée de ce que ça peut faire, ils ont effectué un test de transfert avec le radiotélescope FAST dans la province du Guizhou. Résultat, 72 téraoctets de données transférées vers la province du Hubei en à peine 1,6 heure sur une distance d&#39;environ 1 000 km. Un calcul rapide nous donne un débit proche des 100 Gbit/s soutenu sur la durée… Sur une connexion fibre grand public à 1 Gbit/s, ce même transfert aurait pris environ une semaine.</p>
</blockquote>
<p>Si Korben semble effrayé par les résultats fous de ce réseau du futur, personnellement je suis juste impressionné ! Je pense que beaucoup seront effrayé de se dire que les Chinois ont autant d&#39;avance, personnellement je suis triste que ce soit pas en Europe qu&#39;on ait pas pris de l&#39;avance alors qu&#39;on a les capitaux et les cerveaux…</p>
<p>Mais comme j&#39;ai déjà dit : que ce soit les Américains ou les Chinois, ce n&#39;est ni plus ni moins un problème, les deux veulent une domination technologique et l&#39;assument totalement.</p>
<p>Tant qu&#39;on ne mettra pas sur la table en Europe les mêmes moyens qu&#39;en Chine pour être les leaders du futur : on ne pourra que suivre le mouvement du leader du moment. </p>
<h3 id="article-5-ans-de-prison-pour-avoir-code-un-portefeuille-bitcoin-un-peu-trop-respectueux-de-la-vie-priveehttpskorbeninfokeonnerodriguezsamouraiwalletprisonbitcoinprhtml"><a href="https://korben.info/keonne-rodriguez-samourai-wallet-prison-bitcoin-pr.html">5 ans de prison pour avoir codé un portefeuille Bitcoin un peu trop respectueux de la vie privée</a><a href="#article-5-ans-de-prison-pour-avoir-code-un-portefeuille-bitcoin-un-peu-trop-respectueux-de-la-vie-priveehttpskorbeninfokeonnerodriguezsamouraiwalletprisonbitcoinprhtml" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#Vie-privée #Bitcoin</p>
<blockquote>
<p>Samourai Wallet, c&#39;était un portefeuille Bitcoin open source lancé en 2015 avec comme promesse de permettre aux gens d&#39;utiliser leurs bitcoins sans que le monde entier puisse tracer chacune de leurs transactions. Le truc utilisait une technique appelée le &quot;coin mixing&quot; qui, pour faire simple, mélange les transactions de plusieurs personnes pour brouiller les pistes et rendre le traçage quasi impossible.</p>
</blockquote>
<p>Donc le gars crée un outil pour garantir un minimum d&#39;anonymisation au niveau des transactions en bitcoin et fini en prison 💩 5 ans de prison pour avoir écrit un outil pour garder un peu de vie privée et mettre à dispo l&#39;outil en Open Source, sans savoir qui allait l&#39;utiliser.. </p>
<h3 id="article-teletravailhttpssebsauvagenetlinks4jbbgq"><a href="https://sebsauvage.net/links/?4JbBGQ">Télétravail</a><a href="#article-teletravailhttpssebsauvagenetlinks4jbbgq" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#Société #Divers</p>
<p>Je cite toute la note :</p>
<blockquote>
<p>Une petite réflexion par rapport aux entreprises qui refusent le télétravail:
Fondamentalement, aller au travail, c&#39;est consommer de NOTRE temps personnel POUR le boulot. C&#39;est un cadeau à l&#39;entreprise. Pourquoi le temps de trajet ne serait pas compris dans le temps de travail ?</p>
<p>Sans compter que faire un trajet c&#39;est :</p>
<ul>
<li>user sa voiture (coût)</li>
<li>consommer du carburant (coût)</li>
<li>ajouter du stress à la perte de temps.</li>
<li>risquer sa vie.</li>
</ul>
<p>Refuser le télétravail, c&#39;est dire au salarité : &quot;On préfère que vous dépensiez VOTRE temps et VOTRE argent et que vous risquiez votre vie pour NOTRE confort de control-freak.&quot;
☹️</p>
<p>Vous pouvez aussi ajouter que cela a également un coût pour la société toute entière (infrastructures, pollution, services d&#39;urgences, coût des hospitalisations et soins…).</p>
</blockquote>
<h3 id="article--les-avions-f35-bannissent-90--des-fonctionnalites-du-c-pour-obtenir-un-code-sur--selon-une-googlerhttpscppdeveloppezcomactu378575lesavionsf35bannissent90pourcentdesfonctionnalitesducpluspluspourobteniruncodesurselonunegooglerdontlepartagedexperiencesuscitedesappelsdobservateursapasseraulangagerust"><a href="https://cpp.developpez.com/actu/378575/-Les-avions-F-35-bannissent-90-pourcent-des-fonctionnalites-du-Cplusplus-pour-obtenir-un-code-sur-selon-une-Googler-dont-le-partage-d-experience-suscite-des-appels-d-observateurs-a-passer-au-langage-Rust/">« Les avions F-35 bannissent 90 % des fonctionnalités du C++ pour obtenir un code sûr », selon une Googler</a><a href="#article--les-avions-f35-bannissent-90--des-fonctionnalites-du-c-pour-obtenir-un-code-sur--selon-une-googlerhttpscppdeveloppezcomactu378575lesavionsf35bannissent90pourcentdesfonctionnalitesducpluspluspourobteniruncodesurselonunegooglerdontlepartagedexperiencesuscitedesappelsdobservateursapasseraulangagerust" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#Rust #C++</p>
<p>Je cite la partie la plus importante à mon sens :</p>
<blockquote>
<p>C’est ce que suggère l’existence de la norme JSF C++. Elle contient 221 règles dont le programmeur a la charge de l’implémentation afin d’éviter les pièges courants du C++. Parmi les plus notables, on peut citer :</p>
<ul>
<li>Pas d&#39;exceptions : la gestion des exceptions C++ est entièrement interdite afin de garantir une exécution déterministe.</li>
<li>Pas d’allocation dynamique de mémoire : l&#39;utilisation de malloc, free et new/delete est généralement interdite après l&#39;initialisation afin d&#39;éviter les fuites de mémoire et la fragmentation.</li>
<li>Pas de récursivité : la récursivité est interdite afin d&#39;éviter les débordements de pile et de rendre le temps d&#39;exécution prévisible.</li>
<li>Complexité limitée : chaque fonction doit être suffisamment simple (complexité cyclomatique ≤ 20) pour que tous les chemins de décision puissent être testés de manière approfondie.</li>
</ul>
</blockquote>
<p>Donc en fait pour que C++ acceptable pour l&#39;usage pour un avion de chasse il faut une rigueur de ouf et couper des fonctionnalités de C++, mais c&#39;est bien aux devs de vérifier que y&#39;a pas les fonctionnalités considérées comme non-safe qui soient utilisées 😅 </p>
<p>Pourquoi là-dessus Rust est pour moi largement en avance ? C&#39;est le compilateur qui va vérifier qu&#39;on se plante pas </p>
<p>Pareil dans les commentaires je lis ça :</p>
<blockquote>
<p>le seul langage pourrie que je connaisse c&#39;est javascript, c&#39;est un langage codé à l&#39;arrache avec pleins d&#39;incohérence. D&#39;ailleurs plus personne ne code en javascript et utilise une surcouche comme angular. Dommage d&#39;ailleurs de pas avoir refait ce langage sur des bases plus solide, comme l&#39;a fait php et python (bien merdiques dans leurs 1ere versions)</p>
</blockquote>
<p>(je ne donne pas le nom, on s&#39;en fiche, il a droit d&#39;avoir un avis)</p>
<p>Alors que de bêtise ici à mon sens… Déjà &quot;plus personne ne code en javascript et utilise une surcouche comme angular&quot;, depuis quand Angular c&#39;est un langage ? 😅 ensuite c&#39;est faux de dire que JS est un mauvais langage, il n&#39;a pas du tout été &quot;codé à l&#39;arrache avec plein d&#39;incohérence&quot;, il a été pensé avec une base minuscule et a évolué avec le temps pour correspondre à l&#39;usage. Oui y&#39;a des petites bizarreries avec lesquelles il faut composer, mais c&#39;est le cas de la plupart des langages à mon avis. </p>
<p>À mon avis :</p>
<ul>
<li>il faut prendre le langage le mieux maîtrisé par l&#39;équipe si on a des contraintes critiques (comme le cas du F-35) ;</li>
<li>on peut prendre le langage qui donne les meilleures garanties dans les autres cas (on peut toujours se tromper et apprendre au fil de l&#39;eau) ;</li>
<li>il faut s&#39;outiller pour éviter les erreurs : sonar, les linters, un compilateur strict, etc. Tout ce qui peut vous guider pour éviter le max d&#39;erreur ;</li>
<li>arrêter de cracher sur les autres langages / frameworks : ce n&#39;est pas parce qu&#39;on aime pas ou que c&#39;est pas adapté à tout qu&#39;il faut le jeter (encore plus quand on ne maîtrise pas l&#39;écosystème qui va avec) ;</li>
</ul>
<h3 id="article-benchmarking-windows-against-itself-from-windows-xp-to-windows-11httpshackadaycom20260102benchmarkingwindowsagainstitselffromwindowsxptowindows11"><a href="https://hackaday.com/2026/01/02/benchmarking-windows-against-itself-from-windows-xp-to-windows-11/">Benchmarking Windows Against Itself, From Windows XP To Windows 11</a><a href="#article-benchmarking-windows-against-itself-from-windows-xp-to-windows-11httpshackadaycom20260102benchmarkingwindowsagainstitselffromwindowsxptowindows11" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#Windows</p>
<p>En gros résumé : à matériel égal (même laptop utilisé avec une installation de Windows XP, Windows Vista, Windows 7, Windows 8.1, Windows 10 et Windows 11), Windows 11 a des performances qui se place souvent en dernière position pour et souvent au même niveau que Windows XP. Windows XP est tout de même celui qui s&#39;en sort le mieux pour la consommation RAM et disque. Globalement c&#39;est plutôt Windows 7 et 8.1 qui sortent du lot en termes de performance. </p>
<p>C&#39;est un benchmark, ça vaut ce que ça vaut, mais c&#39;est clairement une démonstration de plus que Windows ne va pas dans le bon sens sur les dernières versions, devient de plus en plus lourd pour pas grand-chose… </p>
<p>Crédit photo : Générée via Mistral AI avec le prompt suivant : </p>
<blockquote>
<p>Une scène chaleureuse et immersive, inspirée par l’esthétique poétique de Studio Ghibli, représentant un bureau de travail en bois clair et vieilli, baigné d’une lumière dorée et tamisée, comme un après-midi d’automne. Au centre, une silhouette stylisée (style anime Ghibli : traits doux, visage non détaillé, vêtements amples et confortables) est assise en tailleur sur un tapis épais, absorbée par la lecture d’un journal tech futuriste. Le journal est ouvert, ses pages légèrement froissées, avec des titres en en-tête calligraphiés à la main : &quot;Frontend&quot;, &quot;Backend&quot;, &quot;IA&quot;, &quot;Sécurité&quot;, et &quot;Vie privée&quot;. Les pages brillent d’un halo bleu pâle, évoquant des lignes de code et des schémas techniques qui s’animent discrètement, comme par magie.</p>
<p>Autour d’elle, des piles de magazines et de carnets s’empilent de manière désordonnée mais harmonieuse. Certains sont ouverts, révélant des extraits d’articles, des croquis de frameworks (représentés par des icônes génériques : un crochet pour le frontend, un engrenage pour le backend, un cerveau pour l’IA, un cadenas pour la sécurité, et un masque pour la vie privée), ou des diagrammes de réseaux de neurones dessinés à la main. Un écran transparent et flottant (style holographique, mais avec un cadre en bois sculpté) affiche des flux d’informations en temps réel : des graphiques de données, des alertes de sécurité, et des extraits de code, le tout dans un style doux et organique, comme intégré à la scène.</p>
<p>En arrière-plan, une grande fenêtre donne sur un paysage urbain nocturne style Ghibli : des bâtiments aux formes arrondies, des lanternes suspendues, et des néons bleutés qui reflètent des motifs de code binaire sur les murs. Une tasse de thé fumant et un petit robot de bureau (inspiré des créatures de Ghibli, comme un mélange entre un Totoro miniature et un assistant tech) observent la scène avec curiosité.</p>
<p>À droite, un panda roux (ton animal préféré) est lové sur un coussin, les yeux mi-clos, comme s’il écoutait attentivement. Il ne doit pas dépasser le tiers de la hauteur de l’image et est positionné en bas à droite, légèrement tourné vers le centre, avec une queue soyeuse enroulée autour de lui.</p>
<p>L’ambiance est à la fois cosy, onirique et high-tech : les couleurs sont douces (beiges, bleus pâles, oranges chauds), avec des contrastes subtils pour mettre en valeur les éléments tech. Les détails sont soignés, avec des textures visibles (grain du bois, tissu du tapis, pelage du panda), et une lumière qui crée des jeux d’ombres chaleureuses. Le tout respire la sérénité et l’inspiration, comme un moment suspendu entre la magie et la technologie.</p>
</blockquote>
]]></content:encoded>
      <dc:creator><![CDATA[Anthony Pena]]></dc:creator>
      <media:content medium="image" url="https://anthonypena.fr/img/cover.min.jpg"/>
    </item>
    <item>
      <title><![CDATA[24 jours, 24 impressions 3D]]></title>
      <guid isPermaLink="false">2025/12/31/24-jours-24-impressions-3d</guid>
      <description><![CDATA[<p>Parce que parfois on me demande à quoi ça sert l&#39;impression 3D : ça sert à tout. C&#39;est pour moi comm…</p>
]]></description>
      <link>https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/index.html</link>
      <category><![CDATA[Impression 3D]]></category>
      <pubDate>Wed, 31 Dec 2025 07:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>Parce que parfois on me demande à quoi ça sert l&#39;impression 3D : ça sert à tout. C&#39;est pour moi comme si on demandait &quot;Qu&#39;est-ce qu&#39;on peut faire avec du plastique ?&quot;. En vrai l&#39;impression 3D ça permet d&#39;aller très loin, particulièrement si on a besoin de faire du sur-mesure. </p>
<p>Je vous montre comme un calendrier de l&#39;avent en retard, comme dernier article de 2025, 24 exemples d&#39;impressions que j&#39;ai faite et trouvée intéressantes à montrer !</p>
<h2 id="article-mon-materiel">Mon matériel<a href="#article-mon-materiel" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Je ne suis pas expert ultime en impression 3D. Je bidouille et apprends au fil des vidéos/lectures sur le sujet depuis 2018-2019 et des expérimentations depuis 2020.</p>
<p>Je ne &quot;maîtrise&quot; que l&#39;impression dite FDM (Fused Deposition Modeling), l&#39;impression 3D en utilisant des bobines de plastique (j&#39;utilise essentiellement du PLA, un peu de PETG à l&#39;occasion, mais il y a plein d&#39;autres options : ABS (de moins en moins utilisé quand même), TPU, ASA, Fibre de Carbon, etc.) qui sont déroulé par une partie chauffante qui va &quot;dessiner&quot; sur un plateau couche par couche un objet.</p>
<p>L&#39;impression 3D est un sujet fascinant, les technologies évoluent encore très fortement, tout se perfectionne, mais on peut trouver des machines très abordables qui font largement le travail qu&#39;on peut en attendre pour le grand public. J&#39;ai personnellement utilisé 2 machines différentes : une Creality Ender 3 (acheté environ 120€ en mai 2020) puis une Creality Ender 3 v3 KE (acheté un peu moins de 300€ mi-2024). Mais je pourrais aussi vous conseiller de jeter un coup d&#39;œil du côté des Artillery Sidewinder ou M1 Pro ou des Anycubic Kobra ou si vous avez un peu plus de budget les Prusa (seul fabriquant européen accessible au grand public à ma connaissance); je ne vous recommanderais par contre pas les Bambu Lab, qui pour moi ont le même problème que le matériel Apple : ça fonctionne mais c&#39;est cher et ça ne vous permettra pas vraiment de comprendre vraiment comment ça fonctionne, comment évoluer.</p>
<p>Globalement, dites-vous que même avec une imprimante entrée de gamme vous permettra de réaliser à peu près n&#39;importe quelle pièce, modulo un peu d&#39;effort de paramétrage et/ou un peu de suivi (particulièrement si vous avez besoin d&#39;utiliser plusieurs couleurs / matières) et/ou de temps. Tous les modèles que je vais montrer ici j&#39;aurai pu les réaliser avec n&#39;importe laquelle des machines que j&#39;ai possédées, mais l&#39;impression est environ 3 à 5 fois plus rapide avec ma Ender 3v3 KE qu&#39;avec ma Ender 3.</p>
<p>Il m&#39;arrive d&#39;imprimer des modèles pris sur Thingiverse ou Creality Cloud, mais la plupart des objets que j&#39;imprime je les modélise moi-même pour avoir exactement ce que je veux.</p>
<h2 id="article-1--des-jetons">1 - Des jetons<a href="#article-1--des-jetons" class="anchor" aria-label="permalink">🔗</a></h2>
<figure>
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_1.min.jpg" alt="Des jetons" is="img-zoom"/>
<figcaption>Des jetons</figcaption>
</figure>
<p>Là j&#39;en ai imprimé 6 sortes différentes (j&#39;en ai créé 8 mais j&#39;ai que 6 couleurs de filament 🤷‍♂️), chacun avec aussi un motif parce qu&#39;il faut aussi penser aux gens qui ne voit pas/mal les couleurs, voir ne voit pas du tout.</p>
<p>Ça sert à plein de trucs : pour faire des jeux, compter des trucs, faire des équipes au hasard, etc.</p>
<h2 id="article-2--bujo-helper">2 - BuJo helper<a href="#article-2--bujo-helper" class="anchor" aria-label="permalink">🔗</a></h2>
<figure id="image-gallery-mon-bujo-helper" class="marked-image-gallery" is="gallery-zoom">
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_2-1.min.jpg" alt="Mon BuJo helper"/>
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_2-2.min.jpg" alt="Mon BuJo helper"/>
<figcaption>Mon BuJo helper</figcaption>
</figure>
<p>Au quotidien j&#39;utilise un carnet pour m&#39;organiser, j&#39;ai une page mensuelle pour avoir une vision du mois et pour gagner du temps je me suis fait une sorte de petite règle pour m&#39;aider à tout positionner en 5s sans me casser la tête. C&#39;est très lié à mon usage, mais c&#39;est facile à faire et adapter à ses habitudes ce genre de trucs.</p>
<p>Avec l&#39;impression 3D c&#39;est super simple de produire un objet qui correspond pile-poil à son usage personnel.</p>
<h2 id="article-3--decoration-de-noel">3 - Décoration de Noël<a href="#article-3--decoration-de-noel" class="anchor" aria-label="permalink">🔗</a></h2>
<figure>
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_3.min.jpg" alt="Une décoration de Noël en forme d&#39;étoile" is="img-zoom"/>
<figcaption>Une décoration de Noël en forme d&#39;étoile</figcaption>
</figure>
<p>Parce que Noël ne veut pas forcément dire vider son compte en banque en déco, on peut complètement utiliser l&#39;impression 3D pour créer des décorations super sympa pour pas cher du tout. Potentiellement des décos uniques.</p>
<p>Ici j&#39;ai fait une simple imbrication d&#39;étoile en blanc (sur un sapin vert à ça rend vraiment bien), mais y&#39;a plein de choix disponibles sur des sites comme Thingiverse !</p>
<h2 id="article-4--pic-pour-noter-ce-quon-mange">4 - Pic pour noter ce qu&#39;on mange<a href="#article-4--pic-pour-noter-ce-quon-mange" class="anchor" aria-label="permalink">🔗</a></h2>
<figure id="image-gallery-un-pic-pour-etiqueter-de-la-nourriture" class="marked-image-gallery" is="gallery-zoom">
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_4-1.min.jpg" alt="Un pic pour étiqueter de la nourriture"/>
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_4-2.min.jpg" alt="Un pic pour étiqueter de la nourriture"/>
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_4-3.min.jpg" alt="Un pic pour étiqueter de la nourriture"/>
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_4-4.min.jpg" alt="Un pic pour étiqueter de la nourriture"/>
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_4-5.min.jpg" alt="Un pic pour étiqueter de la nourriture"/>
<figcaption>Un pic pour étiqueter de la nourriture</figcaption>
</figure>
<p>Parce que j&#39;aime bien ramener des gâteaux ou autres aux collègues, mais on sait jamais trop qui a quoi comme allergie ou restriction alimentaire ou même goût. Dans le doute j&#39;ai pris l&#39;habitude de mettre une indication de ce que je rapporte.</p>
<p>Pour exemple de banana bread, à priori à part si quelqu&#39;un n&#39;aime pas les bananes c&#39;est ok. Mais quand je mets des fruits à coques je le précise, pareil pour les viandes / poissons, halal / pas halal, veggie / vegan / carné. Perso je mange de tout mais je pense aux autres.</p>
<p>À noter que ça marche aussi très bien en gros repas de famille 😇</p>
<p>À noter que là j&#39;ai mon imprimante thermique qui sort des étiquettes autocollantes. Mais un bout de papier et du scotch ça marche aussi 😁 de préférence : faite en sorte que ça déborde sur le côté (comme j&#39;ai fait sur la photo, c&#39;est du sur-mesures, c&#39;est voulu que ça dépasse), c&#39;est plus simple à retirer ensuite pour réutiliser 😉 (pareil le trou rond au milieu c&#39;est pour facilité le retrait de l&#39;étiquette)</p>
<blockquote>
<p>Note : l&#39;impression 3D produit des pièces micro-poreuse, c&#39;est impossible de vraiment les nettoyer en profondeur, donc il ne faut pas mettre des pièces en impression 3D au contact d&#39;aliments chauds et/ou liquides. De plus, avec les imprimantes 3D grand public, vous ne pouvez pas garantir l&#39;hygiène alimentaire, à commencer par l&#39;absence de plomb dans l&#39;imprimante, pendant sa fabrication, pendant la fabrication des différentes pièces (tubes, extrudeurs, etc.), pendant la fabrication des filaments, etc. En gros si vous utilisez des impressions 3D pour du stockage alimentaire en contact direct ou avec du chaud : vous allez vous intoxiquer aux microplastiques et/ou aux métaux lourds.</p>
</blockquote>
<h2 id="article-5--objet-personnalise">5 - Objet personnalisé<a href="#article-5--objet-personnalise" class="anchor" aria-label="permalink">🔗</a></h2>
<figure>
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_5.min.jpg" alt="Une décoration de Noël avec un nom au milieu" is="img-zoom"/>
<figcaption>Une décoration de Noël avec un nom au milieu</figcaption>
</figure>
<p>Le gros avantage de l&#39;impression 3D, c&#39;est qu&#39;on peut faire des tirages uniques super facilement. Le truc qui marche toujours pour faire un petit cadeau, c&#39;est un objet personnalisé avec un prénom, particulièrement quand il s&#39;agit d&#39;un prénom moins commun (dont rarement disponible dans le commerce).</p>
<p>Ici j&#39;ai fait une pseudo-boule de Noël avec une déco toute simple, et un nom qui ressort au milieu (cherchez pas le Homere, c&#39;est le nom de mon équipe au boulot). Si vous faite ça bien, c&#39;est facile de décliner en série pour toute la famille. Imaginez un sapin rempli avec la &quot;boule&quot; au nom de chaque personne de la famille et de toutes les couleurs. Vous l&#39;avez ?</p>
<h2 id="article-6--sousverre--coaster">6 - Sous-verre / coaster<a href="#article-6--sousverre--coaster" class="anchor" aria-label="permalink">🔗</a></h2>
<figure id="image-gallery-un-sous-verre--tasse" class="marked-image-gallery" is="gallery-zoom">
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_6-1.min.jpg" alt="Un sous verre / tasse"/>
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_6-2.min.jpg" alt="Un sous verre / tasse"/>
<figcaption>Un sous verre / tasse</figcaption>
</figure>
<p>Une fois qu&#39;on a une imprimante 3D autant faire au max du sur-mesures non ? Je l&#39;utilise depuis quelque temps déjà ce sous-verre et franchement ça marche : que ce soit pour éviter d&#39;avoir mon bureau mouillé par la condensation ou laisser des marques de mug avec des boissons chaudes, ça fait le taff.</p>
<p>J&#39;aurais pu en trouver dans le commerce, mais souvent ils sont plats, ce qui fait que tout ce qui doit couler ne reste dans le sous-verre mais s&#39;étale. Avec ma version, je n&#39;ai pas ce problème 😁</p>
<p>Par contre pas besoin de faire un sous-verre aussi profond, j&#39;ai un peu abusé, mais ça marche très bien ! Après laissez vous aller niveau imagination sur le motif intérieur.</p>
<h2 id="article-7--crochet-douche">7 - Crochet douche<a href="#article-7--crochet-douche" class="anchor" aria-label="permalink">🔗</a></h2>
<figure id="image-gallery-un-crochet-de-douche-sur-mesure" class="marked-image-gallery" is="gallery-zoom">
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_7-1.min.jpg" alt="Un crochet de douche sur mesure"/>
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_7-2.min.jpg" alt="Un crochet de douche sur mesure"/>
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_7-3.min.jpg" alt="Un crochet de douche sur mesure"/>
<figcaption>Un crochet de douche sur mesure</figcaption>
</figure>
<p>On a tous des trucs chez nous qui ont des dimensions ou des formes très spécifiques. Ici j&#39;ai fait des crochets qui tiennent super bien en place car pile poil adapté à la forme de ma douche. Ça a tenu de 2020 à début 2025 quand j&#39;ai déménagé, c&#39;est du solide !</p>
<h2 id="article-8--cache-webcam">8 - Cache webcam<a href="#article-8--cache-webcam" class="anchor" aria-label="permalink">🔗</a></h2>
<figure>
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_8.min.jpg" alt="Cache webcam" is="img-zoom"/>
<figcaption>Cache webcam</figcaption>
</figure>
<p>Parce que je n&#39;aime pas avoir une caméra braquée sur moi à journée, encore moins quand ce n&#39;est pas ma machine et qu&#39;on pourrait exploiter cette caméra pour me regarder (que ce soit le propriétaire de la machine ou via un piratage), j&#39;aime bien avoir un cache sur la webcam de ma machine. Ici j&#39;en ai fait un tout simple, sur mesure, qui suit parfaitement la forme de la coque de la machine sans couvrir l&#39;écran, sans aucune colle. Pour utiliser la webcam il suffit de faire glisser le cache.</p>
<h2 id="article-9--piege-a-mouche">9 - Piège à mouche<a href="#article-9--piege-a-mouche" class="anchor" aria-label="permalink">🔗</a></h2>
<figure>
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_9.min.jpg" alt="Piège à mouche" is="img-zoom"/>
<figcaption>Piège à mouche</figcaption>
</figure>
<p>J&#39;ai eu plusieurs fois des problèmes de mouches à fruit, j&#39;ai fini par fabriquer un piège tout simple : une sorte d’entonnoir qui permet aux mouches de rentrer dans le pot mais pas d&#39;en ressortir. Au fond du pot il suffit de mettre un mélange vinaigre cidre, sirop de pêche (ou autre fruit), un peu d&#39;eau et puis de poser à hauteur d&#39;yeux.</p>
<p>Régulièrement je sortais le pot et je l&#39;ouvrais fenêtre fermée pour laisser s&#39;échapper les mouches prises au piège mais encore vivante. Ça ne permet pas de voir survivre toutes les mouches mais c&#39;est mieux que les autres techniques qui existent, tout en protégeant un peu les fruits.</p>
<h2 id="article-10--rangement-pour-piles">10 - Rangement pour piles<a href="#article-10--rangement-pour-piles" class="anchor" aria-label="permalink">🔗</a></h2>
<figure id="image-gallery-support-pour-ranger-des-piles-rechargeable" class="marked-image-gallery" is="gallery-zoom">
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_10-1.min.jpg" alt="Support pour ranger des piles rechargeable"/>
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_10-2.min.jpg" alt="Support pour ranger des piles rechargeable"/>
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_10-3.min.jpg" alt="Support pour ranger des piles rechargeable"/>
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_10-4.min.jpg" alt="Support pour ranger des piles rechargeable"/>
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_10-5.min.jpg" alt="Support pour ranger des piles rechargeable"/>
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_10-6.min.jpg" alt="Support pour ranger des piles rechargeable"/>
<figcaption>Support pour ranger des piles rechargeable</figcaption>
</figure>
<p>J&#39;ai besoin de piles rechargeables pour quelques usages, mais pas c&#39;est pas très pratique de chercher les piles à chaque fois, ni le chargeur de piles… J&#39;ai fini par créer un support qui s&#39;accroche à ma peg board <a href="https://www.ikea.com/fr/fr/search/?q%3Dsk%C3%A5dis">Ikea Skadis</a> de sorte à pouvoir ranger le tout de manière assez compacte et toujours à porter de main au-dessus de mon bureau.</p>
<h2 id="article-11--carte-de-visite-avec-qr-code-">11 - Carte de visite (avec QR Code ?)<a href="#article-11--carte-de-visite-avec-qr-code-" class="anchor" aria-label="permalink">🔗</a></h2>
<figure id="image-gallery-carte-de-visite" class="marked-image-gallery" is="gallery-zoom">
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_11-1.min.jpg" alt="Carte de visite"/>
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_11-2.min.jpg" alt="Carte de visite"/>
<figcaption>Carte de visite</figcaption>
</figure>
<p>C&#39;est une idée qui m&#39;a trotté pas mal en tête : est-ce que ce serait possible d&#39;imprimer une carte visite en bicolore avec un QR Code fonctionnel ? Et bien oui.</p>
<p>Là j&#39;ai testé avec une carte très simple, juste l&#39;URL de mon site et un QR Code contenant l&#39;URL de mon site aussi. Très simple mais ça fonctionne ! Que ce soit en vrai ou via une photo de la carte, le QR Code est parfaitement reconnu. Je pense qu&#39;on pourrait industrialiser un peu aussi la création du QR Code.</p>
<p>Je pense qu&#39;on doit pouvoir imaginer pas mal de chose : des cartes avec un texte transparent (ça nécessite de n&#39;avoir aucune partir &quot;flottante&quot; dans le texte), potentiellement une carte moins épaisse (là elle fait 1mm, 0.4mm de noir et 0.6mm de blanc, surement optimisable, mais je voulais être certain de n&#39;avoir aucune transparence dans le blanc pour avoir un bon contraste), je pense qu&#39;on pourrait aussi imaginer une carte où on viendrait intercaler un tissu avec un maillage très large comme on voit <a href="https://youtube.com/shorts/Sbmz7lFbW9M?si%3DCGvj4Df1IjuvtIKd">ici</a>, ou même imaginer des choses complètement différentes du fait justement de ne pas être avec une carte en papier/carton.</p>
<h2 id="article-12--compteur">12 - Compteur<a href="#article-12--compteur" class="anchor" aria-label="permalink">🔗</a></h2>
<figure id="image-gallery-compteur-avec-dizaine-et-unite" class="marked-image-gallery" is="gallery-zoom">
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_12-1.min.jpg" alt="Compteur avec dizaine et unité"/>
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_12-2.min.jpg" alt="Compteur avec dizaine et unité"/>
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_12-3.min.jpg" alt="Compteur avec dizaine et unité"/>
<figcaption>Compteur avec dizaine et unité</figcaption>
</figure>
<p>Je n&#39;ai pas retrouvé le lien du modèle mais ce compteur n&#39;est pas de moi. Il est très simple, il permet de compter les dizaines et les unités. J&#39;en avais besoin pour jouer à un jeu de carte (et non ce n&#39;est pas Magic). Je l&#39;ai promené avec moi pendant quelques semaines sans souci.</p>
<h2 id="article-13--support-camera">13 - Support caméra<a href="#article-13--support-camera" class="anchor" aria-label="permalink">🔗</a></h2>
<figure>
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_13.min.jpg" alt="Support pour caméra" is="img-zoom"/>
<figcaption>Support pour caméra</figcaption>
</figure>
<p>Pour le coup, ce n&#39;est pas moi qui aie modélisé ce support non plus, mais il correspondait plutôt bien à ce dont j&#39;avais besoin : un support pour accrocher ma Nebula Caméra (la caméra de Creality pour faire du suivi d&#39;impression à distance) à mon imprimante pour que ça suive l&#39;impression.</p>
<p>Vous pouvez retrouver le modèle sur <a href="https://www.thingiverse.com/thing:6574108">Thingiverse</a>.</p>
<p>C&#39;est un peu une impression pour l&#39;imprimante (ce qui ne produit pas vraiment de valeur à posséder une imprimante dans un sens), mais je trouve l&#39;exemple intéressant, car on peut fabriquer toute sorte de support de caméra / appareil photo / téléphone avec l&#39;impression 3D !</p>
<h2 id="article-14--crochet-de-porte-pour-sac">14 - Crochet de porte pour sac<a href="#article-14--crochet-de-porte-pour-sac" class="anchor" aria-label="permalink">🔗</a></h2>
<figure id="image-gallery-sac-accroche-a-la-porte-avec-des-crochets" class="marked-image-gallery" is="gallery-zoom">
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_14-1.min.jpg" alt="Sac accroché à la porte avec des crochets"/>
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_14-2.min.jpg" alt="Sac accroché à la porte avec des crochets"/>
<figcaption>Sac accroché à la porte avec des crochets</figcaption>
</figure>
<p>Je pense que c&#39;est un des premiers objets que j&#39;ai modélisés puis imprimé : des crochets pour ranger des sacs derrières les portes. C&#39;est toujours un espace perdu, j&#39;ai déjà testé des patères de porte, mais je trouve ça pas très pratique (prend trop de place, trop haut, gène la fermeture de la porte, pas assez / trop d&#39;espace entre les crochets, etc.), là c&#39;est juste parfait !</p>
<p>Sur ma photo j&#39;ai accroché des sacs, mais j&#39;en ai 3-4 sur presque toutes les portes chez moi pour accrocher des sacs, des vestes, peignoirs, serviettes, etc.</p>
<p>Bref : c&#39;est facile à modéliser, ça coûte rien à imprimer, c&#39;est toujours pratique !</p>
<h2 id="article-15--porte-cle">15 - Porte clé<a href="#article-15--porte-cle" class="anchor" aria-label="permalink">🔗</a></h2>
<figure>
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_15.min.jpg" alt="Porte clé" is="img-zoom"/>
<figcaption>Porte clé</figcaption>
</figure>
<p>J&#39;en ai déjà parlé sur le blog, je suis organisateur d&#39;une conférence : NG Baguette Conf. Pour la première édition j&#39;ai fabriqué des portes clés pour marquer le coup, avec le logo Angular mais les couleurs de la conférence (noir et rose), avec le texte &quot;NGB2025&quot; au dos.</p>
<p>C&#39;est assez facile de faire des portes clés en impression 3D, et vous n&#39;avez qu&#39;à acheter des anneaux de porte clé.</p>
<p>Si comme moi, vous prévoyez d&#39;en faire un bon paquet, investissez dans une <a href="https://a.aliexpress.com/_Evy7HiU">pince &quot;cerclip&quot;</a> (lien non sponsorisé) qui va vous permettre de très facilement ouvrir et refermer les anneaux.</p>
<h2 id="article-16--jeton-de-caddie">16 - Jeton de caddie<a href="#article-16--jeton-de-caddie" class="anchor" aria-label="permalink">🔗</a></h2>
<figure id="image-gallery-jeton-de-caddie" class="marked-image-gallery" is="gallery-zoom">
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_16-1.min.jpg" alt="Jeton de caddie"/>
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_16-2.min.jpg" alt="Jeton de caddie"/>
<figcaption>Jeton de caddie</figcaption>
</figure>
<p>Pas si différent des jetons en numéro 1, ici les dimensions correspondent parfaitement à un jeton de caddie (ou d&#39;une pièce de 0,50€), avec un motif d&#39;axolotl parce que j&#39;aime bien la mascotte de SFEIR !</p>
<h2 id="article-17--marque-page-personnalise">17 - Marque page personnalisé<a href="#article-17--marque-page-personnalise" class="anchor" aria-label="permalink">🔗</a></h2>
<figure id="image-gallery-marque-page-en-forme-depee" class="marked-image-gallery" is="gallery-zoom">
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_17-1.min.jpg" alt="Marque page en forme d&#39;épée"/>
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_17-2.min.jpg" alt="Marque page en forme d&#39;épée"/>
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_17-3.min.jpg" alt="Marque page en forme d&#39;épée"/>
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_17-4.min.jpg" alt="Marque page en forme d&#39;épée"/>
<figcaption>Marque page en forme d&#39;épée</figcaption>
</figure>
<p>Parce que j&#39;aime lire mais que j&#39;ai toujours besoin d&#39;un marque-page j&#39;ai fini par fabriquer les miens, toute une série de petite épée en plastique qui se bloque dans mes livres. Ça m&#39;a éclaté de dessiner puis modéliser ça, ça me fait plaisir de voir mes petites épées dans mes livres.</p>
<p>Personnellement j&#39;ai choisi des épées mais sur des sites comme Thingiverse, on peut trouver des centaines de marques pages en tout genre et pour tous les goûts !</p>
<h2 id="article-18--piece-perdu-de-jeu-de-societe">18 - Pièce perdu de jeu de société<a href="#article-18--piece-perdu-de-jeu-de-societe" class="anchor" aria-label="permalink">🔗</a></h2>
<figure>
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_18.min.jpg" alt="Quelques maisons / hotel de Monopoly" is="img-zoom"/>
<figcaption>Quelques maisons / hotel de Monopoly</figcaption>
</figure>
<p>Parce que c&#39;est facile de perdre des pièces de certains jeux, ma compagne avait perdu quelques hôtels et maisons de son exemplaire du Monopoly. J&#39;en ai pris un exemplaire de chaque et j&#39;en ai fabriqué quelques nouveaux (doré, parce que pourquoi pas ? ou peut-être parce que j&#39;avais plus ni rouge, ni vert à l&#39;époque).</p>
<p>Un petit effort de modélisation, mais je pense que j&#39;aurais pu trouver ça tout prêt aussi. Je pense que beaucoup de jeux peuvent être sauvé par l&#39;impression 3D !</p>
<h2 id="article-19--support-de-tringle-a-rideau">19 - Support de tringle à rideau<a href="#article-19--support-de-tringle-a-rideau" class="anchor" aria-label="permalink">🔗</a></h2>
<figure id="image-gallery-support-de-tringle-a-rideau" class="marked-image-gallery" is="gallery-zoom">
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_19-1.min.jpg" alt="Support de tringle à rideau"/>
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_19-2.min.jpg" alt="Support de tringle à rideau"/>
<figcaption>Support de tringle à rideau</figcaption>
</figure>
<p>Nouveau logement, nouvelle décoration, nouveau rideau. Enfin non, le rideau je l&#39;avais déjà, la tringle aussi (même si je l&#39;ai changé depuis pour avoir une tringle plus longue, sur la photo c&#39;était un peu juste), les trous étaient déjà là. J&#39;ai donc modélisé des supports qui avaient pile la bonne distance pour réutiliser les trous existants et poser un rideau.</p>
<p>À noter que j&#39;ai imprimé deux fois les supports, car la première impression a cassé : le sens d&#39;impression faisait que le poids des rideaux a séparé les couches (sur la seconde photo on voit en haut la version qui a cassé, en bas la version en place depuis avant l&#39;été).</p>
<h2 id="article-20--extensions-pour-des-jouets-denfants">20 - Extensions pour des jouets d’enfants<a href="#article-20--extensions-pour-des-jouets-denfants" class="anchor" aria-label="permalink">🔗</a></h2>
<figure id="image-gallery-rails-de-trains-et-petites-gares" class="marked-image-gallery" is="gallery-zoom">
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_20-1.min.jpg" alt="Rails de trains et petites gares"/>
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_20-2.min.jpg" alt="Rails de trains et petites gares"/>
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_20-3.min.jpg" alt="Rails de trains et petites gares"/>
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_20-4.min.jpg" alt="Rails de trains et petites gares"/>
<figcaption>Rails de trains et petites gares</figcaption>
</figure>
<p>À Noël dernier j&#39;ai offert au petit un ensemble de rails et trains électriques. Très vite j&#39;ai vu qu&#39;il avait du mal avec les rails qu&#39;il avait à créer un circuit (en fait il n&#39;y avait qu&#39;un seul circuit possible et ne permettait pas d&#39;utiliser le pont que j&#39;avais aussi acheté…). J&#39;ai conçu des rails qui ont une certaine souplesse, et permettent de facilement créer des circuits en s&#39;adaptant à l&#39;angle requis (contrairement aux pièces en bois qui ont un angle fixe).</p>
<p>J&#39;ai fait plusieurs longueurs de rails, il faudrait encore que je retravaille le modèle pour corriger certains défauts (si le circuit est fixe trop longtemps les rails ont tendances à ne plus revenir droits, il y a des points de faiblesses, etc.) mais ça fonctionne très bien, le petit s&#39;éclate et ça coûte presque rien à imprimer !</p>
<p>J&#39;ai aussi remarqué que le pont tenait pas très en place, car à la base le pont est censé juste être posé en équilibre sur les deux cubes en bois. J&#39;ai donc fait un petit support qui se place sur le cube et permet de fixer en place le pont et les rails ce qui fait que ça devient beaucoup plus facile de construire le circuit.</p>
<p>J&#39;ai aussi fabriqué des gares, car le circuit commençait à devenir grand pour une seule petite gare, alors que 3 c&#39;est plus sympa ! 😇</p>
<h2 id="article-21--extension-pour-pied-ikea-lack">21 - Extension pour pied Ikea Lack<a href="#article-21--extension-pour-pied-ikea-lack" class="anchor" aria-label="permalink">🔗</a></h2>
<figure id="image-gallery-modules-dextensions-pour-pied-ikea-lack" class="marked-image-gallery" is="gallery-zoom">
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_21-1.min.jpg" alt="Modules d&#39;extensions pour pied Ikea Lack"/>
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_21-2.min.jpg" alt="Modules d&#39;extensions pour pied Ikea Lack"/>
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_21-3.min.jpg" alt="Modules d&#39;extensions pour pied Ikea Lack"/>
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_21-4.min.jpg" alt="Modules d&#39;extensions pour pied Ikea Lack"/>
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_21-5.min.jpg" alt="Modules d&#39;extensions pour pied Ikea Lack"/>
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_21-6.min.jpg" alt="Modules d&#39;extensions pour pied Ikea Lack"/>
<figcaption>Modules d&#39;extensions pour pied Ikea Lack</figcaption>
</figure>
<p>J&#39;avais besoin de faire une colonne de rangement pour mettre mon imprimante et un peu de bazar qui va avec. Mais je voulais quelque chose de modulaire pour pouvoir changer la hauteur des étagères, ajouter des modules spécifiques pour dans le futur peut-être mettre des parois, etc. J&#39;ai donc conçu des blocs qui s&#39;assemblent sans vis (sauf pour le module du bas et du haut qui se visse dans la table). Ensuite tout tien avec des goupilles qui sont simplement un morceau de filament coupé à la bonne longueur pour traverser le module de part en part. C&#39;est fonctionnel, c&#39;est pratique, ça tient vraiment bien, c&#39;est extensible avec peu d&#39;effort (il suffit de retirer la goupille d&#39;un des modules sur chaque pied, puis mettre un nouveau module, puis remettre des goupilles).</p>
<p>Je n&#39;ai pas vraiment fini mon idée (comme j&#39;ai juste rehaussé les étages pour que l&#39;imprimante passe), mais j&#39;ai pu valider que ça fonctionne. C&#39;est assez facile de modéliser un système dans ce genre, et je pense qu&#39;on pourrait l&#39;utiliser pour pas mal de cas d&#39;assemblage !</p>
<h2 id="article-22--bouton-de-porte">22 - Bouton de porte<a href="#article-22--bouton-de-porte" class="anchor" aria-label="permalink">🔗</a></h2>
<figure id="image-gallery-bouton-de-porte" class="marked-image-gallery" is="gallery-zoom">
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_22-1.min.jpg" alt="Bouton de porte"/>
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_22-2.min.jpg" alt="Bouton de porte"/>
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_22-3.min.jpg" alt="Bouton de porte"/>
<figcaption>Bouton de porte</figcaption>
</figure>
<p>Quand j&#39;ai déménagé je me suis retrouvé avec des placards sans poignées et sans clé… Donc ma solution a été très simple : j&#39;ai fait sauter la serrure en place et j&#39;ai utilisé les trous existant pour mettre bouton de porte simple mais efficace qui est fixé avec 4 vis à l&#39;arrière (côté placard) et de la colle en façade pour que le tout soit solidaire.</p>
<p>J&#39;en ai fait deux identiques, c&#39;est en place depuis avril, et ça n&#39;a pas bougé.</p>
<p>L&#39;impression 3D ça peut vraiment prendre une place dans le quotidien même où on le ne penserait pas.</p>
<h2 id="article-23--plateau-puzzle">23 - Plateau puzzle<a href="#article-23--plateau-puzzle" class="anchor" aria-label="permalink">🔗</a></h2>
<figure id="image-gallery-plateau-puzzle" class="marked-image-gallery" is="gallery-zoom">
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_23-1.min.jpg" alt="Plateau puzzle"/>
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_23-2.min.jpg" alt="Plateau puzzle"/>
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_23-3.min.jpg" alt="Plateau puzzle"/>
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_23-4.min.jpg" alt="Plateau puzzle"/>
<figcaption>Plateau puzzle</figcaption>
</figure>
<p>Ma compagne aime faire des puzzles, mais je l&#39;ai vu un peu trop en galère avec ses petits tas de pièces à droite à gauche. Je lui a fabriqué des plateaux pour trier les pièces. J&#39;ai choisi de les faire en forme de pièce de puzzle parce que je trouvais ça plus simple, et j&#39;ai fait en sorte que les plateaux soient empilables pour facilement les ranger, avec ou sans pièces dedans.</p>
<h2 id="article-24--bloque-porte">24 - Bloque porte<a href="#article-24--bloque-porte" class="anchor" aria-label="permalink">🔗</a></h2>
<figure id="image-gallery-bloque-porte" class="marked-image-gallery" is="gallery-zoom">
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_24-1.min.jpg" alt="Bloque porte"/>
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_24-2.min.jpg" alt="Bloque porte"/>
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_24-3.min.jpg" alt="Bloque porte"/>
<img src="https://anthonypena.fr/2025/12/31/24-jours-24-impressions-3d/img/print_24-4.min.jpg" alt="Bloque porte"/>
<figcaption>Bloque porte</figcaption>
</figure>
<p>J&#39;avais un problème compliqué et rempli de contradiction : le petit refusait de dormir la porte fermée, mais pas trop ouverte, le chat voulait absolument entrer dans la chambre du petit quand la porte n&#39;était pas fermée, mais ledit chat empêchait le petit de dormir, je ne voulais pas bloquer trop la porte car si le petit appel il faut qu&#39;on puisse y aller très vite (sans parler d&#39;un risque en cas d&#39;urgence comme un incendie)… 😤 Du coup j&#39;ai fabriqué ce bloc porte. C&#39;est un objet qui ne ressemble pas à grand-chose, j&#39;ai eu besoin de 2-3 itérations pour arriver à ça, mais ça fonctionne.</p>
<p>La porte est bloquée entre-ouverte, assez pour que le petit voie que la porte n&#39;est pas fermée et soit rassuré, mais pas assez pour que la tête du chat passe (en tout la minette est convaincu que ça ne passe pas et n&#39;essaie pas). Une fois habitué, en 2-3 secondes on le met en place ou le retire et ça ne nous gêne pas du tout.</p>
<p>Je ne comprends pas pourquoi cet objet n&#39;a jamais été inventé et commercialisé, ça fonctionne diablement bien !</p>
<h2 id="article-conclusion">Conclusion<a href="#article-conclusion" class="anchor" aria-label="permalink">🔗</a></h2>
<p>L&#39;impression 3D fait partie intégrante de mon quotidien. Je trouve que c&#39;est à la fois passionnant et satisfaisant. Surtout en tant que développeur : on se confronte à la réalité physique et tout ce que ça implique.</p>
<p>Bref, j&#39;adore l&#39;impression 3D, j&#39;avais envie de vous partager un bout de ça ici !</p>
<p>Source :</p>
<ul>
<li>[Impression 3D](<a href="https://fr.wikipedia.org/wA">https://fr.wikipedia.org/wA</a> pixel art illustration (1-bit black and white style) showing a red panda character interacting with 3D-printed objects. The red panda is standing on a puzzle tray, holding a shower hook in one paw and a bookmark in the other. The background is completely black, with only the objects and the panda illuminated in white and shades of gray. The red panda is positioned in the bottom right corner, facing three-quarters away from the viewer, with its tail curled at the bottom. The scene includes 8-10 minimalist maple leaves scattered around the panda, barely visible. The style is retro and minimalist, with a focus on sharp contrasts and simplicity.&quot;iki/Impression_3D)</li>
<li><a href="https://fr.wikipedia.org/wiki/Acide_polylactique">PLA</a></li>
</ul>
<p>Crédit photo : Générée via Mistral AI avec le prompt suivant :</p>
<blockquote>
<p>A pixel art illustration (1-bit black and white style) showing a red panda character interacting with 3D-printed objects. The red panda is standing on a puzzle tray, holding a shower hook in one paw and a bookmark in the other. The background is completely black, with only the objects and the panda illuminated in white and shades of gray. The red panda is positioned in the bottom right corner, facing three-quarters away from the viewer, with its tail curled at the bottom. The scene includes 8-10 minimalist maple leaves scattered around the panda, barely visible. The style is retro and minimalist, with a focus on sharp contrasts and simplicity.</p>
</blockquote>
]]></content:encoded>
      <dc:creator><![CDATA[Anthony Pena]]></dc:creator>
      <media:content medium="image" url="https://anthonypena.fr/img/cover.min.jpg"/>
    </item>
    <item>
      <title><![CDATA["J'ai fini tard hier soir…"]]></title>
      <guid isPermaLink="false">2025/12/23/j-ai-fini-tard-hier-soir</guid>
      <description><![CDATA[<p>Ceux qui ont travaillé avec moi depuis que je suis lead le savent : je râle pas mal contre le fait d…</p>
]]></description>
      <link>https://anthonypena.fr/2025/12/23/j-ai-fini-tard-hier-soir/index.html</link>
      <category><![CDATA[Avis]]></category>
      <category><![CDATA[Métier de dev]]></category>
      <pubDate>Tue, 23 Dec 2025 07:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>Ceux qui ont travaillé avec moi depuis que je suis lead le savent : je râle pas mal contre le fait de travailler le soir, le week-end, pendant les congés, etc. Je sais que ça va souvent de pair avec le fait d&#39;être junior et/ou avec les syndromes de l&#39;imposture et/ou de manquer de confiance en soi, mais je pense que parfois avoir de l&#39;expérience c&#39;est aussi poser un certain cadre pour que tout le monde travaille dans des bonnes conditions. Je vous explique ça !</p>
<blockquote>
<p>Avertissement : cet article s&#39;adresse plutôt aux employés, moins aux indépendants / entrepreneurs, encore que, certains trucs s&#39;appliquent aussi. Cet article s&#39;applique aussi beaucoup facilement aux travaux qui sont peu rapport au temps comme c&#39;est le cas du développement, mais pas seulement !</p>
</blockquote>
<h2 id="article-parlons-argent">Parlons argent<a href="#article-parlons-argent" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Partons d&#39;un basico-basique : vous avez signé un contrat qui défini que vous allez échanger 35 à 39 heures (en fonction de votre contrat) de votre temps chaque semaine contre un salaire. Que se passe-t-il si vous travaillez 1h de plus ? 2h de plus ? 4h de plus ? soyons fou 6h de plus ? chaque semaine… Hé bien vous travaillez gratuitement.</p>
<p>Évidemment je sais que c&#39;est plus compliqué que ça :</p>
<ul>
<li>si comme moi vous avez un contrat en forfait jour annuel vous n&#39;avez pas vraiment d&#39;horaire ;</li>
<li>si vous avez une entreprise qui demande un pointage pour vous offrir du temps de récupération ou un paiement d&#39;heure supplémentaire ça ne marche pas ;</li>
<li>etc.</li>
</ul>
<p>Mais dans la majorité des cas il y a un plafond : quand bien même je suis en forfait jour, j&#39;ai un nombre d&#39;heure qui facturé sur mon ordre de mission en théorie. Pareil pour les heures supplémentaires ou le temps de récupération : il y a assez vite un plafond au-delà duquel ce n&#39;est plus compté.</p>
<p>Ça peut être tentant de donner plus à son travail pour mieux progresser dans l&#39;entreprise, s&#39;assurer d&#39;une certaine réussite de l&#39;entreprise pouvant découler à des primes, etc. Mais êtes-vous sûr que ça arrivera ? Êtes-vous sûr que ça va revenir dans votre sens au bout du compte ? Êtes-vous certain de rester assez longtemps dans l&#39;entreprise pour que votre investissement de temps vous revienne ? Pour moi non.</p>
<h2 id="article-vous-avez-besoin-de-souffler">Vous avez besoin de souffler<a href="#article-vous-avez-besoin-de-souffler" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Comme pas mal de développeur de ma génération et des générations d&#39;avant : j&#39;ai commencé ma carrière en voulant coder, coder, coder, en trouvant que je codais jamais assez vite / bien, en voulant toujours aller plus loin. Donc c&#39;est parfois tentant de rester un peu plus, puis un peu plus, puis un peu plus, surtout quand personne n&#39;attend à la maison. Mais on s&#39;oublie nous. On oublie qu&#39;on a besoin de couper. On a besoin de quitter sa chaise pour que notre cerveau continue de fonctionner.</p>
<p>Ce que j&#39;essaie de vous dire c&#39;est que ne jamais lâcher c&#39;est vous interdire de vous reposer. Donc vous allez vous fatiguer. Et vous aller travailler moins efficacement, faire plus d&#39;erreurs, perdre du temps, etc. Et au final ? Travailler encore plus pour compenser, donc être encore plus fatigué, donc travailler encore moins efficacement, faire encore plus d&#39;erreurs, perdre encore plus de temps, etc.</p>
<p>Vous sentez venir le cycle extrêmement vicieux qui se dessine ?</p>
<p>C&#39;est facile de rentrer dans ce cercle vicieux. C&#39;est plus difficile de voir qu&#39;on est dedans. C&#39;est encore plus difficile d&#39;en sortir quand c&#39;est devenu notre rythme de vie.</p>
<p>Ceux qui bossent avec moi en ce moment le savent : je fais attention à ça et je fais des rappels à l&#39;ordre à ceux qui bossent trop, car si c&#39;est difficile de le voir par soi-même, se prendre un taquet par quelqu&#39;un qui nous mentor est souvent assez impactant pour que ça fonctionne bien je trouve ! 😈</p>
<p>Il y a quand même un cas difficile : le <a href="https://fr.wikipedia.org/wiki/Workaholisme">workaholisme</a>. </p>
<blockquote>
<p>La personne touchée par la dépendance au travail ou ergomanie — mieux connu sous l&#39;anglicisme workaholisme — se caractérise principalement par un effort de travail compulsif supérieur à la moyenne, une recherche excessive et dysfonctionnelle de la perfection et une pulsion à persévérer dans l’excès de travail, ce qui conduit progressivement à une réelle dépendance.
-- Wikipédia</p>
</blockquote>
<p>Ici on est plus face à une &quot;erreur&quot; sur le rythme de travail : on est sur un cas qui est pathologique, vous ne pouvez pas aider ces personnes, vous ne pouvez qu&#39;essayer de les pousser à se faire accompagner ou quitter le travail (au sens &quot;rompre le contrat de travail&quot;). En tout cas je n&#39;ai pas de solution ici…</p>
<p>Par contre peu importe le cas dans lequel on est, il y aura toujours des gens pas forcément très bien intentionnés pour vous exploiter et tirer parti du fait que vous travaillez trop.</p>
<h2 id="article-mais-moi-jadore-coder--">&quot;Mais moi j&#39;adore coder ! 😢&quot;<a href="#article-mais-moi-jadore-coder--" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Et c&#39;est idéal d&#39;être développeur en aimant coder je pense ! Et je ne vous dis pas de ne pas coder pour le plaisir hors des heures de travail si ça vous éclate ! Mais pas sur les projets du boulot.</p>
<p>J&#39;ai toujours codé hors du travail, j&#39;en ai déjà parlé, mais j&#39;ai même commencé à coder 3 ans avant de commencer des études en informatiques, je passe en moyenne 2 à 3h par semaine (parfois plus) sur le présent blog, à ça s&#39;ajoute jusqu&#39;à 4h de code sur des projets persos quand j&#39;en ai envie et le temps. Pour moi coder c&#39;est une passion, je code par plaisir, je teste des trucs quand j&#39;ai des idées, j&#39;ai souvent un projet &quot;doudou&quot;.</p>
<blockquote>
<p>Si vous ne connaissez pas l&#39;idée du projet &quot;doudou&quot; c&#39;est un projet qui permet de se détendre et se faire plaisir, on se met peu / pas de pression, l&#39;idée c&#39;est juste coder un truc dans un autre contexte que le travail.</p>
</blockquote>
<p>Jamais je ne vous dirais que vous n&#39;avez pas le droit de coder hors du boulot. Je serais très mal placé pour ça. Mais si vous travaillez sur les projets du boulot vous ne coupez jamais. Et vous avez besoin de couper. Vous avez besoin de changer d&#39;air.</p>
<p>Et j&#39;ajouterai que si vous coder sur des projets perso, vous allez apprendre beaucoup plus qu&#39;en travaillant sur les projets du boulot : vous n&#39;avez pas le cadre et les contraintes, il faut ré-inventer certains trucs, vous pouvez explorer d&#39;autres idées, vous pouvez tester des outils que vous n&#39;aurez pas l&#39;occasion de voir au travail, c&#39;est hyper enrichissant. Et vous allez devenir meilleur·e plus vite, et donc ça va aider votre projet boulot.</p>
<h2 id="article-mais-luielle-ilelle-arrive-a-faire-ca-dans-sa-semaine-">&quot;Mais lui/elle il/elle arrive à faire ça dans sa semaine !&quot;<a href="#article-mais-luielle-ilelle-arrive-a-faire-ca-dans-sa-semaine-" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Ponctuellement en cas de gros coup dure je veux bien finir plus tard, bosser un peu le midi, éviter de trop poser de jours de congés (sauf si j&#39;ai besoin) mais pas les week-ends par exemple : comme tout le monde, j&#39;ai MA vie et je n&#39;en ai qu&#39;une, si au travail c&#39;est tellement mal géré que ça retombe sur nous ce n&#39;est pas mon erreur, ce n&#39;est pas à moi de le subir. Et c&#39;est pareil pour vous. N&#39;acceptez pas tout et n&#39;importe quoi pour votre travail : votre travail n&#39;est qu&#39;une passe dans votre vie, rien de plus.</p>
<p>Par contre si bosser plus devient une norme, vous créez une fausse impression qu&#39;on peut faire en 35h ce que vous faite en réalité en 40-45h. Même pire : vous donnez l&#39;impression que vous pouvez produire en 35h ce que vous faites en réalité en 40-45h. Donc vous vous piégez à long terme. Vous allez vous épuiser, vous allez vous forcer à prendre un rythme que vous n&#39;êtes pas capable de tenir à long terme, et vous allez craquer.</p>
<p>Imposer cette norme sur votre personne va avoir une autre conséquence : l&#39;imposer au reste de votre équipe. Il y a toujours comparaison entre les différentes personnes d&#39;une équipe. Si une personne bosse 5 à 10h de plus (donc 1j de plus environ) chaque semaine, les autres membres de l&#39;équipe sembleront travailler moins que vous, et il va y avoir une pression implicite qui va se mettre en place sur les autres qui vont tout doucement devoir prendre votre rythme ou partir.</p>
<p>En d&#39;autres termes : à vous épuiser à bosser plus vous donnez l&#39;impression que les autres ne travaillaient pas efficacement (voir pas du tout), alors que c&#39;est faux. Vous allez entraîner les autres dans un cercle vicieux.</p>
<p>Et ne vous dites pas que c&#39;est le fait d&#39;être junior qui fait que vous devez travailler plus pour atteindre le niveau de telle personne qui vous semble hyper forte : si vous êtes junior, vous avez beaucoup à apprendre (qu&#39;on soit clair : c&#39;est normal !), donc votre cerveau est mobilisé très fortement pour digérer tous les nouveaux trucs que vous voyez ; si vous bossez trop, votre cerveau ne sera juste pas capable du tout d&#39;assimiler et vous aurez du mal à apprendre.</p>
<h2 id="article-et-si-on-travaillait-moins-">Et si on travaillait moins ?<a href="#article-et-si-on-travaillait-moins-" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Travailler 35h n&#39;a pas rendu la France moins productive que quand on travaillait à 39h (ou plus d&#39;ailleurs). Surtout aussi parce qu&#39;en réalité beaucoup de gens ne sont pas à 35h mais 37-39h (comme l&#39;époque des 39h impliquait qu&#39;en réalité pas mal de gens était à plus de 40h semaine). Mais aussi parce qu&#39;en réalité : travailler moins c&#39;est aussi travailler mieux et plus efficacement dans pas mal de cas.</p>
<p>Je sais que certains emplois sont très liés à du temps : un agent de sécurité est payé au temps, et s&#39;il travaille moins il surveille moins longtemps, mais il surveille potentiellement plus attentivement aussi ; un ouvrier qui travaille à la chaîne produira moins s&#39;il travaille moins longtemps, mais il fera peut-être moins d&#39;erreur et/ou provoquera moins d&#39;accident ; etc.</p>
<p>Dans l&#39;informatique, il y a peu de gens qui ont un travail lié au temps : si je travaille 28h sur 4j, je ne vais pas produire sensiblement moins qu&#39;en 35h sur 5j. Par contre je vais plus me reposer, commencer la semaine plus en forme (après 3j de week-end), encaisse mieux certains éléments de stress, me poser plus sur mon travail, faire moins d&#39;erreur, etc. C&#39;est saint de travailler moins.</p>
<p>On peut aussi citer la <a href="https://fr.wikipedia.org/wiki/Loi_de_Parkinson">Loi de Parkinson</a> :</p>
<blockquote>
<p>Work expands so as to fill the time available for its completion. General recognition of this fact is shown in the proverbial phrase: It is the busiest man who has time to spare » traduisible par « Le travail s’étend de manière à remplir le temps disponible pour son achèvement. La connaissance générale de ce fait est illustrée par la phrase proverbiale suivante : « C&#39;est l&#39;homme le plus occupé qui a du temps à perdre »
-- citation de Cyril Northcote Parkinson (en 1955) sur Wikipédia</p>
</blockquote>
<p>L&#39;idée n&#39;est pas nouvelle, pourtant elle met du temps à faire son chemin. Quelques entreprises / pays expérimentent de plus en plus la semaine de 4j (y compris en France en 28h/4j ou 32h/4j) et ça fonctionne très bien !</p>
<h2 id="article-et-sinon">Et sinon…<a href="#article-et-sinon" class="anchor" aria-label="permalink">🔗</a></h2>
<blockquote>
<p>&quot;Les seuls qui se souviendront que vous avez fini tard seront vos enfants&quot;</p>
</blockquote>
<p>Je ne sais pas qui a prononcé cette phrase mais ça me semble assez frappant : peu importe que vous ayez des enfants ou pas, c&#39;est vos proches les seuls qui se rappelleront que vous avez passé votre vie au travail plutôt qu&#39;avec eux, ou plutôt, ce sont eux qui ne se rappelleront pas de vous, car vous étiez absent !</p>
<blockquote>
<p>&quot;17h00 et tu pars ? T&#39;as pris ton après-midi ?&quot;</p>
</blockquote>
<p>Le genre de &quot;blague&quot; qu&#39;on est beaucoup à avoir entendu… Pareil pour les open space qui se vidaient quand le(s) manager(s) partait(ent)… Ce n&#39;est pas parce que vous partez le dernier que vous êtes le meilleur employé, ce n&#39;est pas parce que vous êtes dans un milieu toxique (parce que oui c&#39;est toxique de fonctionner comme ça) que vous devez suivre les &quot;règles&quot; et subir en silence les années : imposez le respect de votre droit à déconnecter (la Loi est de votre côté) ou juste partez pour un contexte plus saint !</p>
<blockquote>
<p>&quot;Vous avez fait une livraison pizza ?&quot;</p>
</blockquote>
<p>Je sais que certains sont plutôt en mode sushi ou burger mais peu importe : je pointe les livraisons de fin de journée qui s&#39;éternise sur la soirée, parfois très tard qui finissent par se faire en mangeant à l&#39;arrache, qui sont épuisantes, qui n&#39;aboutissent qu&#39;à des erreurs monumentales, qui détruise votre confiance, qui pourrissent certaines équipes… (Vous sentez que je l&#39;ai vécu en début de carrière ? Imaginez ça avec le chef de projet qui regarde au-dessus de l&#39;épaule et une alarme de sécurité pas désactivée qui sonne pendant 3h consécutives, moi qui cours pour choper le dernier bus ou faire 2h15 de marche à minuit passé et vous avez l&#39;idée de ma dernière &quot;livraison pizza&quot;) Ce n&#39;est pas acceptable…</p>
<h2 id="article-conclusion">Conclusion<a href="#article-conclusion" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Pas un article fun, pas un article technique, mais un article important. Si le sujet vous intéresse, je vous recommande le livre <a href="https://www.babelio.com/livres/Isnards-Lopen-space-ma-tuer/1271110">L&#39;open space m&#39;a tuer</a> qui va beaucoup plus loin.</p>
<p>Dans tous les cas : je ne cherche pas à vous blâmer, vous pointer du doigt, vous faire vous sentir mal si vous vivez cette situation. Je pense que c&#39;est important de prendre conscience du problème, de prendre conscience que ce n&#39;est pas bon ni pour vous ni pour le projet de sur-travailler.</p>
<p>C&#39;est un peu connexe mais aussi : prenez des pauses ! Je suis clairement un mauvais élève à ce sujet : je prends peu de pause, mais j&#39;en prends quand j&#39;ai besoin ! Et je ne parle pas juste d&#39;aller prendre à boire ou aux toilettes, parfois je sens que je sature, donc je coupe, je lis un article de ma veille, je vais regarder mon téléphone 5min, je me lève pour marcher un peu, ou je change juste complètement de sujet : ça donne une bouffer d&#39;air au cerveau, ça élimine la saturation, ça permet de reprendre efficacement. Mieux vaut couper 5-10min et reprendre à 100%, que faire 3h à 50% parce que vous saturez complètement.</p>
<p>Source :</p>
<ul>
<li><a href="https://fr.wikipedia.org/wiki/Loi_de_Parkinson">Loi de Parkinson</a></li>
<li><a href="https://fr.wikipedia.org/wiki/Workaholisme">Workaholisme</a></li>
<li><a href="https://www.babelio.com/livres/Isnards-Lopen-space-ma-tuer/1271110">L&#39;open space m&#39;a tuer</a> d&#39;Alexandre des Isnards</li>
</ul>
<p>Crédit photo : Générée via Mistral AI avec le prompt suivant :</p>
<blockquote>
<p>A detailed illustration in the style of Studio Ghibli: A red panda (inspired by the Firefox mascot) is trapped inside a giant hamster wheel labeled &#39;heure sup&#39; in bold, orange letters. The red panda is wearing a disheveled business suit, looking extremely exhausted: dark circles under the eyes, a slumped posture, and a worn-out expression. The wheel is surrounded by multiple empty coffee cups (some knocked over), crumpled &#39;Urgent&#39; sticky notes scattered everywhere, and clocks showing midnight.</p>
<p>In the background, an open door reveals a peaceful park with a baby red panda sitting alone outside, looking sad or waiting. The park is bathed in warm, calming colors (soft blues, greens, and sunset oranges), contrasting with the chaotic, warm-toned (reds, oranges) indoor scene. The overall mood highlights the fatigue and stress of overworking, while emphasizing the neglected personal life outside.</p>
<p>The art style should be whimsical yet poignant, with expressive characters and rich textures reminiscent of Studio Ghibli’s storytelling. The lighting should enhance the contrast between the stressful indoor environment and the serene outdoor world.</p>
</blockquote>
]]></content:encoded>
      <dc:creator><![CDATA[Anthony Pena]]></dc:creator>
      <media:content medium="image" url="https://anthonypena.fr/img/cover.min.jpg"/>
    </item>
    <item>
      <title><![CDATA[Créer son layout en CSS sans prise de tête !]]></title>
      <guid isPermaLink="false">2025/12/16/creer-son-layout-en-css-sans-prise-de-tete</guid>
      <description><![CDATA[<p>Les années passant j&#39;ai eu l&#39;occasion de travailler avec pas mal de framework JavaScript, CSS et mêm…</p>
]]></description>
      <link>https://anthonypena.fr/2025/12/16/creer-son-layout-en-css-sans-prise-de-tete/index.html</link>
      <category><![CDATA[CSS]]></category>
      <category><![CDATA[Frontend]]></category>
      <category><![CDATA[Tutoriel]]></category>
      <pubDate>Tue, 16 Dec 2025 07:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>Les années passant j&#39;ai eu l&#39;occasion de travailler avec pas mal de framework JavaScript, CSS et même des bibliothèques de composant. Un truc qui me parait toujours absurde c&#39;est à quel point on travaille avec beaucoup trop de <code>&lt;div&gt;</code> pour tout, qu&#39;on fait des structures HTML non sens alors qu&#39;on peut faire tellement plus simple. Et vous savez le mieux ? Faire simple c&#39;est plus puissant au final ! Je vous montre !</p>
<h2 id="article-posons-le-html">Posons le HTML<a href="#article-posons-le-html" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Comme je l&#39;ai fait dans mes articles CSS récent, je vous donne le HTML, et ensuite : on y touche plus !</p>
<pre><code class="hljs language-Html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>CSS is Magic<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">&quot;stylesheet&quot;</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&quot;../reset.css&quot;</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">&quot;stylesheet&quot;</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&quot;./main.css&quot;</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">&quot;stylesheet&quot;</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&quot;./layouts.css&quot;</span> /&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">header</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&quot;../index.html&quot;</span> <span class="hljs-attr">title</span>=<span class="hljs-string">&quot;Back to home&quot;</span>&gt;</span>🏠<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;layout&quot;</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">style</span>=<span class="hljs-string">&quot;margin-right: 1rem&quot;</span>&gt;</span>Choose a layout:<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span>
          &gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">&quot;radio&quot;</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;layout&quot;</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;none&quot;</span> <span class="hljs-attr">checked</span> /&gt;</span> None&lt;/label
        &gt;
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">&quot;radio&quot;</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;layout&quot;</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;flex&quot;</span> /&gt;</span> Flex<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span>
          &gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">&quot;radio&quot;</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;layout&quot;</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;flex-wrap&quot;</span> /&gt;</span> Flex
          Wrap&lt;/label
        &gt;
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">&quot;radio&quot;</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;layout&quot;</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;grid&quot;</span> /&gt;</span> Grid<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">&quot;radio&quot;</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;layout&quot;</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;bento&quot;</span> /&gt;</span> Bento<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span>
          &gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">&quot;radio&quot;</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;layout&quot;</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;dispatched&quot;</span> /&gt;</span>
          Dispatched&lt;/label
        &gt;
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span>
          &gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">&quot;radio&quot;</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;layout&quot;</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;stairs&quot;</span> /&gt;</span> Stairs
          Grid&lt;/label
        &gt;
      <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">header</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">main</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;container&quot;</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">article</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">&quot;../img/persona/emma.jpg&quot;</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">main</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Dubois Emma<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">em</span>&gt;</span>Chef de projet digital<span class="hljs-tag">&lt;/<span class="hljs-name">em</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">article</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">article</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">&quot;../img/persona/lucas.jpg&quot;</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">main</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Moreau Lucas<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">em</span>&gt;</span>Développeur full-stack<span class="hljs-tag">&lt;/<span class="hljs-name">em</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">article</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">article</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">&quot;../img/persona/camille.jpg&quot;</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">main</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Lefèvre Camille<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">em</span>&gt;</span>Responsable marketing<span class="hljs-tag">&lt;/<span class="hljs-name">em</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">article</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">article</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">&quot;../img/persona/thomas.jpg&quot;</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">main</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Bernard Thomas<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">em</span>&gt;</span>Data scientist<span class="hljs-tag">&lt;/<span class="hljs-name">em</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">article</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">article</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">&quot;../img/persona/lea.jpg&quot;</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">main</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Petit Léa<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">em</span>&gt;</span>Designer UX/UI<span class="hljs-tag">&lt;/<span class="hljs-name">em</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">article</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">article</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">&quot;../img/persona/antoine.jpg&quot;</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">main</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Girard Antoine<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">em</span>&gt;</span>Responsable logistique<span class="hljs-tag">&lt;/<span class="hljs-name">em</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">article</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span><div aria-hidden="true" class="language-tag">Html</div>
</code></pre><p>Le code HTML contient une structure basique, le menu en haut dans une balise <code>&lt;header&gt;</code>, puis un ensemble de carte pour afficher des personnes sous la forme d&#39;une série d&#39;<code>&lt;article&gt;</code> dans une balise <code>&lt;main&gt;</code>.</p>
<p>Je vous donne aussi les fichiers de styles de base.</p>
<p>Le <code>reset.css</code> qui va nous donner une base de style plus propre :</p>
<pre><code class="hljs language-CSS">*,
*<span class="hljs-selector-pseudo">::before</span>,
*<span class="hljs-selector-pseudo">::after</span> {
  <span class="hljs-attribute">box-sizing</span>: border-box;
}

<span class="hljs-selector-tag">body</span> {
  <span class="hljs-attribute">margin</span>: unset;
}

<span class="hljs-selector-tag">button</span>,
<span class="hljs-selector-tag">input</span>,
<span class="hljs-selector-tag">textarea</span>,
<span class="hljs-selector-tag">select</span> {
  <span class="hljs-attribute">font</span>: inherit;
}

<span class="hljs-selector-tag">img</span>,
<span class="hljs-selector-tag">picture</span>,
<span class="hljs-selector-tag">svg</span>,
<span class="hljs-selector-tag">canvas</span> {
  <span class="hljs-attribute">display</span>: block;
  <span class="hljs-attribute">max-inline-size</span>: <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">block-size</span>: auto;
}

<span class="hljs-keyword">@media</span> (<span class="hljs-attribute">prefers-reduced-motion</span>: reduce) {
  *,
  *<span class="hljs-selector-pseudo">::before</span>,
  *<span class="hljs-selector-pseudo">::after</span> {
    <span class="hljs-attribute">animation-duration</span>: <span class="hljs-number">0.01ms</span> <span class="hljs-meta">!important</span>;
    <span class="hljs-attribute">animation-iteration-count</span>: <span class="hljs-number">1</span> <span class="hljs-meta">!important</span>;
    <span class="hljs-attribute">transition-duration</span>: <span class="hljs-number">0.01ms</span> <span class="hljs-meta">!important</span>;
    <span class="hljs-attribute">scroll-behavior</span>: auto <span class="hljs-meta">!important</span>;
  }
}<div aria-hidden="true" class="language-tag">CSS</div>
</code></pre><p>Et le <code>main.css</code> qui va essentiellement contenir le style du menu et des cartes des personnes :</p>
<pre><code class="hljs language-CSS"><span class="hljs-comment">/* HEADER */</span>
<span class="hljs-selector-tag">body</span> {
  &amp; &gt; <span class="hljs-selector-tag">header</span> {
    <span class="hljs-attribute">display</span>: flex;
    <span class="hljs-attribute">justify-content</span>: stretch;
    <span class="hljs-attribute">align-items</span>: center;
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">1rem</span>;
    <span class="hljs-attribute">background-color</span>: black;
    <span class="hljs-attribute">color</span>: white;

    <span class="hljs-selector-tag">a</span> {
      <span class="hljs-attribute">font-size</span>: <span class="hljs-number">2rem</span>;
      <span class="hljs-attribute">line-height</span>: <span class="hljs-number">2rem</span>;
    }
    <span class="hljs-selector-tag">form</span> {
      <span class="hljs-attribute">flex</span>: <span class="hljs-number">1</span>;
      <span class="hljs-attribute">display</span>: flex;
      <span class="hljs-attribute">justify-content</span>: center;
      <span class="hljs-attribute">align-items</span>: baseline;
      <span class="hljs-selector-tag">label</span> {
        <span class="hljs-attribute">padding</span>: <span class="hljs-number">0.5rem</span> <span class="hljs-number">1rem</span>;
        <span class="hljs-comment">/* transition: background-color 0.5s; */</span>
        <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">1rem</span>;
        <span class="hljs-attribute">cursor</span>: pointer;

        <span class="hljs-selector-tag">input</span><span class="hljs-selector-attr">[type=<span class="hljs-string">&quot;radio&quot;</span>]</span> {
          <span class="hljs-attribute">width</span>: <span class="hljs-number">1</span>;
          <span class="hljs-attribute">height</span>: <span class="hljs-number">1</span>;
          <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span>;
          <span class="hljs-attribute">position</span>: absolute;
          <span class="hljs-attribute">top</span>: <span class="hljs-number">0</span>;
          <span class="hljs-attribute">left</span>: <span class="hljs-number">0</span>;
          <span class="hljs-attribute">opacity</span>: <span class="hljs-number">0</span>;
        }

        &amp;<span class="hljs-selector-pseudo">:has</span>(<span class="hljs-selector-tag">input</span><span class="hljs-selector-pseudo">:checked</span>) {
          <span class="hljs-attribute">background-color</span>: lightgrey;
          <span class="hljs-attribute">color</span>: black;
        }
      }
    }
  }
}

<span class="hljs-comment">/* CARD */</span>
<span class="hljs-selector-tag">article</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">flex-direction</span>: column;
  <span class="hljs-attribute">justify-content</span>: space-around;
  <span class="hljs-attribute">align-content</span>: space-around;
  <span class="hljs-attribute">background-color</span>: antiquewhite;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">1rem</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">0.5rem</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
  <span class="hljs-selector-tag">img</span> {
    <span class="hljs-attribute">object-fit</span>: cover;
    <span class="hljs-attribute">aspect-ratio</span>: <span class="hljs-number">1</span>/<span class="hljs-number">1</span>;
    <span class="hljs-attribute">max-width</span>: <span class="hljs-number">100%</span>;
    <span class="hljs-attribute">max-height</span>: <span class="hljs-built_in">calc</span>(<span class="hljs-number">100%</span> - <span class="hljs-number">3em</span>);
    <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">50%</span>;
    <span class="hljs-attribute">border</span>: <span class="hljs-number">3px</span> solid chocolate;
    <span class="hljs-attribute">margin</span>: auto;
  }
  <span class="hljs-selector-tag">main</span> {
    <span class="hljs-attribute">text-align</span>: center;
    <span class="hljs-selector-tag">p</span>,
    <span class="hljs-selector-tag">em</span> {
      <span class="hljs-attribute">line-height</span>: <span class="hljs-number">1em</span>;
      <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">0</span>;
      <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">0</span>;
    }
  }
}

<span class="hljs-comment">/* LAYOUTS */</span>
<span class="hljs-selector-id">#container</span> {
  <span class="hljs-attribute">width</span>: fit-content;
  <span class="hljs-attribute">margin</span>: auto;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">1rem</span>;
}<div aria-hidden="true" class="language-tag">CSS</div>
</code></pre><p>Pour l&#39;instant dans le fichier <code>layouts.css</code>, on va juste mettre ça : </p>
<pre><code class="hljs language-CSS"><span class="hljs-selector-id">#container</span> {
  <span class="hljs-attr">--card-size</span>: <span class="hljs-number">18rem</span>;
}

<span class="hljs-selector-tag">body</span><span class="hljs-selector-pseudo">:has</span>(<span class="hljs-selector-tag">header</span> <span class="hljs-selector-tag">form</span> <span class="hljs-selector-tag">input</span><span class="hljs-selector-attr">[name=<span class="hljs-string">&quot;layout&quot;</span>]</span><span class="hljs-selector-attr">[value=<span class="hljs-string">&quot;none&quot;</span>]</span><span class="hljs-selector-pseudo">:checked</span>) {
  <span class="hljs-selector-id">#container</span> {
    <span class="hljs-selector-tag">article</span> {
      <span class="hljs-attribute">max-width</span>: <span class="hljs-built_in">var</span>(--card-size);
    }
  }
}<div aria-hidden="true" class="language-tag">CSS</div>
</code></pre><p>Ce morceau de code va permettre d&#39;avoir accès à la taille de la carte partout pour la suite. La taille de 18rem (pour rappel 1rem = 1 fois la largeur du caractère m dans la taille de police utilisé par défaut dans la page) est purement arbitraire.</p>
<p>J&#39;en profite pour définir le premier layout &quot;none&quot; qui va uniquement forcer une taille raisonnable de chaque carte en se basant sur un menu fonctionnant de la même façon que décrit dans l&#39;article <a href="/articles/2025/10/28/un-menu-100-en-css/">Un menu 100% en CSS</a>.</p>
<p>Normalement, vous devriez avoir ça :</p>
<figure>
<img src="https://anthonypena.fr/2025/12/16/creer-son-layout-en-css-sans-prise-de-tete/img/layout-0-none.png" alt="Vue de l&#39;appli avec le style de base" is="img-zoom"/>
<figcaption>Vue de l&#39;appli avec le style de base</figcaption>
</figure>
<p>À partir de maintenant, on ne va toucher qu&#39;au fichier <code>layouts.css</code> pour créer 6 layouts différents.</p>
<h2 id="article-layout-1--flex">Layout 1 : Flex<a href="#article-layout-1--flex" class="anchor" aria-label="permalink">🔗</a></h2>
<p>C&#39;est basique, mais on a tendance à oublier les basiques donc un petit rappel ne fait pas de mal.</p>
<p>Ajoutons à <code>layouts.css</code> ce code :</p>
<pre><code class="hljs language-CSS">...
<span class="hljs-selector-tag">body</span><span class="hljs-selector-pseudo">:has</span>(<span class="hljs-selector-tag">header</span> <span class="hljs-selector-tag">form</span> <span class="hljs-selector-tag">input</span><span class="hljs-selector-attr">[name=<span class="hljs-string">&quot;layout&quot;</span>]</span><span class="hljs-selector-attr">[value=<span class="hljs-string">&quot;flex&quot;</span>]</span><span class="hljs-selector-pseudo">:checked</span>) {
  <span class="hljs-selector-id">#container</span> {
    <span class="hljs-attribute">display</span>: flex;
    <span class="hljs-attribute">gap</span>: <span class="hljs-number">0.5rem</span>;
  }
}<div aria-hidden="true" class="language-tag">CSS</div>
</code></pre><p>On dit simplement que notre <code>#container</code> est en <code>display: flex</code>, ce qui implicitement indique <code>flex-direction: row</code> (donc en ligne), puis on ajoute aussi un <code>gap: 0.5rem</code> pour avoir un peu d&#39;espace entre nos cartes.</p>
<figure>
<img src="https://anthonypena.fr/2025/12/16/creer-son-layout-en-css-sans-prise-de-tete/img/layout-1-flex.png" alt="Vue de l&#39;appli avec un layout flex" is="img-zoom"/>
<figcaption>Vue de l&#39;appli avec un layout flex</figcaption>
</figure>
<p>Avec deux lignes de CSS, on passe toutes nos cartes en ligne, et qui tiennent dans la largeur de la page. Évidemment ce n&#39;est pas parfait, typiquement, sur mobile ça ne va pas bien se comporter et le contenu va être tout tassé et finira même par déborder de l&#39;écran. Mais si on a peu d&#39;élément ça peut largement suffire !</p>
<h2 id="article-layout-2--flex-wrap">Layout 2 : Flex wrap<a href="#article-layout-2--flex-wrap" class="anchor" aria-label="permalink">🔗</a></h2>
<pre><code class="hljs language-CSS"><span class="hljs-selector-tag">body</span><span class="hljs-selector-pseudo">:has</span>(<span class="hljs-selector-tag">header</span> <span class="hljs-selector-tag">form</span> <span class="hljs-selector-tag">input</span><span class="hljs-selector-attr">[name=<span class="hljs-string">&quot;layout&quot;</span>]</span><span class="hljs-selector-attr">[value=<span class="hljs-string">&quot;flex-wrap&quot;</span>]</span><span class="hljs-selector-pseudo">:checked</span>) {
  <span class="hljs-selector-id">#container</span> {
    <span class="hljs-attribute">display</span>: flex;
    <span class="hljs-attribute">flex-wrap</span>: wrap;
    <span class="hljs-attribute">justify-content</span>: center;
    <span class="hljs-attribute">gap</span>: <span class="hljs-number">0.5rem</span>;

    <span class="hljs-selector-tag">article</span> {
      <span class="hljs-attribute">max-width</span>: <span class="hljs-built_in">var</span>(--card-size);
    }
  }
}<div aria-hidden="true" class="language-tag">CSS</div>
</code></pre><figure id="image-gallery-vue-de-lappli-avec-un-layout-flex-wrap" class="marked-image-gallery" is="gallery-zoom">
<img src="https://anthonypena.fr/2025/12/16/creer-son-layout-en-css-sans-prise-de-tete/img/layout-2-flex-wrap-1.png" alt="Vue de l&#39;appli avec un layout flex wrap"/>
<img src="https://anthonypena.fr/2025/12/16/creer-son-layout-en-css-sans-prise-de-tete/img/layout-2-flex-wrap-2.png" alt="Vue de l&#39;appli avec un layout flex wrap"/>
<img src="https://anthonypena.fr/2025/12/16/creer-son-layout-en-css-sans-prise-de-tete/img/layout-2-flex-wrap-3.png" alt="Vue de l&#39;appli avec un layout flex wrap"/>
<img src="https://anthonypena.fr/2025/12/16/creer-son-layout-en-css-sans-prise-de-tete/img/layout-2-flex-wrap-4.png" alt="Vue de l&#39;appli avec un layout flex wrap"/>
<figcaption>Vue de l&#39;appli avec un layout flex wrap</figcaption>
</figure>
<p>Toujours très simple, on ajoute juste <code>flex-wrap: wrap</code> pour faire en sorte de faire un retour à la ligne quand il n&#39;y a plus de place plutôt que réduire la largeur, et on indique qu&#39;on veut centrer le contenu avec <code>justify-content: center</code>.</p>
<p>On ne le voit pas dans l&#39;exemple mais ces 4 lignes de CSS permettent d&#39;auto-ajuster la répartition des éléments en fonction de la largeur disponible et de chaque élément.</p>
<p>Je vous montre un autre exemple :</p>
<figure>
<img src="https://anthonypena.fr/2025/12/16/creer-son-layout-en-css-sans-prise-de-tete/img/layout-2-flex-wrap-dossier.png" alt="Aperçu d&#39;un autre cas d&#39;usage de flex wrap" is="img-zoom"/>
<figcaption>Aperçu d&#39;un autre cas d&#39;usage de flex wrap</figcaption>
</figure>
<p>En ne gardant que le style du layout j&#39;ai ça :</p>
<pre><code class="hljs language-CSS"><span class="hljs-selector-class">.key-figures</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">flex-wrap</span>: wrap;
  <span class="hljs-attribute">gap</span>: <span class="hljs-number">2rem</span>;
  <span class="hljs-selector-class">.figure-card</span> {
    <span class="hljs-attribute">flex</span>: <span class="hljs-number">1</span> <span class="hljs-number">1</span> auto;
  }
}<div aria-hidden="true" class="language-tag">CSS</div>
</code></pre><blockquote>
<p><code>flex: 1 1 auto</code> étant la version raccourcie de <code>flex-grow: 1</code> (= grandi en fonction de la place disponible) + <code>flex-shrink: 1</code> (= réduit en fonction de la place disponible) + <code>flex-grow: auto</code> (= auto détermine la taille de base).</p>
</blockquote>
<p>Ici j&#39;ai des cartes dont la largeur est automatiquement calculée pour prendre l&#39;espace disponible, automatiquement réparti sur deux lignes, et sans dire comment. Les flex layout sont disponibles depuis assez longtemps maintenant pourtant c&#39;est encore trop peu/mal utilisé à mon sens.</p>
<p>Avant de passer à un autre type de layout, je vous dirais une règle simple : les flex layouts sont à utiliser partout où on veut que le layout s&#39;adapte au contenu.</p>
<h2 id="article-layout-3--grid">Layout 3 : Grid<a href="#article-layout-3--grid" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Maintenant on va partir sur une série de quatre layouts basé sur <code>display: grid</code>, qui à l&#39;inverse de flex est orienté layout, donc on va poser le layout et le contenu va s&#39;adapter au layout.</p>
<pre><code class="hljs language-CSS"><span class="hljs-selector-tag">body</span><span class="hljs-selector-pseudo">:has</span>(<span class="hljs-selector-tag">header</span> <span class="hljs-selector-tag">form</span> <span class="hljs-selector-tag">input</span><span class="hljs-selector-attr">[name=<span class="hljs-string">&quot;layout&quot;</span>]</span><span class="hljs-selector-attr">[value=<span class="hljs-string">&quot;grid&quot;</span>]</span><span class="hljs-selector-pseudo">:checked</span>) {
  <span class="hljs-selector-id">#container</span> {
    <span class="hljs-attribute">display</span>: grid;
    <span class="hljs-attribute">grid-template-columns</span>: <span class="hljs-number">1</span>fr <span class="hljs-number">1</span>fr;
    <span class="hljs-attribute">justify-items</span>: center;
    <span class="hljs-attribute">gap</span>: <span class="hljs-number">0.5rem</span>;
    <span class="hljs-keyword">@media</span> screen <span class="hljs-keyword">and</span> (<span class="hljs-attribute">width</span> &gt; <span class="hljs-number">90rem</span>) {
      <span class="hljs-attribute">grid-template-columns</span>: <span class="hljs-number">1</span>fr <span class="hljs-number">1</span>fr <span class="hljs-number">1</span>fr;
    }
    <span class="hljs-keyword">@media</span> screen <span class="hljs-keyword">and</span> (<span class="hljs-attribute">width</span> &gt; <span class="hljs-number">110rem</span>) {
      <span class="hljs-attribute">grid-template-columns</span>: <span class="hljs-number">1</span>fr <span class="hljs-number">1</span>fr <span class="hljs-number">1</span>fr <span class="hljs-number">1</span>fr;
    }
    <span class="hljs-keyword">@media</span> screen <span class="hljs-keyword">and</span> (<span class="hljs-attribute">width</span> &gt; <span class="hljs-number">130rem</span>) {
      <span class="hljs-attribute">grid-template-columns</span>: <span class="hljs-number">1</span>fr <span class="hljs-number">1</span>fr <span class="hljs-number">1</span>fr <span class="hljs-number">1</span>fr <span class="hljs-number">1</span>fr;
    }
    <span class="hljs-selector-tag">article</span> {
      <span class="hljs-attribute">width</span>: <span class="hljs-built_in">var</span>(--card-size);
    }
  }
}<div aria-hidden="true" class="language-tag">CSS</div>
</code></pre><figure id="image-gallery-vue-de-lappli-avec-un-layout-flex-grid" class="marked-image-gallery" is="gallery-zoom">
<img src="https://anthonypena.fr/2025/12/16/creer-son-layout-en-css-sans-prise-de-tete/img/layout-3-grid-1.png" alt="Vue de l&#39;appli avec un layout flex grid"/>
<img src="https://anthonypena.fr/2025/12/16/creer-son-layout-en-css-sans-prise-de-tete/img/layout-3-grid-2.png" alt="Vue de l&#39;appli avec un layout flex grid"/>
<img src="https://anthonypena.fr/2025/12/16/creer-son-layout-en-css-sans-prise-de-tete/img/layout-3-grid-3.png" alt="Vue de l&#39;appli avec un layout flex grid"/>
<figcaption>Vue de l&#39;appli avec un layout flex grid</figcaption>
</figure>
<p>Ici j&#39;ai mis en place une grille très simple, avec une répartition sur 2 à 5 colonnes en fonction de la largeur de l&#39;écran.</p>
<p>En ne définissant que la propriété <code>grid-template-columns</code> on va indiquer le pattern de chaque ligne (je sais que c&#39;est indiqué <code>-columns</code> mais c&#39;est logique, car on définit la taille de chaque colonne sur une ligne), en ne définissant que ça on va avoir automatiquement un nombre de ligne qui s&#39;adapte au contenu. J&#39;indique aussi <code>justify-items: center</code> pour que l&#39;espace en trop soit réparti à gauche et à droite de la grille équitablement.</p>
<p>Ici on est sur une grille très simple mais c&#39;est super efficace en fonction de ce qu&#39;on souhaite faire !</p>
<h2 id="article-layout-4--bento">Layout 4 : Bento<a href="#article-layout-4--bento" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Passons à un layout intéressant : le bento. On en voit régulièrement, un peu partout pour afficher plein de cartes mais en mettant en avant plus ou moins certaines, parfois aussi avec des animations. Ici nous allons faire un bento simple, sans animation.</p>
<pre><code class="hljs language-CSS"><span class="hljs-selector-tag">body</span><span class="hljs-selector-pseudo">:has</span>(<span class="hljs-selector-tag">header</span> <span class="hljs-selector-tag">form</span> <span class="hljs-selector-tag">input</span><span class="hljs-selector-attr">[name=<span class="hljs-string">&quot;layout&quot;</span>]</span><span class="hljs-selector-attr">[value=<span class="hljs-string">&quot;bento&quot;</span>]</span><span class="hljs-selector-pseudo">:checked</span>) {
  <span class="hljs-selector-id">#container</span> {
    <span class="hljs-attribute">display</span>: grid;
    <span class="hljs-attribute">grid-template-columns</span>: <span class="hljs-built_in">repeat</span>(<span class="hljs-number">4</span>, <span class="hljs-built_in">var</span>(--card-size));
    <span class="hljs-attribute">grid-template-rows</span>: <span class="hljs-built_in">repeat</span>(<span class="hljs-number">3</span>, <span class="hljs-built_in">var</span>(--card-size));
    <span class="hljs-attribute">align-items</span>: center;
    <span class="hljs-attribute">justify-items</span>: center;
    <span class="hljs-attribute">gap</span>: <span class="hljs-number">0.5rem</span>;

    &amp; &gt; <span class="hljs-selector-tag">article</span> {
      <span class="hljs-attribute">max-width</span>: unset;
      <span class="hljs-attribute">max-height</span>: <span class="hljs-number">100%</span>;
    }

    &amp; &gt; <span class="hljs-selector-pseudo">:nth-child</span>(<span class="hljs-number">1</span>) {
      <span class="hljs-attribute">grid-column</span>: auto / span <span class="hljs-number">2</span>;
      <span class="hljs-attribute">grid-row</span>: auto / span <span class="hljs-number">2</span>;
    }
    &amp; &gt; <span class="hljs-selector-pseudo">:nth-child</span>(<span class="hljs-number">2</span>) {
      <span class="hljs-attribute">grid-column</span>: auto / span <span class="hljs-number">1</span>;
      <span class="hljs-attribute">grid-row</span>: auto / span <span class="hljs-number">1</span>;
    }
    &amp; &gt; <span class="hljs-selector-pseudo">:nth-child</span>(<span class="hljs-number">3</span>) {
      <span class="hljs-attribute">grid-column</span>: auto / span <span class="hljs-number">1</span>;
      <span class="hljs-attribute">grid-row</span>: auto / span <span class="hljs-number">2</span>;
      <span class="hljs-attribute">aspect-ratio</span>: <span class="hljs-number">1</span>/<span class="hljs-number">2</span>;
    }
    &amp; &gt; <span class="hljs-selector-pseudo">:nth-child</span>(<span class="hljs-number">4</span>) {
      <span class="hljs-attribute">grid-column</span>: auto / span <span class="hljs-number">1</span>;
      <span class="hljs-attribute">grid-row</span>: auto / span <span class="hljs-number">2</span>;
      <span class="hljs-attribute">aspect-ratio</span>: <span class="hljs-number">1</span>/<span class="hljs-number">2</span>;
    }
    &amp; &gt; <span class="hljs-selector-pseudo">:nth-child</span>(<span class="hljs-number">5</span>) {
      <span class="hljs-attribute">grid-column</span>: auto / span <span class="hljs-number">2</span>;
      <span class="hljs-attribute">grid-row</span>: auto / span <span class="hljs-number">1</span>;
      <span class="hljs-attribute">aspect-ratio</span>: <span class="hljs-number">2</span>/<span class="hljs-number">1</span>;
    }
    &amp; &gt; <span class="hljs-selector-pseudo">:nth-child</span>(<span class="hljs-number">6</span>) {
      <span class="hljs-attribute">grid-column</span>: auto / span <span class="hljs-number">1</span>;
      <span class="hljs-attribute">grid-row</span>: auto / span <span class="hljs-number">1</span>;
    }
  }
}<div aria-hidden="true" class="language-tag">CSS</div>
</code></pre><figure>
<img src="https://anthonypena.fr/2025/12/16/creer-son-layout-en-css-sans-prise-de-tete/img/layout-4-bento.png" alt="Vue de l&#39;appli avec un layout bento" is="img-zoom"/>
<figcaption>Vue de l&#39;appli avec un layout bento</figcaption>
</figure>
<p>L&#39;idée ici c&#39;est de commencer par construire une grille plus grande que ce dont on aurait besoin pour nos cartes (on a 6 cartes, j&#39;ai créé une grille de 4 par 3 donc 12 cases). Ensuite on va placer chaque carte une par une sur notre grille en définissant sa colonne et ligne de départ et le nombre de case à occuper dans chaque direction.</p>
<p>Si on regarde un des positionnements, par exemple le premier :</p>
<pre><code class="hljs language-CSS">&amp; &gt; <span class="hljs-selector-pseudo">:nth-child</span>(<span class="hljs-number">1</span>) {
  <span class="hljs-attribute">grid-column</span>: auto / span <span class="hljs-number">2</span>;
  <span class="hljs-attribute">grid-row</span>: auto / span <span class="hljs-number">2</span>;
}<div aria-hidden="true" class="language-tag">CSS</div>
</code></pre><p>On voit <code>grid-column: auto / span 2;</code>, ici <code>auto</code> signifiant &quot;place à la prochaine case disponible&quot; et <code>span 2</code> signifie &quot;doit s&#39;étaler sur 2 colonnes&quot;. Dans la même logique <code>grid-row: auto / span 2</code> indique de placer dès que possible en s&#39;étalant sur 2 lignes.</p>
<p>On aurait pu choisir explicitement l&#39;emplacement de chaque carte mais c&#39;est beaucoup plus simple de laisser le navigateur choisir, par contre ça veut aussi dire que c&#39;est le navigateur qui choisit l&#39;emplacement. Même si normalement on observera toujours le même placement avec un remplissage &quot;ligne à ligne&quot;.</p>
<figure>
<img src="https://anthonypena.fr/2025/12/16/creer-son-layout-en-css-sans-prise-de-tete/img/layout-4-bento-2.png" alt="Vue du bento avec le numéro de child" is="img-zoom"/>
<figcaption>Vue du bento avec le numéro de child</figcaption>
</figure>
<p>J&#39;ai besoin de jouer avec l&#39;aspect-ratio de chaque élément parce que dans le style de la carte j&#39;ai forcé un aspect-ratio, donc si vous n&#39;en avez pas à la base, vous pouvez surement vous en passer aussi (en fonction du rendu que vous voulez avoir), mais personnellement je voulais m&#39;assurer d&#39;avoir une grille parfaitement régulière.</p>
<h2 id="article-layout-5--dispatched">Layout 5 : Dispatched<a href="#article-layout-5--dispatched" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Comme les grilles c&#39;est magique (non c&#39;est juste bien pensé 😛), on peut aussi laisser des cases vides dans la grille et positionner dans un ordre arbitraire les différentes cartes.</p>
<pre><code class="hljs language-CSS"><span class="hljs-selector-tag">body</span><span class="hljs-selector-pseudo">:has</span>(<span class="hljs-selector-tag">header</span> <span class="hljs-selector-tag">form</span> <span class="hljs-selector-tag">input</span><span class="hljs-selector-attr">[name=<span class="hljs-string">&quot;layout&quot;</span>]</span><span class="hljs-selector-attr">[value=<span class="hljs-string">&quot;dispatched&quot;</span>]</span><span class="hljs-selector-pseudo">:checked</span>) {
  <span class="hljs-selector-id">#container</span> {
    <span class="hljs-attribute">display</span>: grid;
    <span class="hljs-attribute">grid-template</span>:
      <span class="hljs-string">&quot;. one three&quot;</span> <span class="hljs-built_in">var</span>(--card-size)
      <span class="hljs-string">&quot;six four .&quot;</span> <span class="hljs-built_in">var</span>(--card-size)
      <span class="hljs-string">&quot;five four two&quot;</span> <span class="hljs-built_in">var</span>(--card-size)
      / <span class="hljs-built_in">var</span>(--card-size) <span class="hljs-built_in">var</span>(--card-size) <span class="hljs-built_in">var</span>(--card-size);
    <span class="hljs-attribute">align-items</span>: center;
    <span class="hljs-attribute">justify-items</span>: center;
    <span class="hljs-attribute">gap</span>: <span class="hljs-number">0.5rem</span>;

    &amp; &gt; <span class="hljs-selector-pseudo">:nth-child</span>(<span class="hljs-number">1</span>) {
      <span class="hljs-attribute">grid-area</span>: one;
    }
    &amp; &gt; <span class="hljs-selector-pseudo">:nth-child</span>(<span class="hljs-number">2</span>) {
      <span class="hljs-attribute">grid-area</span>: two;
    }
    &amp; &gt; <span class="hljs-selector-pseudo">:nth-child</span>(<span class="hljs-number">3</span>) {
      <span class="hljs-attribute">grid-area</span>: three;
    }
    &amp; &gt; <span class="hljs-selector-pseudo">:nth-child</span>(<span class="hljs-number">4</span>) {
      <span class="hljs-attribute">grid-area</span>: four;
    }
    &amp; &gt; <span class="hljs-selector-pseudo">:nth-child</span>(<span class="hljs-number">5</span>) {
      <span class="hljs-attribute">grid-area</span>: five;
    }
    &amp; &gt; <span class="hljs-selector-pseudo">:nth-child</span>(<span class="hljs-number">6</span>) {
      <span class="hljs-attribute">grid-area</span>: six;
    }
  }
}<div aria-hidden="true" class="language-tag">CSS</div>
</code></pre><figure>
<img src="https://anthonypena.fr/2025/12/16/creer-son-layout-en-css-sans-prise-de-tete/img/layout-5-dispatched.png" alt="Vue de l&#39;appli avec un layout dispatched" is="img-zoom"/>
<figcaption>Vue de l&#39;appli avec un layout dispatched</figcaption>
</figure>
<p>C&#39;est finalement assez simple à comprendre pourtant c&#39;est hyper puissant ! Avec la propriété <code>grid-template</code> on va &quot;dessiner&quot; notre grille en nommant les différentes zones qu&#39;on veut placer et en définissant la taille des éléments. Le fonctionnement est je trouve très visuel : on va définir une chaîne de caractère pour chaque ligne, sur chaque ligne on nomme les différentes zones qui sont visibles (un <code>.</code> signifiant &quot;vide&quot;), après le contenu de la ligne on indique la hauteur de la ligne, et on enchaîne comme ça toutes les lignes jusqu&#39;à un <code>/</code> suivi de la taille des colonnes.</p>
<p>Si je prends l&#39;exemple que j&#39;ai écrit <code>&quot;. one three&quot; var(--card-size)</code> va indiquer que la première ligne contient une case vide puis la zone <code>one</code>, puis la zone <code>three</code> et elle doit avoir une hauteur d&#39;une carte ; ensuite la seconde ligne <code>&quot;six four .&quot; var(--card-size)</code> la zone <code>six</code> puis <code>four</code> puis vide ; ensuite la troisième ligne <code>&quot;five four two&quot; var(--card-size)</code> indique qu&#39;on veut la zone <code>five</code> puis <code>four</code> puis <code>two</code>. Vous noterez bien que la zone <code>four</code> est à cheval entre la ligne 2 et 3 ce qui permet qu&#39;elle soit plus grande.</p>
<p>Puis pour chaque carte on va définir sur quelle zone on souhaite l&#39;afficher avec <code>grid-area</code> (attention à ne pas mettre de <code>&quot;</code> sur cette propriété, ça ne fonctionnera).</p>
<p>Les noms des zones sont arbitraires et vous pouvez donc être super explicite avec ce nommage. Par exemple :</p>
<pre><code class="hljs language-CSS"><span class="hljs-selector-tag">body</span> {
  <span class="hljs-attribute">grid-template</span>: 
    <span class="hljs-string">&quot;header header&quot;</span> / <span class="hljs-number">5rem</span>
    <span class="hljs-string">&quot;main aside&quot;</span> / <span class="hljs-number">1</span>fr
    <span class="hljs-string">&quot;main .&quot;</span> / <span class="hljs-number">1</span>fr
    <span class="hljs-string">&quot;footer footer&quot;</span> / <span class="hljs-number">10rem</span>
    / <span class="hljs-number">2</span>fr <span class="hljs-number">1</span>fr ;
}<div aria-hidden="true" class="language-tag">CSS</div>
</code></pre><p>fonctionnera aussi bien que</p>
<pre><code class="hljs language-CSS"><span class="hljs-selector-tag">body</span> {
  <span class="hljs-attribute">grid-template</span>: 
    <span class="hljs-string">&quot;h h&quot;</span> / <span class="hljs-number">5rem</span>
    <span class="hljs-string">&quot;m a&quot;</span> / <span class="hljs-number">1</span>fr
    <span class="hljs-string">&quot;m .&quot;</span> / <span class="hljs-number">1</span>fr
    <span class="hljs-string">&quot;f f&quot;</span> / <span class="hljs-number">10rem</span>
    / <span class="hljs-number">2</span>fr <span class="hljs-number">1</span>fr ;
}<div aria-hidden="true" class="language-tag">CSS</div>
</code></pre><p>Mais la première version est quand même beaucoup plus simple à relire et donc à favoriser !</p>
<h2 id="article-layout-6--stairs-grid">Layout 6 : Stairs grid<a href="#article-layout-6--stairs-grid" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Pour tout vous dire, c&#39;est en construisant un layout comme ça que j&#39;ai eu l&#39;idée d&#39;écrire cet article ! 🤓</p>
<p>L&#39;idée ici c&#39;est de placer tous les éléments en &quot;escalier&quot; : le premier élément, puis le suivant à droite juste à moitié plus bas, puis en continuant de remplir comme ça.</p>
<pre><code class="hljs language-CSS"><span class="hljs-selector-tag">body</span><span class="hljs-selector-pseudo">:has</span>(<span class="hljs-selector-tag">header</span> <span class="hljs-selector-tag">form</span> <span class="hljs-selector-tag">input</span><span class="hljs-selector-attr">[name=<span class="hljs-string">&quot;layout&quot;</span>]</span><span class="hljs-selector-attr">[value=<span class="hljs-string">&quot;stairs&quot;</span>]</span><span class="hljs-selector-pseudo">:checked</span>) {
  <span class="hljs-selector-id">#container</span> {
    <span class="hljs-attribute">display</span>: grid;
    <span class="hljs-attribute">grid-template</span>:
      <span class="hljs-string">&quot;one .&quot;</span> <span class="hljs-number">1</span>fr
      <span class="hljs-string">&quot;one two&quot;</span> <span class="hljs-number">1</span>fr
      <span class="hljs-string">&quot;three two&quot;</span> <span class="hljs-number">1</span>fr
      <span class="hljs-string">&quot;three four&quot;</span> <span class="hljs-number">1</span>fr
      <span class="hljs-string">&quot;five four&quot;</span> <span class="hljs-number">1</span>fr
      <span class="hljs-string">&quot;five six&quot;</span> <span class="hljs-number">1</span>fr
      <span class="hljs-string">&quot;. six&quot;</span> <span class="hljs-number">1</span>fr
      / <span class="hljs-built_in">var</span>(--card-size) <span class="hljs-built_in">var</span>(--card-size);
    <span class="hljs-keyword">@media</span> screen <span class="hljs-keyword">and</span> (<span class="hljs-attribute">width</span> &gt; <span class="hljs-number">90rem</span>) {
      <span class="hljs-attribute">grid-template</span>:
        <span class="hljs-string">&quot;one . .&quot;</span> <span class="hljs-number">1</span>fr
        <span class="hljs-string">&quot;one two .&quot;</span> <span class="hljs-number">1</span>fr
        <span class="hljs-string">&quot;three two four&quot;</span> <span class="hljs-number">1</span>fr
        <span class="hljs-string">&quot;three five four&quot;</span> <span class="hljs-number">1</span>fr
        <span class="hljs-string">&quot;. five six&quot;</span> <span class="hljs-number">1</span>fr
        <span class="hljs-string">&quot;. . six&quot;</span> <span class="hljs-number">1</span>fr
        / <span class="hljs-built_in">var</span>(--card-size) <span class="hljs-built_in">var</span>(--card-size) <span class="hljs-built_in">var</span>(--card-size);
    }
    <span class="hljs-attribute">justify-items</span>: center;
    <span class="hljs-attribute">gap</span>: <span class="hljs-number">0.5rem</span>;

    &amp; &gt; <span class="hljs-selector-pseudo">:nth-child</span>(<span class="hljs-number">1</span>) {
      <span class="hljs-attribute">grid-area</span>: one;
    }
    &amp; &gt; <span class="hljs-selector-pseudo">:nth-child</span>(<span class="hljs-number">2</span>) {
      <span class="hljs-attribute">grid-area</span>: two;
    }
    &amp; &gt; <span class="hljs-selector-pseudo">:nth-child</span>(<span class="hljs-number">3</span>) {
      <span class="hljs-attribute">grid-area</span>: three;
    }
    &amp; &gt; <span class="hljs-selector-pseudo">:nth-child</span>(<span class="hljs-number">4</span>) {
      <span class="hljs-attribute">grid-area</span>: four;
    }
    &amp; &gt; <span class="hljs-selector-pseudo">:nth-child</span>(<span class="hljs-number">5</span>) {
      <span class="hljs-attribute">grid-area</span>: five;
    }
    &amp; &gt; <span class="hljs-selector-pseudo">:nth-child</span>(<span class="hljs-number">6</span>) {
      <span class="hljs-attribute">grid-area</span>: six;
    }
  }
}<div aria-hidden="true" class="language-tag">CSS</div>
</code></pre><figure>
<img src="https://anthonypena.fr/2025/12/16/creer-son-layout-en-css-sans-prise-de-tete/img/layout-6-stairs-grid.png" alt="Vue de l&#39;appli avec un layout stairs grid" is="img-zoom"/>
<figcaption>Vue de l&#39;appli avec un layout stairs grid</figcaption>
</figure>
<p>On voit que c&#39;est assez facile de faire ça au final, il faut juste prendre le temps de définir le template de notre grille correctement.</p>
<h2 id="article-conclusion">Conclusion<a href="#article-conclusion" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Je n&#39;ai clairement pas fait un guide ultime de layout en CSS, certains en lignes le fond clairement bien mieux que moi ! Je vous montre juste quelques exemples de layout qu&#39;on peut réaliser simplement, mais qui demande de comprendre comment fonctionne flex et grid.</p>
<p>Il reste beaucoup de chose à explorer : toutes les propriétés de flex/grid que je n&#39;ai pas utilisé, l&#39;imbrication de flex, l&#39;imbrication de grid, les sub-grid, le mix flex / grid, etc. J&#39;espère juste vous avoir montré qu&#39;avec du CSS moderne on n&#39;a pas besoin d&#39;imbriquer des <code>&lt;div&gt;</code> dans tous sens, d&#39;avoir des <code>class</code> sur tous les éléments, d&#39;avoir un outil &quot;utility-first&quot; à la Tailwind, ou n&#39;importe quoi d&#39;autres pour faire un layout, juste un peu de CSS et se poser sur ce qu&#39;on veut faire.</p>
<p>Source :</p>
<ul>
<li><a href="https://github.com/kuroidoruido/css-is-magic/tree/main/flex-grid">Code source du projet</a></li>
<li><a href="https://css-tricks.com/snippets/css/a-guide-to-flexbox/">Cheat sheet Flexbox</a></li>
<li><a href="https://css-tricks.com/snippets/css/complete-guide-grid/">Cheat sheet Grid</a></li>
<li><a href="https://developer.mozilla.org/fr/docs/Glossary/Flex">CSS Flex (mdn)</a></li>
<li><a href="https://developer.mozilla.org/fr/docs/Web/CSS/Guides/Grid_layout">CSS Grid layout (mdn)</a></li>
<li><a href="https://developer.mozilla.org/fr/docs/Web/CSS/Reference/Properties/grid-template">CSS grid-template (mdn)</a></li>
<li><a href="https://developer.mozilla.org/fr/docs/Web/CSS/Reference/Properties/grid-area">CSS grid-area (mdn)</a></li>
<li><a href="https://developer.mozilla.org/fr/docs/Web/CSS/Reference/Properties/grid-row">CSS grid-row (mdn)</a></li>
<li><a href="https://developer.mozilla.org/fr/docs/Web/CSS/Reference/Properties/grid-column">CSS grid-column (mdn)</a></li>
<li><a href="https://developer.mozilla.org/fr/docs/Web/CSS/Reference/Properties/grid-template-columns">CSS grid-template-columns (mdn)</a></li>
<li><a href="https://developer.mozilla.org/fr/docs/Web/CSS/Reference/Properties/grid-template-rows">CSS grid-template-rows (mdn)</a></li>
</ul>
<p>Crédit photo : Générée via Mistral AI avec le prompt suivant :</p>
<blockquote>
<p>A beautifully detailed 16:9 illustration of a Japanese bento box, divided into compartments that visually represent CSS layout techniques (flex, grid, bento, and stairs). Each compartment contains a cute animal: a red panda in a larger, prominent compartment (symbolizing a hero section), an axolotl in a medium-sized compartment (symbolizing a sidebar or secondary content), and a cat in a smaller compartment (symbolizing a footer or tertiary content). The bento box itself is intricately designed, with wooden textures and soft shadows, evoking the warmth and charm of Studio Ghibli’s art style. </p>
<p>The compartments are organized to reflect different CSS layouts:</p>
<ul>
<li>The top row uses a flex layout, with equal-sized compartments.</li>
<li>The middle row uses a grid layout, with varying compartment sizes.</li>
<li>The bottom row uses a bento layout, with asymmetrical, nested compartments.</li>
<li>The right side features a stairs-like arrangement, with overlapping compartments.</li>
</ul>
<p>Around the bento box, small CSS icons and symbols (like <code>&lt;div&gt;</code>, flexbox, grid, and curly braces {}) float gently, adding a whimsical touch. The background is a dark, minimalist gradient with subtle glowing highlights, reminiscent of a cozy night scene. The animals are expressive and playful: the red panda is holding a tiny HTML tag, the axolotl is peeking out from behind a grid symbol, and the cat is curled up next to a flexbox icon. The lighting is soft and warm, casting gentle shadows and creating a cozy, inviting atmosphere. The overall mood is magical, charming, and creative, celebrating the art of CSS and web design.</p>
</blockquote>
]]></content:encoded>
      <dc:creator><![CDATA[Anthony Pena]]></dc:creator>
      <media:content medium="image" url="https://anthonypena.fr/img/cover.min.jpg"/>
    </item>
    <item>
      <title><![CDATA[Revue de presse - Décembre 2025]]></title>
      <guid isPermaLink="false">2025/12/02/revue-de-presse-decembre</guid>
      <description><![CDATA[]]></description>
      <link>https://anthonypena.fr/2025/12/02/revue-de-presse-decembre/index.html</link>
      <category><![CDATA[Revue de presse]]></category>
      <pubDate>Tue, 02 Dec 2025 07:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<h2 id="article-frontend">Frontend<a href="#article-frontend" class="anchor" aria-label="permalink">🔗</a></h2>
<h3 id="article-le-dev-web-avec-denis-souron---le-permacodeurhttpsyoutube9daemx7jguq"><a href="https://youtu.be/9DAEmX7jguQ">Le Dev Web, avec Denis Souron 🤩 — Le Permacodeur</a><a href="#article-le-dev-web-avec-denis-souron---le-permacodeurhttpsyoutube9daemx7jguq" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#Tech #Web #Frontend</p>
<p><a href="https://youtu.be/9DAEmX7jguQ"><img src="https://anthonypena.fr/2025/12/02/revue-de-presse-decembre/img/youtube-9DAEmX7jguQ.jpg" alt="https://youtu.be/9DAEmX7jguQ" title="Youtube video preview"/></a></p>
<p>Échange super intéressant du Permacodeur (Stéphane Trébel de son vrai nom) et Denis Souron autour du web, de l&#39;IA, de l&#39;industrie de la tech, de comment tout évolue, de plein de trucs !</p>
<p>Y&#39;a des constats que je fais aussi (qui transparaisse dans mes écrits aussi), y&#39;a des trucs que j&#39;avais pas connectés comme ça dans ma tête, y&#39;a des réflexions que je trouve super pertinentes, ça me donne aussi envie de refaire du Rust (alors que c&#39;est pas vraiment le propos) !</p>
<p>En tout cas : ça vaut vraiment le coup d&#39;écouter ça !</p>
<h3 id="article-create-inverted-borders-with-smooth-hover-animation-using-css--sumod-panickerhttpsyoutubel4svea3svy"><a href="https://youtu.be/L4svea3-svY">Create Inverted Borders with Smooth Hover Animation using CSS — @Sumod Panicker</a><a href="#article-create-inverted-borders-with-smooth-hover-animation-using-css--sumod-panickerhttpsyoutubel4svea3svy" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#CSS #Frontend</p>
<p><a href="https://youtu.be/L4svea3-svY"><img src="https://anthonypena.fr/2025/12/02/revue-de-presse-decembre/img/youtube-L4svea3-svY.jpg" alt="https://youtu.be/L4svea3-svY" title="Youtube video preview"/></a></p>
<p>Effet très sympa visuellement en utilisant un combo : grid, position: absolute, border-radius, :before/:after et un background radial-gradient.</p>
<p>C&#39;est juste dommage que le code n&#39;est pas disponible en texte à copier-coller…</p>
<p>Clairement : faut que je creuse les radient et ses variantes, clairement plein de truc à réaliser avec ces éléments !</p>
<h3 id="article-whats-new-in-angular-210httpsblogninjasquadcom20251120whatisnewangular210"><a href="https://blog.ninja-squad.com/2025/11/20/what-is-new-angular-21.0">What&#39;s new in Angular 21.0?</a><a href="#article-whats-new-in-angular-210httpsblogninjasquadcom20251120whatisnewangular210" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#Angular #Frontend #Vitest #Angular-Devs-France</p>
<p>Comme d&#39;habitude : un super récap de la nouvelle release d&#39;Angular par la Ninja Squad. Ne pas oublier d&#39;aller voir les billets pour Angular <a href="https://blog.ninja-squad.com/2025/08/20/what-is-new-angular-20.2">20.2</a> et <a href="https://blog.ninja-squad.com/2025/09/11/what-is-new-angular-20.3">20.3</a> et aussi les parties <a href="https://blog.ninja-squad.com/2025/11/04/angular-signal-forms-part-1">1</a> et <a href="https://blog.ninja-squad.com/2025/11/14/angular-signal-forms-part-2">2</a> de l&#39;article dédié aux Signal Form (la nouvelle façon de faire des formulaires en Angular).</p>
<p>Ce que je retiens surtout :</p>
<ul>
<li>vitest par défaut pour les tests unitaires ;</li>
<li>Zoneless par défaut sur les nouveaux projets et maintenant la manière officielle de faire de l&#39;Angular ;</li>
<li>sortie en expérimentale des Signal Forms ;</li>
<li><code>SimpleChanges</code> est enfin type-safe et prend en option un <code>&lt;T&gt;</code> qui vaut <code>any</code> par défaut pour ne rien casser du code existant mais qui va permettre typer explicitement notre code (moins utile avec les Signal mais toujours bon à prendre) ;</li>
<li>si on a pas besoin de passer d&#39;option, on peut omettre <code>provideHttpClient()</code> au bootstrap, surtout pratique pour les tests car ça évite d&#39;avoir à l&#39;ajouter partout ;</li>
<li>le <code>Router</code> permet maintenant de jouer sur le scrolling ;</li>
<li>introduction d&#39;une nouvelle stratégie d&#39;encapsulation <code>ExperimentalIsolatedShadowDom</code> qui permet d&#39;utiliser une isolation native avec du ShadowDOM qui est géré par le navigateur ;</li>
<li>arrivé du package <code>@angular/aria</code> pour faciliter la création de composant réutilisable ET accessible ET qui fonctionnent au clavier ;</li>
<li>des nouvelles options / nouveaux scripts pour générer des fichiers pour les agents IA pour faciliter le développement moderne en orientant vos agents vers du code moderne ;</li>
</ul>
<p>Plein d&#39;autres petites choses aussi comme d&#39;habitudes, donc allez lire l&#39;article !</p>
<p>Et j&#39;en profite aussi pour vous partager le lien vers la <a href="https://www.youtube.com/live/TYkLhQFOosE">table ronde sur Angular 21 d&#39;Angular Devs France qui se passera jeudi 4</a> (en replay dans la foulée).</p>
<h2 id="article-ia">IA<a href="#article-ia" class="anchor" aria-label="permalink">🔗</a></h2>
<h3 id="article-je-vous-devoile-loutil-ia-dont-je-ne-peux-plus-me-passer---underscore_httpsyoutube0u3qcumk0hw"><a href="https://youtu.be/0u3QcumK0hw">Je vous dévoile l’outil IA dont je ne peux plus me passer —  Underscore_</a><a href="#article-je-vous-devoile-loutil-ia-dont-je-ne-peux-plus-me-passer---underscore_httpsyoutube0u3qcumk0hw" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#Underscore_ #IA</p>
<p><a href="https://youtu.be/0u3QcumK0hw"><img src="https://anthonypena.fr/2025/12/02/revue-de-presse-decembre/img/youtube-0u3QcumK0hw.jpg" alt="https://youtu.be/0u3QcumK0hw" title="Youtube video preview"/></a></p>
<p>Vidéo super intéressante sur comment on peut utiliser de l&#39;IA pour s&#39;aider à trouver des idées, automatiser des tâches très mécaniques, tout en jouant sur l&#39;imperfection inhérente des modèles (quand on génère des images, il faut souvent plusieurs générations pour avoir un bon résultat par exemple).</p>
<p>Pas mal d&#39;explication / vulgarisation sur le process mis en place, la théorie, etc.</p>
<p>En gros résumé, ce que dit Michaël c&#39;est que l&#39;IA n&#39;a remplacé personne chez MiCorp, elle est venue faciliter un peu le travail, accompagner les créatifs dans les différents processus de création / réalisation, automatiser du travail mécanique qu&#39;ils ne prenaient pas le temps de faire (exemple avec le Podcast, car ça demandait une énergie qu&#39;ils n&#39;avaient pas mais en l&#39;automatisant ça passe mieux), l&#39;IA n&#39;étant pas assez fiable, assez stable, consistante, capable de compréhension pour faire plus.</p>
<h3 id="article-cest-au-tour-de-sandisk-daugmenter-ses-tarifs-de-50httpswwwminimachinesnetactusandiskaugmentertarifsssdram137137"><a href="https://www.minimachines.net/actu/sandisk-augmenter-tarifs-ssd-ram-137137">C’est au tour de Sandisk d’augmenter ses tarifs de 50%</a><a href="#article-cest-au-tour-de-sandisk-daugmenter-ses-tarifs-de-50httpswwwminimachinesnetactusandiskaugmentertarifsssdram137137" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#IA #Tech #RAM</p>
<p>Je cite deux extraits :</p>
<blockquote>
<p>Face à une demande de composants mémoire et stockage en hausse continue, Sandisk annonce une hausse de ses tarifs de 50% pour novembre. Les composants NAND sont particulièrement visés par ces hausses qui sont clairement liées au marché de l’IA</p>
</blockquote>
<p>Et</p>
<blockquote>
<p>Plusieurs autres fabricants que Sandisk indiquent les résultats d’exploitation de leur activité NAND et Flash avec des résultats assez éclairants quant à la hausse des prix : Transcend annonce un troisième trimestre 2025 avec un revenu de 133 millions de dollars. En hausse de 27% par rapport au second trimestre et de 63% par rapport au troisième trimestre de 2024.  Sa marge brute a augmenté de 45%. Et son profit net explose littéralement avec un magnifique +334% sur un an. Innodisk voit son revenu grimper de 64 % sur un an avec un profit qui augmente de 250%. Apacer Technology de son côté indique un profit en hausse de 70% entre le troisième trimestre de 2024 et celui de 2025.</p>
</blockquote>
<p>En parallèle Pierre explique que le marché global est en train de se réorienter vers les gros clients (achat de gros, payé à l&#39;avance, peu de marketing, livraison jusqu&#39;à la palette complète, etc.), délaissant le grand public (qui demande beaucoup plus de marketing, un soin sur l&#39;emballage individuel, etc.). Mais aussi avec un focus sur les mémoires plus rentables comme la DDR5 et HBM, délaissant les DDR4 par exemple qui commence à voir leur tarif exploser.</p>
<p>Les amis, si vous avez une machine qui tourne, croisez les doigts qu&#39;elle ne vous claque pas dans les doigts prochainement ou la facture sera salée 🙃</p>
<h2 id="article-securite">Sécurité<a href="#article-securite" class="anchor" aria-label="permalink">🔗</a></h2>
<h3 id="article-voici-le-top-10-des-mots-de-passe-les-plus-utilises-en-2025-et-cest-toujours-aussi-catastrophiquehttpswwwphonandroidcomvoiciletop10desmotsdepasselesplusutilisesen2025etcesttoujoursaussicatastrophiquehtml"><a href="https://www.phonandroid.com/voici-le-top-10-des-mots-de-passe-les-plus-utilises-en-2025-et-cest-toujours-aussi-catastrophique.html">Voici le top 10 des mots de passe les plus utilisés en 2025 et c’est toujours aussi catastrophique</a><a href="#article-voici-le-top-10-des-mots-de-passe-les-plus-utilises-en-2025-et-cest-toujours-aussi-catastrophiquehttpswwwphonandroidcomvoiciletop10desmotsdepasselesplusutilisesen2025etcesttoujoursaussicatastrophiquehtml" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#Sécurité #Mot-de-passe</p>
<p>Je vous donne la liste qui est remontée :</p>
<ol>
<li>123456</li>
<li>12345678</li>
<li>123456789</li>
<li>admin</li>
<li>1234</li>
<li>Aa123456</li>
<li>12345</li>
<li>password</li>
<li>123</li>
<li>1234567890</li>
</ol>
<p>Perso je suis juste surpris de ne pas trouver &quot;azerty&quot; ou quelque chose du genre comme d&#39;habitude… En tout cas : si vous avez un mot de passe dans cette liste, dites-vous que c&#39;est les premiers mots de passes que n&#39;importe quel pirate va tester !</p>
<h3 id="article-we-should-all-be-using-dependency-cooldownshttpsblogyossariannet20251121weshouldallbeusingdependencycooldowns"><a href="https://blog.yossarian.net/2025/11/21/We-should-all-be-using-dependency-cooldowns">We should all be using dependency cooldowns</a><a href="#article-we-should-all-be-using-dependency-cooldownshttpsblogyossariannet20251121weshouldallbeusingdependencycooldowns" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#Sécurité #Supply-chain-attack #NPM #Renovate #Dependabot</p>
<p>La grande majorité des attaques par supply chain se préparent pendant des mois mais ont une période de risque assez courtes (quelques heures à quelques jours en général, même si ça arrive que ce soit plus comme xz où la période d&#39;activation avec remédiation a été de 5 semaines).</p>
<p>Pensez donc (comme suggéré dans l&#39;article) à régler vos Renovate / Dependabot pour ne pas vous proposer un package qui a moins d&#39;une semaine, dans le doute.</p>
<p>Pensez aussi si vous faite du <code>npm</code> à ne <strong>JAMAIS</strong> installer vos dépendances avec <code>npm i</code> / <code>npm install</code> mais toujours avec <code>npm ci</code> pour ne pas tirer accidentellement des nouvelles versions de dépendance au passage qui se diffuseraient dans l&#39;équipe. Perso je demande un revert dans mon équipe si je vois que le <code>package-lock.json</code> a été modifié sans que le <code>package.json</code> l&#39;ait été par principe.</p>
<h3 id="article-des-outils-de-formatage-de-code-ont-expose-des-milliers-de-mots-de-passehttpskorbeninfocodebeautifiersfuitecredentialsbanquesgouvernementshtml"><a href="https://korben.info/code-beautifiers-fuite-credentials-banques-gouvernements.html">Des outils de formatage de code ont exposé des milliers de mots de passe</a><a href="#article-des-outils-de-formatage-de-code-ont-expose-des-milliers-de-mots-de-passehttpskorbeninfocodebeautifiersfuitecredentialsbanquesgouvernementshtml" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#Sécurité #JSON #Mot-de-passe</p>
<p>Sans surprise, les outils JSONFormatter et CodeBeautify (outils en ligne pour faire du formatage de code) n&#39;était pas 100% dans le navigateur et ont conservés plus de 80 000 extraits de code qui viennent de fuiter… Avec plein d&#39;identifiants / secrets / mot de passe / etc.</p>
<p>C&#39;est important d&#39;utiliser des outils offline si vous en avez un peu quelque chose à faire de la sécurité !</p>
<h2 id="article-divers">Divers<a href="#article-divers" class="anchor" aria-label="permalink">🔗</a></h2>
<h3 id="article-scripts-i-wrote-that-i-use-all-the-timehttpsevanhahncomscriptsiwrotethatiuseallthetime"><a href="https://evanhahn.com/scripts-i-wrote-that-i-use-all-the-time/">Scripts I wrote that I use all the time</a><a href="#article-scripts-i-wrote-that-i-use-all-the-timehttpsevanhahncomscriptsiwrotethatiuseallthetime" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#Linux #macOS #Shell #Scripts</p>
<p>Véritable mine d&#39;or d&#39;idée de scripts / alias à utiliser sous Linux et macOS. Vraiment on sent que l&#39;auteur utilise ça au quotidien.</p>
<p>Ne vous attendez pas à des scripts de centaines de lignes qui font des trucs de fou, là on parle de commandes toutes simples qui vont remplir un usage simple.</p>
<p>Quelques exemples :</p>
<ul>
<li>serveit pour lancer un mini serveur http dans le dossier courant en utilisant au mieux ce qui est dispo sur la machine ;</li>
<li>notify va afficher une notification en utilisant ce qui est dispo sur la machine ;</li>
<li>catbin va aller chercher le chemin d&#39;une commande et afficher le contenu (pratique pour retrouver ce que fait un script) ;</li>
<li>prettypath va afficher le contenu de $PATH mais avec une ligne par entrée pour facilité la lecture ;</li>
</ul>
<p>Et y&#39;a plein plein de chose comme ça, ça donne des idées, mais y&#39;a aussi les sources pour récupérer tout ça !</p>
<h3 id="article-le-zilog-z80-le-cauchemar-dintel---olivier-poncethttpsyoutubetckqmyuzx4k"><a href="https://youtu.be/tCKqMYUzx4k">Le Zilog Z80, le cauchemar d&#39;Intel —  Olivier Poncet</a><a href="#article-le-zilog-z80-le-cauchemar-dintel---olivier-poncethttpsyoutubetckqmyuzx4k" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#z80</p>
<p><a href="https://youtu.be/tCKqMYUzx4k"><img src="https://anthonypena.fr/2025/12/02/revue-de-presse-decembre/img/youtube-tCKqMYUzx4k.jpg" alt="https://youtu.be/tCKqMYUzx4k" title="Youtube video preview"/></a></p>
<p>Si comme moi vous avez découvert l&#39;informatique à l&#39;adolescence vers la fin des années 2000, vous ne connaissez sûrement pas les z80… Pourtant ce sont des processeurs mythiques et important de l&#39;informatique des années 80-90, qui ont révolutionné le marché, étaient (et sont encore) présent partout, jusque dans les Gameboys !!</p>
<p>Super vidéo d&#39;Olivier qui nous refait l&#39;historique du z80, nous explique son fonctionnement, et me donne envie encore une fois de craquer sur pour un Sinclair zx81 pour découvrir cet univers 😍</p>
<h3 id="article-intel-et-boe-veulent-baisser-la-frequence-des-ecrans-a-1-hzhttpswwwminimachinesnetactuintelecransrafraichissement1hz136978"><a href="https://www.minimachines.net/actu/intel-ecrans-rafraichissement-1-hz-136978">Intel et BOE veulent baisser la fréquence des écrans à 1 Hz</a><a href="#article-intel-et-boe-veulent-baisser-la-frequence-des-ecrans-a-1-hzhttpswwwminimachinesnetactuintelecransrafraichissement1hz136978" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#Intel #Technologie</p>
<p>Idée d&#39;Intel et BOE : permettre de descendre jusqu&#39;à un rafraîchissement de 1Hz.</p>
<p>En gros l&#39;idée n&#39;est pas de faire un écran spécial qui ne gère que 1Hz mais utiliser la technologie MFD (Multi-Fréquence Display) et de jouer sur une variation de la fréquence en fonction de l&#39;usage pour optimiser la consommation d&#39;énergie (chaque rafraîchissement consommant de l&#39;énergie en calcul GPU). Donc on pourrait imaginer des écrans qui font du 120Hz (ou même plus) en jeu, du 60Hz quand on est sur notre navigateur ou devant une vidéo, du 30Hz quand on relit un document texte, du 1Hz quand on n&#39;est plus devant l&#39;écran ou qu&#39;on a juste un lecteur audio qui tourne.</p>
<p>Intel parle évidemment d&#39;une &quot;IA&quot; qui déciderait de la fréquence idéale, je suis d&#39;accord avec Pierre (l&#39;auteur du blog) : ce sera plutôt un algorithme assee bateau pour définir la fréquence à choisir avec une catégorisation des applications. Intel prévoit de donner plus de détail en 2026.</p>
<p>Franchement : je comprends même pas qu&#39;on ait pas déjà fait ça plus tôt 😅</p>
<h3 id="article-ezgif--free-online-animated-gif-editorhttpsezgifcom"><a href="https://ezgif.com/">Ezgif - free online animated GIF editor</a><a href="#article-ezgif--free-online-animated-gif-editorhttpsezgifcom" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#Outil #Optimisation #Gif</p>
<p>J&#39;ai découvert cet outil en cherchant comment réduire la taille d&#39;un gif pour un article. Franchement l&#39;outil est top !</p>
<p>On peut découper, redimensionner, optimiser les couleurs, changer la vitesse, ajouter des effets, ajouter du texte, etc. Et on peut appliquer chaque modification étape par étape de sorte à pouvoir comparer avec l&#39;étape précédente.</p>
<p>Dans mon cas j&#39;avais besoin de couper une sous-partie d&#39;un gif (capture d&#39;écran gif de l&#39;écran complet au lieu de juste une fenêtre), j&#39;en ai profité pour réduire la palette de couleur pour optimiser encore un peu le poids :</p>
<ul>
<li>au début mon gif faisait 113Mo ;</li>
<li>après découpage de la partie qui m&#39;intéressait 8,89Mo ;</li>
<li>après optimisation de la palette de couleur 760Ko ;</li>
</ul>
<p>Je dois juste admettre un truc : il faut un bon bloqueur de pub pour pas être pollué par les cookies et les bandeaux pubs… Après comme j&#39;utilise depuis toujours Firefox, je peux utiliser <a href="https://ublockorigin.com/fr">uBlock Origin</a> comme je le fais depuis plus d&#39;une décennie sans problème, je n&#39;ai pas été trop impacté.</p>
<h3 id="article-microsoft-doesnt-want-you-to-know-this--tsodinghttpsyoutubeiuidbfjl62s"><a href="https://youtu.be/iuIdBfjL62s">Microsoft doesn&#39;t want you to know this — @Tsoding</a><a href="#article-microsoft-doesnt-want-you-to-know-this--tsodinghttpsyoutubeiuidbfjl62s" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#Git #SSH</p>
<p><a href="https://youtu.be/iuIdBfjL62s"><img src="https://anthonypena.fr/2025/12/02/revue-de-presse-decembre/img/youtube-iuIdBfjL62s.jpg" alt="https://youtu.be/iuIdBfjL62s" title="Youtube video preview"/></a></p>
<p>Dans cett courte vidéo on voit comment utiliser git, avec une connexion SSH (comme on le ferait pour Github / Gitlab) mais sans avoir setup de forge comme Github / Gitlab / Codeberg / Gitea / etc. juste un serveur ssh.</p>
<p>Concrètement, ce qu&#39;il faut comme setup :</p>
<ul>
<li>un serveur ssh (sur la plupart des linux aujourd&#39;hui <code>systemctl start sshd</code>, voir c&#39;est déjà activé si vous avez un serveur Linux) ;</li>
<li>pousser une clé ssh / utiliser un login mot de passe ;</li>
<li>et voilà 🥳 ;</li>
</ul>
<p>Ce qui va vous manquer c&#39;est les apports d&#39;une forge :</p>
<ul>
<li>gestion des PRs / MRs ;</li>
<li>interface web pour naviguer dans les commits / tags / branches ;</li>
<li>issue tracker ;</li>
</ul>
<p>Mais sinon, tout le reste est fourni par git, juste il va falloir maîtriser git plutôt que faire des clic-clic sur l&#39;interface web 🤷‍♂️</p>
<p>Tsodium cite la documentation officielle de Git, donc je mets le lien direct sur le setup pour faire du git directement sur ssh : <a href="https://git-scm.com/book/en/v2/Git-on-the-Server-Setting-Up-the-Server">https://git-scm.com/book/en/v2/Git-on-the-Server-Setting-Up-the-Server</a></p>
<h3 id="article-qualcomm-tire-le-frein-a-main-sur-lopen-source-darduinohttpswwwminimachinesnetactuqualcommopensourcedarduino137500"><a href="https://www.minimachines.net/actu/qualcomm-open-source-darduino-137500">Qualcomm tire le frein à main sur l’Open Source d’Arduino</a><a href="#article-qualcomm-tire-le-frein-a-main-sur-lopen-source-darduinohttpswwwminimachinesnetactuqualcommopensourcedarduino137500" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#Open-Source #Qualcomm #Arduino</p>
<p>Le chapeau de l&#39;article résume bien la situation :</p>
<blockquote>
<p>Début octobre, Qualcomm s’offrait Arduino. Fin novembre, la marque tord le cou des fondations Open Source de la société.</p>
</blockquote>
<p>Après 2 mois sous le gyron de Qualcomm, on voit déjà les premiers effets de sentir : changement de license, changement de politique de donnée (en gros toutes les données d&#39;Arduino sont maintenant utilisables librement et sans limite de temps par Qualcomm), interdiction de reverse engineering, etc. Du grand classique Qualcomm…</p>
<p>Longue vie aux ESP et Raspberry Pi Pico pour l&#39;électronique…</p>
<h3 id="article-les-operateurs-telecoms-vont-conserver-enormement-de-donnees-sur-vous-le-gouvernement-limpose-par-decrethttpswwwphonandroidcomlesoperateurstelecomsvontconserverenormementdedonneessurvouslegouvernementlimposepardecrethtml"><a href="https://www.phonandroid.com/les-operateurs-telecoms-vont-conserver-enormement-de-donnees-sur-vous-le-gouvernement-limpose-par-decret.html">Les opérateurs télécoms vont conserver énormément de données sur vous, le gouvernement l’impose par décret</a><a href="#article-les-operateurs-telecoms-vont-conserver-enormement-de-donnees-sur-vous-le-gouvernement-limpose-par-decrethttpswwwphonandroidcomlesoperateurstelecomsvontconserverenormementdedonneessurvouslegouvernementlimposepardecrethtml" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#Vie-privée #DNS #Réseaux-sociaux #Internet #FAI</p>
<p>Et un petit décret pour obliger les opérateurs à garder pendant 12 mois les métadonnées de connexions permettant largement de savoir tout ce que font les français.</p>
<p>Officiellement il n&#39;y a conservation que des IPs, des heures de connexions, les sites associés aux IPs, et quelques données du genre. Dans les faits ça veut dire qu&#39;il existera quelque part une base de donnée de chacune de vos actions en ligne.</p>
<p>Pour la blague il y a quand même une obligation de conserver les métadonnées des publications des commentaires sur les réseaux sociaux. Comment un FAI pourrait le savoir en HTTPS sans intercepter toutes en connexion et déchiffrer les connexions ?</p>
<p>Si vous ne voyez pas le problème : est-ce que vous seriez d&#39;accord pour avoir quelqu&#39;un qui note chaque fois que vous sortez de chez vous et la destination que vous avez pour le consigner au chaud pendant 12 mois ? Je ne pense pas…</p>
<p>c&#39;est vraiment le moment de changer vos DNS, utilisez du Tor ou des VPN à l&#39;étranger, et toutes méthodes permettant de l&#39;anonymisation !</p>
<h3 id="article-veqqq--gitembigennerhttpsgithubcomveqqqgitembigenner"><a href="https://github.com/veqqq/git-embigenner">veqqq / git-embigenner</a><a href="#article-veqqq--gitembigennerhttpsgithubcomveqqqgitembigenner" class="anchor" aria-label="permalink">🔗</a></h3>
<p>#Github</p>
<p>Ce repo propose un script qui va générer des commits vides. Pourquoi faire ? Simuler une activité sur Github qui donne l&#39;impression qu&#39;on ait actif tous les jours !</p>
<p>En effet de plus en plus de gens considèrent que c&#39;est important, sans que ça ait de sens particulier.</p>
<p>Et comme d&#39;habitude une stats qui peut être intéressante devient un objectif à tenir, donc les gens trouvent des moyens de tricher, donc c&#39;est n&#39;importe quoi…</p>
<p>Crédit photo : Générée via Mistral AI avec le prompt suivant :</p>
<blockquote>
<p>Create an image of a person deeply absorbed in reading a printed newspaper, seated at a rustic wooden table in a warm, inviting space. The scene is bathed in soft, golden light from a vintage desk lamp, casting gentle shadows across the table. A stack of newspapers and magazines, slightly disheveled, surrounds the reader, with visible headlines and text hinting at current events and stories. A steaming cup of coffee sits nearby, adding to the cozy ambiance.</p>
<p>In the background, a large window frames a dynamic cityscape or the lively atmosphere of a newsroom, suggesting the connection between the reader and the world outside. The focus is on the tactile experience of holding the newspaper—crumpled edges, ink-stained fingers, and the rustle of pages—while the setting feels intimate yet alive with the energy of journalism. The colors are warm and rich, with earthy tones and pops of contrast to draw attention to the act of reading and the immersive world of news.</p>
</blockquote>
]]></content:encoded>
      <dc:creator><![CDATA[Anthony Pena]]></dc:creator>
      <media:content medium="image" url="https://anthonypena.fr/img/cover.min.jpg"/>
    </item>
    <item>
      <title><![CDATA[Créer un TUI avec Deno !]]></title>
      <guid isPermaLink="false">2025/11/25/creer-un-tui-avec-deno</guid>
      <description><![CDATA[<p>Au moment de la publication de mon article sur la création de CLI en Deno l&#39;ami Thierry Chantier m&#39;a…</p>
]]></description>
      <link>https://anthonypena.fr/2025/11/25/creer-un-tui-avec-deno/index.html</link>
      <category><![CDATA[Deno]]></category>
      <category><![CDATA[Bash]]></category>
      <category><![CDATA[TypeScript]]></category>
      <category><![CDATA[Tutoriel]]></category>
      <pubDate>Tue, 25 Nov 2025 07:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>Au moment de la publication de mon article sur la création de <a href="/2025/10/23/creer-son-cli-facilement-avec-deno/">CLI en Deno</a> l&#39;ami Thierry Chantier m&#39;a défié de créer un TUI avec Deno ! Vous vous en doutez : j&#39;ai relevé le défie !</p>
<h2 id="article-cli-vs-tui">CLI vs TUI<a href="#article-cli-vs-tui" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Commençons par le BA.ba : un CLI c&#39;est un outil en ligne de commande (CLI = Command Line Interface) qu&#39;on appelle à chaque fois qu&#39;on va vouloir effectuer une action, un TUI (Terminal User Interface) va être appelé une fois puis on va pouvoir manipuler l&#39;outil dans le terminal comme on le ferait avec une GUI (Graphical User Interface) habituel au clavier ou à la souris.</p>
<p>Les TUI ont encore un intérêt fort de nos jours, ils consomment peu de ressource, fonctionnent très bien en local mais aussi via SSH sur une machine distante !</p>
<p>On trouve beaucoup de TUI extrêmement pratique ! Je pense que celui que j&#39;ai le plus utilisé est surement <a href="https://dev.yorhel.nl/ncdu/scr">NCDU</a> qui permet de naviguer dans une vue du système de fichier mettant en avant la taille occupée par les fichiers / dossiers, le second c&#39;est <a href="https://www.cgsecurity.org/wiki/TestDisk_Etape_par_Etape">TestDisk</a> qui permet de naviguer dans un système de fichier sans s&#39;occuper de l&#39;index pour aller chercher des fichiers supprimés mais encore présent physiquement sur le disque (vous n&#39;imaginez pas comment ça peut sauver la vie !), et plus récemment j&#39;utilise quotidiennement <a href="https://github.com/MitMaro/git-interactive-rebase-tool?tab%3Dreadme-ov-file#git-interactive-rebase-tool">git-interactive-rebase-tool</a> qui offre un menu interactif pour faire un rebase avec git.</p>
<h2 id="article-creer-le-projet">Créer le projet<a href="#article-creer-le-projet" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Je ne vais tout détailler, je vous renvoie à mon article précédent. Mais en résumé : </p>
<pre><code class="hljs language-Bash"><span class="hljs-built_in">mkdir</span> hello-tui
deno init
deno install npm:figlet npm:crayon<div aria-hidden="true" class="language-tag">Bash</div>
</code></pre><p>Modifier le fichier <code>deno.json</code> pour ajouter <code>tui</code> et <code>tui/components</code> :</p>
<pre><code class="hljs language-JSON"><span class="hljs-punctuation">{</span>
  <span class="hljs-attr">&quot;tasks&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span>
    <span class="hljs-attr">&quot;dev&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;deno run -A --watch main.ts&quot;</span>
  <span class="hljs-punctuation">}</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;imports&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span>
    <span class="hljs-attr">&quot;crayon&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;npm:crayon@^6.0.1&quot;</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;figlet&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;npm:figlet@^1.9.3&quot;</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;tui&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;https://deno.land/x/tui@2.1.11/mod.ts&quot;</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;tui/components&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;https://deno.land/x/tui@2.1.11/src/components/mod.ts&quot;</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;@std/assert&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;jsr:@std/assert@1&quot;</span>
  <span class="hljs-punctuation">}</span>
<span class="hljs-punctuation">}</span><div aria-hidden="true" class="language-tag">JSON</div>
</code></pre><blockquote>
<p>Note 1 : ça vous montre que Deno n&#39;est pas limité à JSR ou NPM, il peut tirer des modules depuis n&#39;importe quelle URL http(s), par contre il faut créer les entrées manuellement dans le fichier <code>deno.json</code>.</p>
</blockquote>
<blockquote>
<p>Note 2 : vous noterez aussi que j&#39;ai ajouté <code>-A</code> dans la commande de la task dev, pour ne pas avoir à m&#39;occuper des permissions (<code>-A</code> indique à Deno d&#39;ouvrir toutes les permissions). C&#39;est une mauvaise pratique, mais pour la démo et pour le dev ça fonctionnera très bien, il sera toujours temps de revenir dessus une fois le projet complet.</p>
</blockquote>
<h2 id="article-premier-affichage">Premier affichage<a href="#article-premier-affichage" class="anchor" aria-label="permalink">🔗</a></h2>
<pre><code class="hljs language-TypeScript"><span class="hljs-keyword">import</span> { crayon } <span class="hljs-keyword">from</span> <span class="hljs-string">&quot;crayon&quot;</span>;
<span class="hljs-keyword">import</span> {
  handleInput,
  handleKeyboardControls,
  handleMouseControls,
  <span class="hljs-title class_">Tui</span>,
} <span class="hljs-keyword">from</span> <span class="hljs-string">&quot;tui&quot;</span>;

<span class="hljs-keyword">const</span> tui = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Tui</span>({
  <span class="hljs-attr">style</span>: crayon.<span class="hljs-property">bgBlack</span>, <span class="hljs-comment">// Make background black</span>
  <span class="hljs-attr">refreshRate</span>: <span class="hljs-number">1000</span> / <span class="hljs-number">60</span>, <span class="hljs-comment">// Run in 60FPS</span>
});

tui.<span class="hljs-title function_">dispatch</span>(); <span class="hljs-comment">// Close Tui on CTRL+C</span>

<span class="hljs-title function_">handleInput</span>(tui);
<span class="hljs-title function_">handleMouseControls</span>(tui);
<span class="hljs-title function_">handleKeyboardControls</span>(tui);

tui.<span class="hljs-title function_">run</span>();<div aria-hidden="true" class="language-tag">TypeScript</div>
</code></pre><p>En l&#39;état ça n&#39;est pas très impressionnant, mais ça va afficher un fond noir sur l&#39;ensemble du terminal et attendre. Si vous avez un doute si ça fonctionne vous pouvez toujours changer la valeur de <code>style</code> dans le constructeur de <code>Tui</code> pour voir varier la couleur de fond.</p>
<figure>
<img src="https://anthonypena.fr/2025/11/25/creer-un-tui-avec-deno/img/first-display.gif" alt="Premier affichage avec variation du fond entre noir et vert" is="img-zoom"/>
<figcaption>Premier affichage avec variation du fond entre noir et vert</figcaption>
</figure>
<h2 id="article-hello-world">Hello World!<a href="#article-hello-world" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Ajoutons un peu de texte :</p>
<pre><code class="hljs language-TypeScript">
<span class="hljs-keyword">import</span> {
  ...
  <span class="hljs-title class_">Signal</span>,
} <span class="hljs-keyword">from</span> <span class="hljs-string">&quot;tui&quot;</span>;
<span class="hljs-keyword">import</span> { <span class="hljs-title class_">Text</span> } <span class="hljs-keyword">from</span> <span class="hljs-string">&quot;tui/components&quot;</span>;
...

<span class="hljs-keyword">const</span> text = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Signal</span>(<span class="hljs-string">&quot;Hello, world!&quot;</span>);

<span class="hljs-keyword">new</span> <span class="hljs-title class_">Text</span>({
  <span class="hljs-attr">parent</span>: tui,
  text,
  <span class="hljs-attr">multiCodePointSupport</span>: <span class="hljs-literal">true</span>,
  <span class="hljs-attr">theme</span>: {
    <span class="hljs-attr">base</span>: crayon.<span class="hljs-property">magenta</span>,
  },
  <span class="hljs-attr">rectangle</span>: { <span class="hljs-attr">column</span>: <span class="hljs-number">1</span>, <span class="hljs-attr">row</span>: <span class="hljs-number">1</span> },
  <span class="hljs-attr">zIndex</span>: <span class="hljs-number">0</span>,
});

tui.<span class="hljs-title function_">run</span>();<div aria-hidden="true" class="language-tag">TypeScript</div>
</code></pre><figure>
<img src="https://anthonypena.fr/2025/11/25/creer-un-tui-avec-deno/img/hello-world.png" alt="Affichage du texte &quot;Hello, world!&quot; en magenta" is="img-zoom"/>
<figcaption>Affichage du texte &quot;Hello, world!&quot; en magenta</figcaption>
</figure>
<p>Toujours pas très impressionnant, mais on voit globalement ce qui est important avec TUI : comment créer une brique visuelle, comment l&#39;ajouter l&#39;écran en définissant son parent, comment créer un élément qui change de manière réactive via un Signal (si vous faite du Angular ou du SolidJS, ça devrait pas vous surprendre !).</p>
<p>Donc maintenant, il suffit de dérouler pour avoir un affichage d&#39;une bannière ASCII comme pour notre précédent CLI !</p>
<h2 id="article-afficher-une-banniere-ascii">Afficher une bannière ASCII<a href="#article-afficher-une-banniere-ascii" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Comme pour le CLI, on va utiliser la librairie <code>figlet</code> pour générer notre bannière. Sauf que <code>figlet</code> va nous fournir une chaîne de caractère multi-lignes, or à l&#39;étape précédente, on utilisait un <code>Text</code> pour l&#39;affichage qui ne supporte qu&#39;une seule ligne de texte. On va donc remplacer notre <code>new Text(...)</code> par un <code>new Label(...)</code> qui gère le multi-ligne.</p>
<p>Comme j&#39;ai prévu dans rendre ce TUI un peu interactif, on va vouloir rester sur des Signal pour la génération de la bannière : à chaque changement de <code>text</code>, mettre à jour un autre <code>Signal</code> qui se nommera <code>asciiText</code> avec la bannière correspondante.</p>
<p>Pour ça c&#39;est facile :</p>
<pre><code class="hljs language-TypeScript">...
<span class="hljs-keyword">const</span> text = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Signal</span>(<span class="hljs-string">&quot;Hello, world!&quot;</span>);
<span class="hljs-keyword">const</span> asciiText = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Signal</span>(<span class="hljs-string">&quot;&quot;</span>);

<span class="hljs-keyword">new</span> <span class="hljs-title class_">Effect</span>(<span class="hljs-title function_">async</span> () =&gt; {
  asciiText.<span class="hljs-property">value</span> = <span class="hljs-keyword">await</span> <span class="hljs-title function_">figlet</span>(text.<span class="hljs-property">value</span>, { <span class="hljs-attr">font</span>: <span class="hljs-string">&quot;Standard&quot;</span> });
});

<span class="hljs-keyword">new</span> <span class="hljs-title class_">Label</span>({
  ...
  <span class="hljs-attr">text</span>: asciiText,
  ...
});
...<div aria-hidden="true" class="language-tag">TypeScript</div>
</code></pre><p>Le résultat :</p>
<figure>
<img src="https://anthonypena.fr/2025/11/25/creer-un-tui-avec-deno/img/dirty-banner.png" alt="Affichage de la bannière mais avec le texte en fond transparent alors que le reste est noir" is="img-zoom"/>
<figcaption>Affichage de la bannière mais avec le texte en fond transparent alors que le reste est noir</figcaption>
</figure>
<p>Ça fonctionne, mais c&#39;est moche… Donc on va ajuster un peu le style pour avoir le texte et le fond qui prennent les couleurs par défaut du terminal, chez moi en blanc sur partiellement transparent.</p>
<p>Pour faire ça, il faut supprimer <code>style: crayon.bgBlack,</code> dans le <code>new Tui()</code> et le <code>base: crayon.magenta</code> dans la partie <code>thème</code> du <code>new Label()</code>.</p>
<figure>
<img src="https://anthonypena.fr/2025/11/25/creer-un-tui-avec-deno/img/banner-no-param.png" alt="Bannière en blanc sur transparent (couleurs par défaut de mon terminal)" is="img-zoom"/>
<figcaption>Bannière en blanc sur transparent (couleurs par défaut de mon terminal)</figcaption>
</figure>
<blockquote>
<p>Note : je fais avec mes goûts / habitudes / préférences, sentez-vous libre de mettre les couleurs / styles qui vous conviennent à vous !</p>
</blockquote>
<h2 id="article-rendons-ca-dynamique-">Rendons ça dynamique !<a href="#article-rendons-ca-dynamique-" class="anchor" aria-label="permalink">🔗</a></h2>
<p>L&#39;idée maintenant serait de pouvoir choisir dynamiquement le texte qu&#39;on affiche sous forme de bannière.</p>
<p>Pour ça il nous faut donc un <code>Input</code> (champs de texte d&#39;une seule ligne), et chaque changement de valeur mettra à jour la bannière. Et après on suit la même logique que pour le label : on le crée (avec des options très similaires), on le positionne (on va en profiter pour déplacer le label plus bas au passage) et on affiche. À noter qu&#39;on a pas besoin d&#39;un listener sur l&#39;input, comme on lui passe une référence vers notre <code>Signal</code> <code>text</code> il sera mis à jour automatiquement !</p>
<pre><code class="hljs language-TypeScript">...
<span class="hljs-keyword">import</span> { <span class="hljs-title class_">Input</span>, <span class="hljs-title class_">Label</span> } <span class="hljs-keyword">from</span> <span class="hljs-string">&quot;tui/components&quot;</span>;

...

<span class="hljs-keyword">const</span> text = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Signal</span>(<span class="hljs-string">&quot;Hello, world!&quot;</span>);
<span class="hljs-keyword">const</span> asciiText = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Signal</span>(<span class="hljs-string">&quot;&quot;</span>);

...

<span class="hljs-keyword">new</span> <span class="hljs-title class_">Input</span>({
  <span class="hljs-attr">parent</span>: tui,
  <span class="hljs-attr">placeholder</span>: <span class="hljs-string">&quot;type here&quot;</span>,
  <span class="hljs-attr">theme</span>: {
    <span class="hljs-attr">base</span>: crayon.<span class="hljs-property">bgLightBlack</span>,
    <span class="hljs-attr">focused</span>: crayon.<span class="hljs-property">bgLightGreen</span>,
    <span class="hljs-attr">active</span>: crayon.<span class="hljs-property">bgYellow</span>,
    <span class="hljs-attr">cursor</span>: { <span class="hljs-attr">base</span>: crayon.<span class="hljs-property">blue</span> },
  },
  text,
  <span class="hljs-attr">rectangle</span>: { <span class="hljs-attr">column</span>: <span class="hljs-number">1</span>, <span class="hljs-attr">row</span>: <span class="hljs-number">1</span>, <span class="hljs-attr">width</span>: <span class="hljs-number">40</span> },
  <span class="hljs-attr">zIndex</span>: <span class="hljs-number">0</span>,
});

<span class="hljs-keyword">new</span> <span class="hljs-title class_">Label</span>({
  ...
  <span class="hljs-attr">rectangle</span>: { <span class="hljs-attr">column</span>: <span class="hljs-number">1</span>, <span class="hljs-attr">row</span>: <span class="hljs-number">3</span> },
  ...
});
...<div aria-hidden="true" class="language-tag">TypeScript</div>
</code></pre><figure>
<img src="https://anthonypena.fr/2025/11/25/creer-un-tui-avec-deno/img/input-1.gif" alt="Affichage du résultat avec un input mais qui n&#39;écrase pas l&#39;affichage précédent" is="img-zoom"/>
<figcaption>Affichage du résultat avec un input mais qui n&#39;écrase pas l&#39;affichage précédent</figcaption>
</figure>
<p>Comme on peut le voir, à chaque fois qu&#39;on change la valeur de l&#39;input, on voit le texte changer mais le contenu précédent n&#39;est pas écrasé 🫠 Du coup je vais prendre une option de facilité (il y a peut-être mieux) et je vais ajouter des espaces en &quot;bourrage&quot; à la suite du texte pour effacer un éventuel précédent texte 💩</p>
<pre><code class="hljs language-TypeScript">...
<span class="hljs-keyword">new</span> <span class="hljs-title class_">Effect</span>(<span class="hljs-title function_">async</span> () =&gt; {
  <span class="hljs-keyword">const</span> whiteSpaces = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Array</span>(<span class="hljs-number">100</span>).<span class="hljs-title function_">fill</span>(<span class="hljs-string">&quot; &quot;</span>).<span class="hljs-title function_">join</span>(<span class="hljs-string">&quot;&quot;</span>);
  asciiText.<span class="hljs-property">value</span> = <span class="hljs-keyword">await</span> <span class="hljs-title function_">figlet</span>(text.<span class="hljs-property">value</span> + whiteSpaces, {
    <span class="hljs-attr">font</span>: <span class="hljs-string">&quot;Standard&quot;</span>,
  });
});
...<div aria-hidden="true" class="language-tag">TypeScript</div>
</code></pre><figure>
<img src="https://anthonypena.fr/2025/11/25/creer-un-tui-avec-deno/img/input-2.gif" alt="Avec des espaces en bourrage ça fonctionne mieux d&#39;un coup !" is="img-zoom"/>
<figcaption>Avec des espaces en bourrage ça fonctionne mieux d&#39;un coup !</figcaption>
</figure>
<h2 id="article-et-avec-une-police-dynamique-">Et avec une police dynamique ?<a href="#article-et-avec-une-police-dynamique-" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Je me dis que quitte à faire un TUI autant aller au bout et proposer une police dynamique pour le texte en ASCII. Donc prenons la liste des polices gérées par Figlet et faisons en une liste déroulante (<code>Combobox</code> ici). C&#39;est très proche de ce qu&#39;on a fait pour l&#39;<code>Input</code> à part qu&#39;on va en plus donner une liste de valeur possible.</p>
<p>À noter que le composant <code>Combobox</code> garde la valeur sélectionnée par son index dans la liste, donc par facilité d&#39;utilisation, je crée un <code>Signal</code> de type <code>Computed</code> (comprendre <code>Signal</code> qui est dérivé dynamiquement et de manière réactive d&#39;un ou plusieurs autre(s) <code>Signal</code>(s)) pour avoir directement la police actuelle.</p>
<pre><code class="hljs language-TypeScript">...
<span class="hljs-keyword">import</span> { <span class="hljs-title class_">ComboBox</span>, <span class="hljs-title class_">Input</span>, <span class="hljs-title class_">Label</span> } <span class="hljs-keyword">from</span> <span class="hljs-string">&quot;tui/components&quot;</span>;
...

<span class="hljs-keyword">const</span> <span class="hljs-variable constant_">AVAILABLE_FONTS</span> = [
  <span class="hljs-string">&quot;1Row&quot;</span>, <span class="hljs-string">&quot;3-D&quot;</span>, <span class="hljs-string">&quot;3D Diagonal&quot;</span>, <span class="hljs-string">&quot;3D-ASCII&quot;</span>, <span class="hljs-string">&quot;3x5&quot;</span>, <span class="hljs-string">&quot;4Max&quot;</span>, <span class="hljs-string">&quot;5 Line Oblique&quot;</span>, <span class="hljs-string">&quot;Standard&quot;</span>, <span class="hljs-string">&quot;Ghost&quot;</span>, <span class="hljs-string">&quot;Big&quot;</span>, 
  <span class="hljs-string">&quot;Block&quot;</span>, <span class="hljs-string">&quot;Bubble&quot;</span>, <span class="hljs-string">&quot;Digital&quot;</span>, <span class="hljs-string">&quot;Ivrit&quot;</span>, <span class="hljs-string">&quot;Mini&quot;</span>, <span class="hljs-string">&quot;Script&quot;</span>, <span class="hljs-string">&quot;Shadow&quot;</span>, <span class="hljs-string">&quot;Slant&quot;</span>, <span class="hljs-string">&quot;Small&quot;</span>, <span class="hljs-string">&quot;Speed&quot;</span>, <span class="hljs-string">&quot;Tinker-Toy&quot;</span>
];
<span class="hljs-keyword">const</span> <span class="hljs-variable constant_">DEFAULT_FONT</span> = <span class="hljs-number">7</span>;
<span class="hljs-keyword">const</span> fontIndex = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Signal</span>&lt;<span class="hljs-built_in">number</span> | <span class="hljs-literal">undefined</span>&gt;(<span class="hljs-variable constant_">DEFAULT_FONT</span>);
<span class="hljs-keyword">const</span> font = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Computed</span>(<span class="hljs-function">() =&gt;</span>
  <span class="hljs-variable constant_">AVAILABLE_FONTS</span>[fontIndex.<span class="hljs-property">value</span> ?? <span class="hljs-variable constant_">DEFAULT_FONT</span>]
);
...
<span class="hljs-keyword">new</span> <span class="hljs-title class_">Effect</span>(<span class="hljs-title function_">async</span> () =&gt; {
  ...
  asciiText.<span class="hljs-property">value</span> = <span class="hljs-keyword">await</span> <span class="hljs-title function_">figlet</span>(text.<span class="hljs-property">value</span> + whiteSpaces, {
    <span class="hljs-attr">font</span>: font.<span class="hljs-property">value</span>,
  });
});

...

<span class="hljs-keyword">new</span> <span class="hljs-title class_">ComboBox</span>({
  <span class="hljs-attr">parent</span>: tui,
  <span class="hljs-attr">items</span>: <span class="hljs-variable constant_">AVAILABLE_FONTS</span>,
  <span class="hljs-attr">placeholder</span>: <span class="hljs-string">&quot;choose a style&quot;</span>,
  <span class="hljs-attr">selectedItem</span>: fontIndex,
  <span class="hljs-attr">theme</span>: {
    <span class="hljs-attr">base</span>: crayon.<span class="hljs-property">bgGreen</span>,
    <span class="hljs-attr">focused</span>: crayon.<span class="hljs-property">bgLightGreen</span>,
    <span class="hljs-attr">active</span>: crayon.<span class="hljs-property">bgYellow</span>,
  },
  <span class="hljs-attr">rectangle</span>: {
    <span class="hljs-attr">column</span>: <span class="hljs-number">45</span>,
    <span class="hljs-attr">row</span>: <span class="hljs-number">1</span>,
    <span class="hljs-attr">height</span>: <span class="hljs-number">1</span>,
    <span class="hljs-attr">width</span>: <span class="hljs-number">14</span>,
  },
  <span class="hljs-attr">zIndex</span>: <span class="hljs-number">0</span>,
});<div aria-hidden="true" class="language-tag">TypeScript</div>
</code></pre><figure>
<img src="https://anthonypena.fr/2025/11/25/creer-un-tui-avec-deno/img/combobox-1.gif" alt="On voit le changement de police et un crash à la fin…" is="img-zoom"/>
<figcaption>On voit le changement de police et un crash à la fin…</figcaption>
</figure>
<p>Comme vous pouvez le voir : c&#39;est moche et ça crash… C&#39;est moche parce qu&#39;à la fermeture du menu rien n&#39;est re-rendu pour cacher ce qu&#39;on avait avant 🫠 Ça crash quand on passe sur une police qui prend moins de ligne que la précédente…</p>
<p>Je n&#39;ai pas vu d&#39;option particulière pour gérer ça donc j&#39;ai choisi très simplement d&#39;ajouter des lignes blanches à la suite du texte en ascii pour faire du bourrage à nouveau et combler les lignes &quot;manquantes&quot; (clairement, la lib devrait gérer ça pour moi).</p>
<pre><code class="hljs language-TypeScript"><span class="hljs-keyword">new</span> <span class="hljs-title class_">Effect</span>(<span class="hljs-title function_">async</span> () =&gt; {
  ...
  <span class="hljs-keyword">let</span> newAsciiText = <span class="hljs-keyword">await</span> <span class="hljs-title function_">figlet</span>(text.<span class="hljs-property">value</span> + whiteSpaces, {
    <span class="hljs-attr">font</span>: font.<span class="hljs-property">value</span>,
  });
  <span class="hljs-keyword">const</span> newAsciiTextRows = newAsciiText.<span class="hljs-title function_">split</span>(<span class="hljs-string">&quot;\n&quot;</span>).<span class="hljs-property">length</span>;
  <span class="hljs-keyword">const</span> asciiTextRows = asciiText.<span class="hljs-property">value</span>.<span class="hljs-title function_">split</span>(<span class="hljs-string">&quot;\n&quot;</span>).<span class="hljs-property">length</span>;
  <span class="hljs-keyword">if</span> (newAsciiTextRows &lt; asciiTextRows) {
    newAsciiText += <span class="hljs-string">&quot;\n&quot;</span> +
      <span class="hljs-keyword">new</span> <span class="hljs-title class_">Array</span>(asciiTextRows - newAsciiTextRows).<span class="hljs-title function_">fill</span>(whiteSpaces).<span class="hljs-title function_">join</span>(<span class="hljs-string">&quot;\n&quot;</span>);
  }
  asciiText.<span class="hljs-property">value</span> = newAsciiText;
});<div aria-hidden="true" class="language-tag">TypeScript</div>
</code></pre><figure>
<img src="https://anthonypena.fr/2025/11/25/creer-un-tui-avec-deno/img/combobox-2.gif" alt="Avec un bourrage pour les lignes &quot;manquantes&quot; ça fonctionne" is="img-zoom"/>
<figcaption>Avec un bourrage pour les lignes &quot;manquantes&quot; ça fonctionne</figcaption>
</figure>
<p>Pour le fait que le menu soit toujours plus ou moins visible parce qu&#39;il manque un re-rendu, c&#39;est dû au fait que j&#39;ai choisi d&#39;avoir un fond transparent… Donc c&#39;est à noter : si vous voulez avoir un fond transparent, c&#39;est compliqué de faire un TUI propre… On va donc mettre un fond noir un peu partout et tout devrait rentrer dans l&#39;ordre. Au passage on peut aussi éviter d&#39;ajouter des espaces en bourrage à la suite du texte pour effacer le texte précédent.</p>
<pre><code class="hljs language-TypeScript">...
<span class="hljs-keyword">const</span> tui = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Tui</span>({
  ...
  <span class="hljs-attr">style</span>: crayon.<span class="hljs-property">bgBlack</span>,
});
...
<span class="hljs-keyword">new</span> <span class="hljs-title class_">Effect</span>(<span class="hljs-title function_">async</span> () =&gt; {
  ...
  <span class="hljs-keyword">let</span> newAsciiText = <span class="hljs-keyword">await</span> <span class="hljs-title function_">figlet</span>(text.<span class="hljs-property">value</span>, { <span class="hljs-attr">font</span>: font.<span class="hljs-property">value</span> });
  ...
});
...
<span class="hljs-keyword">new</span> <span class="hljs-title class_">Label</span>({
  ...
  <span class="hljs-attr">theme</span>: {
    <span class="hljs-attr">base</span>: crayon.<span class="hljs-property">bgBlack</span>,
  },
  ...
});
...<div aria-hidden="true" class="language-tag">TypeScript</div>
</code></pre><figure>
<img src="https://anthonypena.fr/2025/11/25/creer-un-tui-avec-deno/img/combobox-3.gif" alt="Avec un fond sur nos différents composant ça fonctionne mieux" is="img-zoom"/>
<figcaption>Avec un fond sur nos différents composant ça fonctionne mieux</figcaption>
</figure>
<p>Il reste en fait un seul dernier problème : la liste déroulante passe derrière le <code>Label</code>, pour ça il faut jouer avec le paramètre <code>zIndex</code> pour faire passer la liste déroulante au premier plan (comme on ferait en CSS finalement).</p>
<pre><code class="hljs language-TypeScript">...
<span class="hljs-keyword">new</span> <span class="hljs-title class_">ComboBox</span>({
    ...
  <span class="hljs-attr">zIndex</span>: <span class="hljs-number">1000</span>,
});
...<div aria-hidden="true" class="language-tag">TypeScript</div>
</code></pre><figure>
<img src="https://anthonypena.fr/2025/11/25/creer-un-tui-avec-deno/img/combobox-4.gif" alt="Avec le zIndex c&#39;est parfait" is="img-zoom"/>
<figcaption>Avec le zIndex c&#39;est parfait</figcaption>
</figure>
<h2 id="article-avec-un-vrai-layout-">Avec un vrai layout ?<a href="#article-avec-un-vrai-layout-" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Jusque-là, on plaçait manuellement nos éléments à l&#39;écran en les positionnant à la ligne/colonne près, avec des tailles fixes. Or avec TUI, on peut très bien utiliser des composants de layout tout près qui permettent de se faciliter la vie.</p>
<p>Il existe plusieurs layouts : horizontal, vertical et grid.</p>
<p>On voudrait garder un positionnement similaire à ce qu&#39;on a : l&#39;input en haut à gauche, le combobox en haut à droite et le maximum de place pour le label contenant la bannière ASCII.</p>
<p>Déjà on va ajouter une entrée dans le <code>deno.json</code> pour accéder aux layouts (comme on avait fait pour les composants) :</p>
<pre><code class="hljs language-JSON"><span class="hljs-punctuation">{</span>
  ...
  <span class="hljs-attr">&quot;imports&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span>
    ...
    <span class="hljs-attr">&quot;tui/layout&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;https://deno.land/x/tui@2.1.11/src/layout/mod.ts&quot;</span><span class="hljs-punctuation">,</span>
    ...
  <span class="hljs-punctuation">}</span>
<span class="hljs-punctuation">}</span><div aria-hidden="true" class="language-tag">JSON</div>
</code></pre><p>Ensuite on crée notre layout en lui donnant la référence du <code>Rectangle</code> de l&#39;instance de <code>Tui</code> pour que le layout prenne toute la place, et on définit un pattern pour positionner nos éléments :</p>
<pre><code class="hljs language-TypeScript">...
<span class="hljs-keyword">import</span> { <span class="hljs-title class_">GridLayout</span> } <span class="hljs-keyword">from</span> <span class="hljs-string">&quot;tui/layout&quot;</span>;
...
<span class="hljs-keyword">const</span> layout = <span class="hljs-keyword">new</span> <span class="hljs-title class_">GridLayout</span>({
  <span class="hljs-attr">rectangle</span>: tui.<span class="hljs-property">rectangle</span>,
  <span class="hljs-attr">pattern</span>: [
    [<span class="hljs-string">&quot;input&quot;</span>, <span class="hljs-string">&quot;combobox&quot;</span>],
    [<span class="hljs-string">&quot;result&quot;</span>, <span class="hljs-string">&quot;result&quot;</span>],
    [<span class="hljs-string">&quot;result&quot;</span>, <span class="hljs-string">&quot;result&quot;</span>],
    [<span class="hljs-string">&quot;result&quot;</span>, <span class="hljs-string">&quot;result&quot;</span>],
    [<span class="hljs-string">&quot;result&quot;</span>, <span class="hljs-string">&quot;result&quot;</span>],
    [<span class="hljs-string">&quot;result&quot;</span>, <span class="hljs-string">&quot;result&quot;</span>],
    [<span class="hljs-string">&quot;result&quot;</span>, <span class="hljs-string">&quot;result&quot;</span>],
  ],
  <span class="hljs-attr">gapX</span>: <span class="hljs-number">1</span>,
  <span class="hljs-attr">gapY</span>: <span class="hljs-number">1</span>,
});
...<div aria-hidden="true" class="language-tag">TypeScript</div>
</code></pre><p>L&#39;idée ici c&#39;est d&#39;indiquer qu&#39;on veut que la ligne avec input et combobox prenne 6 fois moins de place en hauteur que result. </p>
<p>Ensuite on va créer des instances de <code>Rectangle</code>, <code>InputRectangle</code> et <code>LabelRectangle</code> qui vont bien à partir du rectangle que produit le layout pour chaque élément, car contrairement à ce que la documentation dit, on ne peut pas utiliser en direct ce que donne le layout, car on a un problème de compatibilité de type… Au passage on en profite pour forcer une hauteur à 1 pour le combobox.</p>
<pre><code class="hljs language-TypeScript">...
<span class="hljs-keyword">const</span> inputRectangle = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Computed</span>((): <span class="hljs-function"><span class="hljs-params">InputRectangle</span> =&gt;</span> {
  <span class="hljs-keyword">const</span> rect = layout.<span class="hljs-title function_">element</span>(<span class="hljs-string">&quot;input&quot;</span>);
  <span class="hljs-keyword">return</span> ({
    <span class="hljs-attr">column</span>: rect.<span class="hljs-property">value</span>.<span class="hljs-property">column</span>,
    <span class="hljs-attr">row</span>: rect.<span class="hljs-property">value</span>.<span class="hljs-property">row</span>,
    <span class="hljs-attr">width</span>: rect.<span class="hljs-property">value</span>.<span class="hljs-property">width</span>,
  });
});
<span class="hljs-keyword">const</span> comboboxRectangle = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Computed</span>((): <span class="hljs-function"><span class="hljs-params">Rectangle</span> =&gt;</span> {
  <span class="hljs-keyword">const</span> rect = layout.<span class="hljs-title function_">element</span>(<span class="hljs-string">&quot;combobox&quot;</span>);
  <span class="hljs-keyword">return</span> ({
    <span class="hljs-attr">column</span>: rect.<span class="hljs-property">value</span>.<span class="hljs-property">column</span>,
    <span class="hljs-attr">row</span>: rect.<span class="hljs-property">value</span>.<span class="hljs-property">row</span>,
    <span class="hljs-attr">width</span>: rect.<span class="hljs-property">value</span>.<span class="hljs-property">width</span>,
    <span class="hljs-attr">height</span>: <span class="hljs-number">1</span>,
  });
});
<span class="hljs-keyword">const</span> labelRectangle = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Computed</span>((): <span class="hljs-function"><span class="hljs-params">LabelRectangle</span> =&gt;</span> {
  <span class="hljs-keyword">const</span> rect = layout.<span class="hljs-title function_">element</span>(<span class="hljs-string">&quot;result&quot;</span>);
  <span class="hljs-keyword">return</span> ({
    <span class="hljs-attr">column</span>: rect.<span class="hljs-property">value</span>.<span class="hljs-property">column</span>,
    <span class="hljs-attr">row</span>: rect.<span class="hljs-property">value</span>.<span class="hljs-property">row</span>,
    <span class="hljs-attr">width</span>: rect.<span class="hljs-property">value</span>.<span class="hljs-property">width</span>,
    <span class="hljs-attr">height</span>: rect.<span class="hljs-property">value</span>.<span class="hljs-property">height</span>,
  });
});
...<div aria-hidden="true" class="language-tag">TypeScript</div>
</code></pre><p>Ensuite on va utiliser les différents rectangles qu&#39;on a créés sur nos composants :</p>
<pre><code class="hljs language-TypeScript">...
<span class="hljs-keyword">new</span> <span class="hljs-title class_">Input</span>({
  <span class="hljs-attr">parent</span>: tui,
  <span class="hljs-attr">placeholder</span>: <span class="hljs-string">&quot;type here&quot;</span>,
  <span class="hljs-attr">theme</span>: {
    <span class="hljs-attr">base</span>: crayon.<span class="hljs-property">bgLightBlack</span>,
    <span class="hljs-attr">focused</span>: crayon.<span class="hljs-property">bgLightGreen</span>,
    <span class="hljs-attr">active</span>: crayon.<span class="hljs-property">bgYellow</span>,
    <span class="hljs-attr">cursor</span>: { <span class="hljs-attr">base</span>: crayon.<span class="hljs-property">blue</span> },
  },
  text,
  <span class="hljs-attr">rectangle</span>: inputRectangle,
  <span class="hljs-attr">zIndex</span>: <span class="hljs-number">0</span>,
});

<span class="hljs-keyword">new</span> <span class="hljs-title class_">ComboBox</span>({
  <span class="hljs-attr">parent</span>: tui,
  <span class="hljs-attr">items</span>: <span class="hljs-variable constant_">AVAILABLE_FONTS</span>,
  <span class="hljs-attr">placeholder</span>: <span class="hljs-string">&quot;choose a style&quot;</span>,
  <span class="hljs-attr">selectedItem</span>: fontIndex,
  <span class="hljs-attr">theme</span>: {
    <span class="hljs-attr">base</span>: crayon.<span class="hljs-property">bgGreen</span>,
    <span class="hljs-attr">focused</span>: crayon.<span class="hljs-property">bgLightGreen</span>,
    <span class="hljs-attr">active</span>: crayon.<span class="hljs-property">bgYellow</span>,
  },
  <span class="hljs-attr">rectangle</span>: comboboxRectangle,
  <span class="hljs-attr">zIndex</span>: <span class="hljs-number">1000</span>,
});

<span class="hljs-keyword">new</span> <span class="hljs-title class_">Label</span>({
  <span class="hljs-attr">parent</span>: tui,
  <span class="hljs-attr">text</span>: asciiText,
  <span class="hljs-attr">multiCodePointSupport</span>: <span class="hljs-literal">true</span>,
  <span class="hljs-attr">theme</span>: {
    <span class="hljs-attr">base</span>: crayon.<span class="hljs-property">bgBlack</span>,
  },
  <span class="hljs-attr">rectangle</span>: labelRectangle,
  <span class="hljs-attr">zIndex</span>: <span class="hljs-number">0</span>,
  <span class="hljs-attr">overwriteRectangle</span>: <span class="hljs-literal">true</span>,
});
...<div aria-hidden="true" class="language-tag">TypeScript</div>
</code></pre><figure>
<img src="https://anthonypena.fr/2025/11/25/creer-un-tui-avec-deno/img/grid-layout.png" alt="Avec un grid layout" is="img-zoom"/>
<figcaption>Avec un grid layout</figcaption>
</figure>
<p>Avec un Grid Layout ça ne semble pas tellement différent visuellement, je suis d&#39;accord. Par contre ça ouvre la porte à un layout plus complexe, assez facilement.</p>
<h2 id="article-conclusion">Conclusion<a href="#article-conclusion" class="anchor" aria-label="permalink">🔗</a></h2>
<p>Je m&#39;arrête là pour cette démo de TUI en Deno. J&#39;ai choisi de le faire avec la lib <code>TUI</code> car bien qu&#39;écrite par un indépendant elle est écrite en pure-typescript pour Deno ça me paraissait un bon choix.</p>
<p>Cette librairie n&#39;est pas parfaite, on peut surement trouver mieux en allant chercher dans les dépendances NPM, mais cette lib fonctionne bien, et je pense qu&#39;il manquerait juste un peu d&#39;effort pour en faire un lib vraiment complète !</p>
<p>En tout cas, j&#39;ai bien relevé le défi de Thierry : j&#39;ai créé un TUI avec Deno ! 😎 Je n&#39;avais jamais créé de TUI et je pense que je le referais à l&#39;occasion vu comment c&#39;est finalement assez facile et pratique pour certains trucs ! 🤓</p>
<p>Source :</p>
<ul>
<li><a href="https://deno.com/">Deno</a></li>
<li><a href="https://github.com/Im-Beast/deno_tui">TUI lib</a></li>
<li><a href="https://www.npmjs.com/package/figlet">Figlet lib</a></li>
<li><a href="https://github.com/kuroidoruido/deno-cli-example/tree/main/hello-tui">Code source du projet</a></li>
</ul>
<p>Crédit photo : Générée via Mistral AI avec le prompt suivant :</p>
<blockquote>
<p>A cozy, magical developer&#39;s workshop inspired by Studio Ghibli, blending retro-futuristic and cyberpunk-light elements. The scene features a friendly anthropomorphic fox character (wearing glasses and a hoodie) sitting at a vintage CRT terminal, coding a TUI (Terminal User Interface) in Deno. The terminal screen displays an ASCII art banner dynamically changing fonts, an input field, and a combobox, just like in a Deno TUI demo. Beside the fox, a small, cute robot assistant—made of retro tech parts like gears, wires, and a tiny screen displaying a Deno logo—holds a floppy disk and points at the terminal with excitement. The workshop is filled with warm, soft lighting, floating holographic Deno logos (turquoise triangles), and retro tech like floppy disks, tangled cables, and a glowing neon desk lamp. The background includes lush greenery, floating books, and a starry night sky visible through a large window, creating a dreamy contrast between nature and technology. The color palette is a harmonious mix of pastel pinks, blues, and greens, with vibrant turquoise and neon accents highlighting the tech elements. The atmosphere is whimsical, creative, and inviting, evoking both the charm of Studio Ghibli and the nostalgia of 80s/90s cyberpunk. The fox is focused and happy, surrounded by tiny magical sparks and glowing code snippets floating in the air. The robot assistant has a playful, helpful expression, adding a touch of humor and warmth. The overall style is semi-realistic with a soft anime aesthetic, highly detailed, and visually rich, balancing organic and technological elements seamlessly.</p>
</blockquote>
]]></content:encoded>
      <dc:creator><![CDATA[Anthony Pena]]></dc:creator>
      <media:content medium="image" url="https://anthonypena.fr/img/cover.min.jpg"/>
    </item>
  </channel>
</rss>