<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet href="pretty-atom-feed.xsl" type="text/xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="fr">
  
  <title>Waly</title>
  <subtitle>Je partage mes expériences de développeur web passionné.</subtitle>
  <link href="https://ahmadouwalyndiaye.dev/feed/feed.xml" rel="self" />
  <link href="https://ahmadouwalyndiaye.dev/" />
  <updated>2026-04-25T00:00:00Z</updated>
  <id>https://ahmadouwalyndiaye.dev/</id>
  <author>
    <name>Ahmadou Waly NDIAYE</name>
    <email>ahmadouwalyndiaye@gmail.com</email>
  </author>
  <entry>
    <title>Cloud Resource Manager : provisionner de l&#39;AWS depuis une interface web</title>
    <link href="https://ahmadouwalyndiaye.dev/blog/examcloud/" />
    <updated>2026-04-25T00:00:00Z</updated>
    <id>https://ahmadouwalyndiaye.dev/blog/examcloud/</id>
    <content type="html">&lt;p&gt;Dans le cadre d&#39;un examen de Cloud Computing, j&#39;avais une semaine pour livrer un projet qui touche à AWS. L&#39;énoncé était assez libre — l&#39;essentiel était de démontrer qu&#39;on sait provisionner des ressources cloud. J&#39;aurais pu faire un script shell ou un simple README avec des captures. J&#39;ai préféré construire une vraie interface.&lt;/p&gt;
&lt;p&gt;Le projet : une application web qui permet de créer et supprimer des ressources AWS (EC2, S3, RDS) depuis un dashboard, sans jamais toucher à la console AWS. En coulisses, chaque action déclenche un pipeline GitLab CI/CD qui exécute Terraform.&lt;/p&gt;
&lt;p&gt;Le repo : &lt;a href=&quot;https://gitlab.com/sir-kane/exam-cloud&quot;&gt;gitlab.com/sir-kane/exam-cloud&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;la-stack&quot;&gt;La stack&lt;/h2&gt;
&lt;p&gt;Pour l&#39;interface, j&#39;ai choisi &lt;strong&gt;Laravel 11 + Filament 3 + Livewire 3&lt;/strong&gt;. Filament génère un admin panel propre très vite, et Livewire permet de faire des composants réactifs sans écrire de JS. Pour l&#39;infra : &lt;strong&gt;Terraform&lt;/strong&gt; côté IaC, &lt;strong&gt;GitLab CI/CD&lt;/strong&gt; comme moteur d&#39;exécution, et &lt;strong&gt;AWS&lt;/strong&gt; comme target.&lt;/p&gt;
&lt;p&gt;Le flux est simple : l&#39;utilisateur remplit un formulaire → Laravel appelle l&#39;API GitLab → un runner CI exécute Terraform → la ressource apparaît dans AWS.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;UI Filament → GitLabPipelineService → GitLab API → CI Runner (Terraform) → AWS
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;declencher-le-pipeline-a-la-demande&quot;&gt;Déclencher le pipeline à la demande&lt;/h2&gt;
&lt;p&gt;Le truc qui m&#39;a plu dans cette architecture, c&#39;est que le pipeline n&#39;est &lt;strong&gt;pas déclenché par un push&lt;/strong&gt;. Il est déclenché par l&#39;application, via l&#39;API GitLab, avec des variables qui décrivent la ressource à créer.&lt;/p&gt;
&lt;pre class=&quot;language-php&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// app/Services/GitLabPipelineService.php&lt;/span&gt;
&lt;span class=&quot;token class-name static-context&quot;&gt;Http&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;withHeaders&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;PRIVATE-TOKEN&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;token&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$gitlabUrl&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;/api/v4/projects/&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$projectId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;/pipeline&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;ref&#39;&lt;/span&gt;       &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;main&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;variables&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;key&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;TF_ACTION&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;       &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;value&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;apply&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;key&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;RESOURCE_TYPE&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;value&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;ec2&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;key&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;RESOURCE_NAME&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;value&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;mon-serveur&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;key&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;RESOURCE_REGION&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;value&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;us-east-1&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Dans le &lt;code&gt;.gitlab-ci.yml&lt;/code&gt;, le job &lt;code&gt;apply&lt;/code&gt; ne s&#39;exécute que si &lt;code&gt;$TF_ACTION == &amp;quot;apply&amp;quot;&lt;/code&gt;. Pour chaque type de ressource, Terraform reçoit les variables et n&#39;instancie que ce qui est demandé grâce à un &lt;code&gt;count&lt;/code&gt; conditionnel :&lt;/p&gt;
&lt;pre class=&quot;language-hcl&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-hcl&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;locals&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;is_ec2&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt; var.resource_type &lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ec2&quot;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;is_s3&lt;/span&gt;  &lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt; var.resource_type &lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;s3&quot;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;is_rds&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt; var.resource_type &lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;rds&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;resource &lt;span class=&quot;token type variable&quot;&gt;&quot;aws_instance&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;this&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;count&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt; local.is_ec2 ? &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; : &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;# ...&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Un seul &lt;code&gt;terraform apply&lt;/code&gt;, trois types de ressources, zéro duplication.&lt;/p&gt;
&lt;h2 id=&quot;le-piege-du-state-terraform-pour-la-suppression&quot;&gt;Le piège du state Terraform pour la suppression&lt;/h2&gt;
&lt;p&gt;C&#39;est là où j&#39;ai passé le plus de temps.&lt;/p&gt;
&lt;p&gt;Pour créer une ressource, Terraform est parfait. Pour la &lt;strong&gt;supprimer&lt;/strong&gt;, il y a un problème : le runner GitLab est éphémère. Chaque pipeline repart d&#39;un état vide. Un job &lt;code&gt;terraform destroy&lt;/code&gt; sur un state vide ne trouve rien à supprimer — et il ne fait rien.&lt;/p&gt;
&lt;p&gt;La solution : pour le destroy, j&#39;abandonne Terraform et j&#39;utilise l&#39;&lt;strong&gt;AWS CLI&lt;/strong&gt; directement. Chaque ressource a été créée avec un tag &lt;code&gt;ResourceId&lt;/code&gt; (l&#39;ID en base de l&#39;application). Le job de suppression retrouve la ressource par ce tag et la supprime.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# destroy-ec2&lt;/span&gt;
&lt;span class=&quot;token assign-left variable&quot;&gt;INSTANCE_ID&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;aws ec2 describe-instances &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--region&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$RESOURCE_REGION&lt;/span&gt;&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--filters&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Name=tag:ResourceId,Values=&lt;span class=&quot;token variable&quot;&gt;${RESOURCE_ID}&lt;/span&gt;&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
            &lt;span class=&quot;token string&quot;&gt;&quot;Name=instance-state-name,Values=running,stopped,pending,stopping&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Reservations[0].Instances[0].InstanceId&#39;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;

aws ec2 terminate-instances &lt;span class=&quot;token parameter variable&quot;&gt;--region&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$RESOURCE_REGION&lt;/span&gt;&quot;&lt;/span&gt; --instance-ids &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$INSTANCE_ID&lt;/span&gt;&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;C&#39;est moins élégant que du Terraform pur, mais c&#39;est robuste et ça marche indépendamment de l&#39;état du runner.&lt;/p&gt;
&lt;h2 id=&quot;deux-autres-problemes-rencontres&quot;&gt;Deux autres problèmes rencontrés&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Les noms de buckets S3 sont globaux.&lt;/strong&gt; Un nom comme &lt;code&gt;mon-bucket-test&lt;/code&gt; peut déjà appartenir à n&#39;importe quel autre compte AWS dans le monde. Pour garantir l&#39;unicité, j&#39;inclus l&#39;Account ID dans le nom :&lt;/p&gt;
&lt;pre class=&quot;language-hcl&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-hcl&quot;&gt;&lt;span class=&quot;token property&quot;&gt;bucket&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token type variable&quot;&gt;resource_slug&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;-&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token type variable&quot;&gt;aws_caller_identity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;current&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;account_id&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;-&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token type variable&quot;&gt;resource_id&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Les identifiants RDS ont des contraintes strictes.&lt;/strong&gt; AWS refuse tout ce qui n&#39;est pas minuscules + chiffres + tirets. Un nom avec des espaces ou des underscores lève une erreur de validation immédiate. Il faut normaliser le slug côté application avant de l&#39;envoyer au pipeline.&lt;/p&gt;
&lt;h2 id=&quot;trois-formulaires-et-un-chatbot&quot;&gt;Trois formulaires et un chatbot&lt;/h2&gt;
&lt;p&gt;L&#39;interface propose deux façons d&#39;arriver au même résultat.&lt;/p&gt;
&lt;p&gt;La première : trois formulaires Filament, un par type de ressource (EC2, S3, RDS). Chacun expose les paramètres propres à son type — région et instance type pour EC2, niveau d&#39;accès ACL pour S3, moteur et classe d&#39;instance pour RDS. Formulaire soumis → pipeline déclenché.&lt;/p&gt;
&lt;p&gt;La deuxième : un assistant Livewire en mode conversationnel. Même logique, même résultat final, mais l&#39;utilisateur avance étape par étape via des boutons. Il choisit d&#39;abord le type de ressource, puis la région, puis les options spécifiques, et confirme à la fin. Ça ressemble à un chatbot mais il n&#39;y a aucun LLM derrière — juste un composant Livewire avec une machine d&#39;états.&lt;/p&gt;
&lt;p&gt;L&#39;idée c&#39;était de proposer une UX plus accessible pour quelqu&#39;un qui ne sait pas ce qu&#39;est un &lt;code&gt;t3.micro&lt;/code&gt;, sans dupliquer la logique métier.&lt;/p&gt;
&lt;h2 id=&quot;ce-que-j-en-retiens&quot;&gt;Ce que j&#39;en retiens&lt;/h2&gt;
&lt;p&gt;Ce projet m&#39;a confirmé que GitLab CI/CD peut très bien servir de moteur d&#39;exécution de tâches, pas juste de pipeline de déploiement. Déclencher un pipeline à la demande avec des variables, c&#39;est une approche propre pour orchestrer de l&#39;IaC depuis une application métier.&lt;/p&gt;
&lt;p&gt;Le vrai enseignement côté Terraform : &lt;strong&gt;le state, c&#39;est tout&lt;/strong&gt;. Sans state persistant (S3 backend, Terraform Cloud…), le destroy devient un cas à gérer à part. C&#39;est quelque chose que je vais intégrer dès le début sur mes prochains projets.&lt;/p&gt;
&lt;h2 id=&quot;pour-aller-plus-loin&quot;&gt;Pour aller plus loin&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Dépôt GitLab : &lt;a href=&quot;https://gitlab.com/sir-kane/exam-cloud&quot;&gt;gitlab.com/sir-kane/exam-cloud&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://registry.terraform.io/providers/hashicorp/aws/latest/docs&quot;&gt;Documentation Terraform AWS Provider&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.gitlab.com/ee/api/pipelines.html#create-a-new-pipeline&quot;&gt;API GitLab – Trigger a pipeline&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>Talk: L&#39;outillage JavaScript au DevFest Yamoussoukro</title>
    <link href="https://ahmadouwalyndiaye.dev/blog/devfest-yamoussoukro/" />
    <updated>2025-12-13T00:00:00Z</updated>
    <id>https://ahmadouwalyndiaye.dev/blog/devfest-yamoussoukro/</id>
    <content type="html">&lt;iframe src=&quot;https://docs.google.com/presentation/d/1pxSYyPwBO1oXnx7nU0klt_atwqYBsA3SgAU1M7DkJ2g/embed?start=false&amp;loop=false&quot; width=&quot;100%&quot; height=&quot;420&quot; style=&quot;border:none;border-radius:8px;&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;text-align:left&quot;&gt;&lt;/th&gt;
&lt;th style=&quot;text-align:left&quot;&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:left&quot;&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;text-align:left&quot;&gt;13 décembre 2025&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:left&quot;&gt;&lt;strong&gt;Lieu&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;text-align:left&quot;&gt;Stade Charles Konan Banny, Yamoussoukro — &lt;img src=&quot;https://ahmadouwalyndiaye.dev/img/devfest.png&quot; alt=&quot;DevFest&quot; width=&quot;32&quot;&gt; &lt;a href=&quot;https://gdg.community.dev/&quot;&gt;DevFest Yamoussoukro 2025&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;p&gt;J&#39;avais déjà présenté ce talk sur l&#39;outillage JavaScript au &lt;a href=&quot;https://ahmadouwalyndiaye.dev/blog/devfest-dakar/&quot;&gt;DevFest Dakar&lt;/a&gt; en janvier. Quand l&#39;opportunité s&#39;est présentée de le faire à Yamoussoukro, j&#39;ai pas hésité.&lt;/p&gt;
&lt;p&gt;Faire le déplacement jusqu&#39;en Côte d&#39;Ivoire, c&#39;était l&#39;occasion de rencontrer des communautés de développeurs qu&#39;on ne croise pas habituellement. On parle souvent de la scène tech en Afrique de l&#39;Ouest comme d&#39;un tout, mais chaque ville a sa dynamique propre, ses centres d&#39;intérêt, ses questions. Les échanges qu&#39;on a eus surtout autour du développement Front m&#39;ont autant apporté que le talk lui-même.&lt;/p&gt;
&lt;p&gt;J&#39;ai beaucoup aimé cette journée.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Le contenu du talk couvre 4 mécanismes fondamentaux derrière les bundlers modernes (Webpack, Vite, Rollup...) :&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Minification&lt;/strong&gt; — réduire le poids des fichiers en supprimant les commentaires, espaces et en renommant les variables. Un fichier passe de 228 à 98 caractères, le comportement reste identique.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bundling&lt;/strong&gt; — concaténer plusieurs modules en un seul fichier pour limiter les requêtes HTTP.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tree Shaking&lt;/strong&gt; — supprimer le code non utilisé. Ça ne fonctionne qu&#39;avec des ES modules (exports nommés). L&#39;exemple qui illustre bien : moment.js (~250 Ko) vs day.js (~7 Ko) pour le même usage de dates.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Code Splitting&lt;/strong&gt; — charger les fichiers à la demande plutôt que tout d&#39;un coup. La primitive native, c&#39;est l&#39;import dynamique :&lt;/p&gt;
&lt;pre class=&quot;language-js&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;button&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;click&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; hello &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;./utils/hello.js&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;hello&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Sir Kane&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Le détail complet de chaque concept est dans le &lt;a href=&quot;https://ahmadouwalyndiaye.dev/blog/devfest-dakar/&quot;&gt;compte rendu du DevFest Dakar&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;pour-aller-plus-loin&quot;&gt;Pour aller plus loin&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Les slides : &lt;a href=&quot;https://docs.google.com/presentation/d/1pxSYyPwBO1oXnx7nU0klt_atwqYBsA3SgAU1M7DkJ2g/present&quot;&gt;ouvrir en plein écran&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Le code source des démos : &lt;a href=&quot;https://github.com/sir-kain/js-tools&quot;&gt;github.com/sir-kain/js-tools&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.astro.build/fr/reference/directives-reference/#directives-client&quot;&gt;Code splitting avec les directives Astro&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://bundlephobia.com/&quot;&gt;Bundlephobia — voir la taille d&#39;un package npm&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>Talk: Le Lazy-Loading (amélioration des perfs)</title>
    <link href="https://ahmadouwalyndiaye.dev/blog/lazy-loading/" />
    <updated>2025-12-05T00:00:00Z</updated>
    <id>https://ahmadouwalyndiaye.dev/blog/lazy-loading/</id>
    <content type="html">&lt;iframe src=&quot;https://docs.google.com/presentation/d/1UhLKGDT5KhIEVRGLFDIIyUtN8A1uzNbd/embed?start=false&amp;loop=false&quot; width=&quot;100%&quot; height=&quot;420&quot; style=&quot;border:none;border-radius:8px;&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;text-align:left&quot;&gt;&lt;/th&gt;
&lt;th style=&quot;text-align:left&quot;&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:left&quot;&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;text-align:left&quot;&gt;5 décembre 2025&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:left&quot;&gt;&lt;strong&gt;Lieu&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;text-align:left&quot;&gt;&lt;img src=&quot;https://ahmadouwalyndiaye.dev/img/tcm.svg&quot; alt=&quot;TheCodingMachine&quot; width=&quot;32&quot; height=&quot;32&quot; style=&quot;width:64px&quot;&gt; &lt;a href=&quot;https://www.thecodingmachine.com/&quot;&gt;TheCodingMachine&lt;/a&gt; · en ligne&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:left&quot;&gt;&lt;strong&gt;Demo&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;text-align:left&quot;&gt;&lt;a href=&quot;https://sir-kain.github.io/lazy-loading/&quot;&gt;sir-kain.github.io/lazy-loading&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;p&gt;Le lazy loading, c&#39;est une technique pour charger efficacement du contenu sur une page web. Ça répond à une seule question : &lt;strong&gt;quand charger ?&lt;/strong&gt; Pas quoi, pas comment — juste quand.&lt;/p&gt;
&lt;p&gt;L&#39;idée : ne charger un élément que quand il est sur le point d&#39;être visible. Pas la version &amp;quot;installe cette lib et ça marche&amp;quot;, mais la version &amp;quot;voilà ce que le navigateur sait faire tout seul&amp;quot;.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;pourquoi-s-en-preoccuper&quot;&gt;Pourquoi s&#39;en préoccuper ?&lt;/h2&gt;
&lt;p&gt;Une page web charge tout ce qu&#39;elle trouve dans le HTML, même ce qui est à 3 scrolls de distance et que l&#39;utilisateur ne verra peut-être jamais. C&#39;est du réseau gaspillé, du temps de chargement rallongé, et des métriques Lighthouse qui souffrent (FCP, LCP, Speed Index...).&lt;/p&gt;
&lt;h2 id=&quot;les-images-le-cas-le-plus-simple&quot;&gt;Les images — le cas le plus simple&lt;/h2&gt;
&lt;h3 id=&quot;loading-lazy-c-est-tout&quot;&gt;&lt;code&gt;loading=&amp;quot;lazy&amp;quot;&lt;/code&gt;, c&#39;est tout&lt;/h3&gt;
&lt;p&gt;La bonne nouvelle, c&#39;est que pour les images, le navigateur fait le travail depuis des années. Un seul attribut suffit :&lt;/p&gt;
&lt;pre class=&quot;language-html&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;mon-image.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;a ne jamais oublier&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;loading&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;lazy&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Pas de JavaScript. Pas de bibliothèque. Juste un attribut HTML natif, supporté partout. L&#39;image ne sera téléchargée que lorsqu&#39;elle approche du viewport.&lt;/p&gt;
&lt;h3 id=&quot;la-balise-picture-afficher-vs-bien-afficher&quot;&gt;La balise &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; : afficher VS bien afficher&lt;/h3&gt;
&lt;p&gt;L&#39;autre chose que j&#39;ai montrée, c&#39;est la différence entre &amp;quot;afficher une image&amp;quot; et &amp;quot;bien afficher une image&amp;quot;. Une &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; basique envoie la même image JPEG à tout le monde — mobile, desktop, connexion lente, écran Retina. C&#39;est rarement optimal.&lt;/p&gt;
&lt;p&gt;La balise &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; permet de laisser le navigateur choisir le meilleur format et la meilleure taille selon le contexte :&lt;/p&gt;
&lt;pre class=&quot;language-html&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;picture&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;source&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;image/avif&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;srcset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/image-400.avif 400w, /image-800.avif 800w, /image-1200.avif 1200w&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;sizes&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 800px&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;source&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;image/webp&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;srcset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/image-400.webp 400w, /image-800.webp 800w, /image-1200.webp 1200w&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;sizes&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 800px&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/image-800.jpeg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;srcset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/image-400.jpeg 400w, /image-800.jpeg 800w&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;sizes&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 800px&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;Description de l&#39;image&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;1600&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;900&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;loading&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;lazy&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;decoding&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;async&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;picture&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Le navigateur descend la liste : si AVIF est supporté, il prend AVIF. Sinon WebP. Sinon JPEG. Il choisit aussi la bonne taille selon la largeur d&#39;affichage. Et &lt;code&gt;loading=&amp;quot;lazy&amp;quot;&lt;/code&gt; + &lt;code&gt;decoding=&amp;quot;async&amp;quot;&lt;/code&gt; sur le &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; intérieur restent valides dans ce contexte.&lt;/p&gt;
&lt;h2 id=&quot;les-contenus-lourds-l-intersectionobserver&quot;&gt;Les contenus lourds — l&#39;IntersectionObserver&lt;/h2&gt;
&lt;p&gt;Pour tout ce qui n&#39;est pas une image (iframes, composants lourds, vidéos, sections entières), il n&#39;y a pas d&#39;attribut magique. Mais il y a une API native : &lt;strong&gt;IntersectionObserver&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Son rôle : détecter quand un élément entre dans le viewport, sans polling, sans événement &lt;code&gt;scroll&lt;/code&gt; chronophage.&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; observer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;IntersectionObserver&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;entries&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  entries&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;entry&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;entry&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;isIntersecting&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;// charger ici&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;threshold&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;rootMargin&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;0px&#39;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelectorAll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;.ma-class&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;el&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  observer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;observe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;el&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;threshold: 0.5&lt;/code&gt; signifie que le callback se déclenche quand 50% de l&#39;élément est visible. &lt;code&gt;rootMargin&lt;/code&gt; permet d&#39;anticiper le chargement avant même que l&#39;élément soit visible (par exemple &lt;code&gt;&#39;200px&#39;&lt;/code&gt; pour charger 200px avant l&#39;arrivée dans le viewport).&lt;/p&gt;
&lt;p&gt;C&#39;est cette API qui est derrière la plupart des implémentations modernes de lazy loading — y compris dans des frameworks comme Vue, React ou Angular.&lt;/p&gt;
&lt;h2 id=&quot;la-demo&quot;&gt;La démo&lt;/h2&gt;
&lt;p&gt;Pour illustrer tout ça, j&#39;ai fait une petite page de démo : &lt;a href=&quot;https://sir-kain.github.io/lazy-loading/&quot;&gt;sir-kain.github.io/lazy-loading&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Deux choses à observer :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Images adaptatives&lt;/strong&gt; : l&#39;image mobile ne charge que sur mobile, l&#39;image desktop seulement sur desktop — grâce à &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; et ses &lt;code&gt;&amp;lt;source&amp;gt;&lt;/code&gt; avec media queries.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;IntersectionObserver en action&lt;/strong&gt; : chaque section affiche un message dans la console (&lt;code&gt;Partie 1 affichée&lt;/code&gt;, &lt;code&gt;Partie 2 affichée&lt;/code&gt;...) uniquement quand elle devient visible dans le viewport. Ouvre les DevTools et fais défiler — tu verras les logs apparaître au bon moment.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;pour-aller-plus-loin&quot;&gt;Pour aller plus loin&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Les slides : &lt;a href=&quot;https://docs.google.com/presentation/d/1UhLKGDT5KhIEVRGLFDIIyUtN8A1uzNbd/present&quot;&gt;ouvrir en plein écran&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;La démo : &lt;a href=&quot;https://sir-kain.github.io/lazy-loading/&quot;&gt;sir-kain.github.io/lazy-loading&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Le code source : &lt;a href=&quot;https://github.com/sir-kain/lazy-loading&quot;&gt;github.com/sir-kain/lazy-loading&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/fr/docs/Web/HTML/Element/img#loading&quot;&gt;&lt;code&gt;loading&lt;/code&gt; sur MDN&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/fr/docs/Web/HTML/Element/picture&quot;&gt;&lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; sur MDN&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/fr/docs/Web/API/Intersection_Observer_API&quot;&gt;Intersection Observer API sur MDN&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/performance/first-contentful-paint?hl=fr&quot;&gt;Métriques Lighthouse (FCP, LCP, CLS...)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>Talk: Chrome built-in AI APIs</title>
    <link href="https://ahmadouwalyndiaye.dev/blog/chrome-builtin-ai/" />
    <updated>2025-10-25T00:00:00Z</updated>
    <id>https://ahmadouwalyndiaye.dev/blog/chrome-builtin-ai/</id>
    <content type="html">&lt;iframe src=&quot;https://docs.google.com/presentation/d/1AOr12gD7B9Y_7yTUVKyG6FTmrHMPdacD/embed?start=false&amp;loop=false&quot; width=&quot;100%&quot; height=&quot;420&quot; style=&quot;border:none;border-radius:8px;&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;text-align:left&quot;&gt;&lt;/th&gt;
&lt;th style=&quot;text-align:left&quot;&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:left&quot;&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;text-align:left&quot;&gt;25 octobre 2025&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:left&quot;&gt;&lt;strong&gt;Lieu&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;text-align:left&quot;&gt;FST de l&#39;UCAD, Dakar — &lt;a href=&quot;https://galsen.dev/&quot;&gt;Hacktoberfest Galsen Dev&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Demo : &lt;a href=&quot;https://chrome-ia.netlify.app/&quot;&gt;chrome-ia.netlify.app&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Le 25 octobre 2025, &lt;a href=&quot;https://galsen.dev/&quot;&gt;Galsen Dev&lt;/a&gt; organisait son Hacktoberfest à la FST de l&#39;UCAD. J&#39;ai eu un slot pour présenter quelque chose que je suivais depuis un moment dans ma veille : les &lt;strong&gt;APIs IA intégrées directement dans Chrome&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Le sujet a bien résonné dans la salle, alors j&#39;en fais un résumé ici.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Prérequis indispensable&lt;/strong&gt; : avant tout, il faut rejoindre le &lt;a href=&quot;https://developer.chrome.com/docs/ai/join-epp&quot;&gt;Early Preview Program (EPP)&lt;/a&gt;. Sans ça, les APIs ne sont tout simplement pas disponibles dans le navigateur.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;l-idee-centrale&quot;&gt;L&#39;idée centrale&lt;/h2&gt;
&lt;p&gt;Aujourd&#39;hui, intégrer de l&#39;IA dans une app web passe forcément par un serveur : on envoie la requête, le modèle tourne quelque part dans le cloud, la réponse revient. Ça marche, mais ça implique de la latence, des coûts, une connexion internet — et les données de l&#39;utilisateur quittent son appareil.&lt;/p&gt;
&lt;p&gt;Ce que Google est en train d&#39;expérimenter, c&#39;est de faire tourner &lt;strong&gt;Gemini Nano&lt;/strong&gt; directement dans Chrome. Pas dans le cloud. Dans le navigateur, sur la machine de l&#39;utilisateur. Avec trois bénéfices immédiats : &lt;strong&gt;privé, offline, performant&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;La taille exacte du modèle peut varier au fil des mises à jour de Chrome — actuellement environ &lt;strong&gt;4 Go&lt;/strong&gt;. Pour voir la version installée sur votre machine, rendez-vous sur &lt;strong&gt;&lt;code&gt;chrome://on-device-internals&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&quot;ce-que-j-ai-montre&quot;&gt;Ce que j&#39;ai montré&lt;/h2&gt;
&lt;p&gt;La partie qui a le plus intrigué la salle, c&#39;est la simplicité du code. Appeler un LLM depuis le navigateur, ça ressemble à ça :&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; session &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; LanguageModel&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;expectedInputs&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;text&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;languages&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;en&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;expectedOutputs&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;text&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;languages&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;en&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; response &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; session&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;prompt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Explain quantum computing like I&#39;m five.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Pas de clé API. Pas de requête HTTP. Le modèle répond directement.&lt;/p&gt;
&lt;p&gt;Il y a aussi une &lt;strong&gt;Translator API&lt;/strong&gt;, une &lt;strong&gt;Summarizer API&lt;/strong&gt;, un &lt;strong&gt;Language Detector&lt;/strong&gt;... Autant de fonctionnalités exposées nativement, sans dépendance externe.&lt;/p&gt;
&lt;p&gt;Ce qui m&#39;a convaincu que c&#39;est une direction sérieuse : &lt;strong&gt;Bluesky l&#39;utilise déjà&lt;/strong&gt; pour traduire les posts. Thomas Steiner (@tomayac) en a parlé &lt;a href=&quot;https://bsky.app/profile/tomayac.com/post/3lzlaf5kpq22x&quot;&gt;ici&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;ce-qu-il-faut-retenir&quot;&gt;Ce qu&#39;il faut retenir&lt;/h2&gt;
&lt;p&gt;C&#39;est encore en &lt;strong&gt;early preview&lt;/strong&gt;, pas activé par défaut. Donc pas question de l&#39;utiliser en prod sans fallback. Mais c&#39;est une direction qui mérite d&#39;être suivie de près, surtout pour ceux qui construisent des apps où la confidentialité et le mode offline comptent.&lt;/p&gt;
&lt;p&gt;Sur la standardisation : Google a déjà proposé ces APIs à la communauté web et les a soumises au &lt;strong&gt;&lt;a href=&quot;https://www.w3.org/standards/about/&quot;&gt;W3C&lt;/a&gt;&lt;/strong&gt; et au &lt;strong&gt;&lt;a href=&quot;https://wicg.io/&quot;&gt;Web Incubator Community Group (WICG)&lt;/a&gt;&lt;/strong&gt; pour discussion. L&#39;objectif à terme est qu&#39;elles fonctionnent dans tous les navigateurs, pas seulement Chrome.&lt;/p&gt;
&lt;h2 id=&quot;pour-aller-plus-loin&quot;&gt;Pour aller plus loin&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Les slides : &lt;a href=&quot;https://docs.google.com/presentation/d/1AOr12gD7B9Y_7yTUVKyG6FTmrHMPdacD/present&quot;&gt;ouvrir en plein écran&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Ma démo interactive : &lt;a href=&quot;https://chrome-ia.netlify.app/&quot;&gt;chrome-ia.netlify.app&lt;/a&gt; &lt;em&gt;(Chrome requis + early preview)&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Le code source : &lt;a href=&quot;https://github.com/sir-kain/chrome-ia&quot;&gt;github.com/sir-kain/chrome-ia&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Rejoindre le programme early preview : &lt;a href=&quot;https://goo.gle/chrome-ai-dev-preview-join&quot;&gt;goo.gle/chrome-ai-dev-preview-join&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Plus de démos officielles à explorer : &lt;a href=&quot;https://chrome.dev/web-ai-demos/&quot;&gt;chrome.dev/web-ai-demos&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>Talk: L&#39;outillage JavaScript - Les bundler</title>
    <link href="https://ahmadouwalyndiaye.dev/blog/devfest-dakar/" />
    <updated>2025-01-13T00:00:00Z</updated>
    <id>https://ahmadouwalyndiaye.dev/blog/devfest-dakar/</id>
    <content type="html">&lt;iframe src=&quot;https://docs.google.com/presentation/d/1pxSYyPwBO1oXnx7nU0klt_atwqYBsA3SgAU1M7DkJ2g/embed?start=false&amp;loop=false&quot; width=&quot;100%&quot; height=&quot;420&quot; style=&quot;border:none;border-radius:8px;&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;text-align:left&quot;&gt;&lt;/th&gt;
&lt;th style=&quot;text-align:left&quot;&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:left&quot;&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;text-align:left&quot;&gt;13 janvier 2025&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:left&quot;&gt;&lt;strong&gt;Lieu&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;text-align:left&quot;&gt;Hôtel Sea Plaza, Dakar — &lt;img src=&quot;https://ahmadouwalyndiaye.dev/img/devfest.png&quot; alt=&quot;DevFest&quot; width=&quot;32&quot;&gt; &lt;a href=&quot;https://gdg.community.dev/gdg-dakar/&quot;&gt;DevFest Dakar&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://ahmadouwalyndiaye.dev/blog/devfest-dakar/kOlqr3Ru_3-2048.avif 2048w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://ahmadouwalyndiaye.dev/blog/devfest-dakar/kOlqr3Ru_3-2048.webp 2048w&quot;&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://ahmadouwalyndiaye.dev/blog/devfest-dakar/kOlqr3Ru_3-2048.jpeg&quot; alt=&quot;Présentation de l&#39;outillage JavaScript au DevFest Dakar 2025&quot; width=&quot;2048&quot; height=&quot;1542&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Quand on parle d&#39;outillage JavaScript, on parle souvent de Webpack, Vite, Rollup... sans vraiment savoir ce qu&#39;ils font sous le capot. Au DevFest Dakar, j&#39;ai pris le parti de décortiquer les 4 mécanismes fondamentaux derrière ces outils.&lt;/p&gt;
&lt;h2 id=&quot;minification&quot;&gt;Minification&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Objectif : réduire le poids des fichiers à charger par le navigateur.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Le navigateur n&#39;a pas besoin de code lisible. Il n&#39;a besoin que de code fonctionnel. La minification exploite ça en appliquant plusieurs transformations successives :&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Suppression des commentaires, espaces et sauts de ligne inutiles&lt;/li&gt;
&lt;li&gt;Renommage des variables en noms courts (&lt;code&gt;firstNumber&lt;/code&gt; → &lt;code&gt;f&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Réécriture avec des opérateurs plus compacts (ternaires, etc.)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Résultat concret sur un fichier &lt;code&gt;math.js&lt;/code&gt; : &lt;strong&gt;228 caractères → 98 caractères&lt;/strong&gt;, sans changer le comportement.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Avant (math.js) — 228 chars&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;firstNumber&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; secondNumber&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; firstNumber &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; secondNumber&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// Recursivity&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;factorial&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;number &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; number &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;factorial&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;number &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Après (math.min.js) — 98 chars&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;f&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;s&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; f&lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;s&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;factorial&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; n&lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;n&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;factorial&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Les outils du marché, du plus lent au plus rapide : &lt;strong&gt;Terser&lt;/strong&gt; (JS, 2018), &lt;strong&gt;SWC&lt;/strong&gt; (Rust, 2019), &lt;strong&gt;Esbuild&lt;/strong&gt; (Go, 2020).&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;Don&#39;t minify what you don&#39;t need. Minification without tree-shaking is like compressing a trash can without taking out the garbage.&amp;quot; — &lt;em&gt;Philip Walton&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;bundling&quot;&gt;Bundling&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Objectif : concaténer plusieurs fichiers en un seul.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Un projet JS moderne est découpé en modules. Sans bundler, le navigateur doit faire une requête HTTP par fichier. Le bundling rassemble tout en un &lt;code&gt;bundle.js&lt;/code&gt; unique.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// math.js&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; b

&lt;span class=&quot;token comment&quot;&gt;// index.js&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; add &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;./math&#39;&lt;/span&gt;
console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// → bundle.js&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; b
console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Les &lt;code&gt;import&lt;/code&gt;/&lt;code&gt;export&lt;/code&gt; disparaissent, le code est inliné. Une seule requête réseau au lieu de deux.&lt;/p&gt;
&lt;h2 id=&quot;tree-shaking&quot;&gt;Tree Shaking&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Objectif : supprimer le code non utilisé.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Le tree shaking, c&#39;est ce qui fait que si tu importes &lt;code&gt;add&lt;/code&gt; depuis un fichier qui exporte aussi &lt;code&gt;subtract&lt;/code&gt;, seul &lt;code&gt;add&lt;/code&gt; se retrouve dans le bundle final. Mais ça ne fonctionne qu&#39;avec des &lt;strong&gt;ES modules&lt;/strong&gt; (exports nommés), pas avec CommonJS.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// ❌ Non tree shakable — exporte un objet entier&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// math.js&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; math &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;subtract&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; b &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; math
&lt;span class=&quot;token comment&quot;&gt;// index.js — importe tout l&#39;objet même si on n&#39;utilise que add&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; math &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;./math&#39;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// ✅ Tree shakable — exports nommés&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// math.js&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; b
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;subtract&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; b
&lt;span class=&quot;token comment&quot;&gt;// index.js — seul add est inclus dans le bundle&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; add &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;./math&#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Un exemple qui parle : &lt;strong&gt;moment.js&lt;/strong&gt; (~250 Ko) vs &lt;strong&gt;day.js&lt;/strong&gt; (~7 Ko) pour le même usage. La différence vient en grande partie du fait que moment.js n&#39;est pas tree shakable.&lt;/p&gt;
&lt;h2 id=&quot;code-splitting&quot;&gt;Code Splitting&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Objectif : charger les fichiers à la demande, pas tous d&#39;un coup.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Le bundling crée un seul fichier — mais si ce fichier fait 2 Mo, l&#39;utilisateur le télécharge entier au premier chargement, même pour les parties qu&#39;il ne verra jamais. Le code splitting inverse la logique : on découpe en plusieurs chunks, chargés uniquement quand on en a besoin.&lt;/p&gt;
&lt;p&gt;La primitive native, c&#39;est l&#39;&lt;strong&gt;import dynamique&lt;/strong&gt; :&lt;/p&gt;
&lt;pre class=&quot;language-js&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;button&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;click&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; hello &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;./utils/hello.js&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;hello&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Sir Kane&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Le fichier &lt;code&gt;hello.js&lt;/code&gt; n&#39;est téléchargé qu&#39;au clic. Avant ça, zéro requête.&lt;/p&gt;
&lt;p&gt;Les frameworks ont leurs propres abstractions par-dessus : &lt;code&gt;defineAsyncComponent&lt;/code&gt; en Vue, les &lt;code&gt;client:&lt;/code&gt; directives en Astro (&lt;code&gt;client:load&lt;/code&gt;, &lt;code&gt;client:idle&lt;/code&gt;, &lt;code&gt;client:visible&lt;/code&gt;...).&lt;/p&gt;
&lt;h2 id=&quot;pour-aller-plus-loin&quot;&gt;Pour aller plus loin&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Les slides : &lt;a href=&quot;https://docs.google.com/presentation/d/1pxSYyPwBO1oXnx7nU0klt_atwqYBsA3SgAU1M7DkJ2g/present&quot;&gt;ouvrir en plein écran&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Le code source des démos : &lt;a href=&quot;https://github.com/sir-kain/js-tools&quot;&gt;github.com/sir-kain/js-tools&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.astro.build/fr/reference/directives-reference/#directives-client&quot;&gt;Code splitting avec les directives Astro&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=zxiJXQpRa4E&quot;&gt;Conf de Hubert Sablonnière sur la compression&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://bundlephobia.com/&quot;&gt;Bundlephobia — voir la taille d&#39;un package npm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/articles/lcp?hl=fr&quot;&gt;Métriques LCP sur web.dev&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>Les combinateurs de promesses en JavaScript</title>
    <link href="https://ahmadouwalyndiaye.dev/blog/promise-combinators/" />
    <updated>2024-08-18T00:00:00Z</updated>
    <id>https://ahmadouwalyndiaye.dev/blog/promise-combinators/</id>
    <content type="html">&lt;p&gt;&lt;video src=&quot;https://ahmadouwalyndiaye.dev/blog/promise-combinators/promise-strategies.mp4&quot; width=&quot;100%&quot; style=&quot;border-radius:8px;&quot; autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot; playsinline=&quot;&quot;&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Dès qu&#39;on a plusieurs tâches asynchrones à gérer en parallèle, la question se pose : comment les orchestrer ? C&#39;est là qu&#39;interviennent les &lt;strong&gt;combinateurs de promesses&lt;/strong&gt;. JavaScript en fournit quatre nativement, et chacun a un comportement bien précis.&lt;/p&gt;
&lt;p&gt;Pour illustrer ça, j&#39;ai construit un petit &lt;a href=&quot;https://promise-combinator.netlify.app/&quot;&gt;showcase&lt;/a&gt; avec 3 promesses qui se résolvent ou échouent aléatoirement dans un intervalle de 3 secondes. On peut observer en direct ce que chaque combinateur retourne selon les résultats.&lt;/p&gt;
&lt;h2 id=&quot;promise-all&quot;&gt;Promise.all&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Échoue dès qu&#39;une promesse est rejetée. Sinon, retourne un tableau de tous les résultats.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;C&#39;est le combinateur &amp;quot;tout ou rien&amp;quot;. Si les 3 promesses réussissent, tu récupères leurs 3 résultats dans l&#39;ordre. Si une seule échoue, tu tombes directement dans le &lt;code&gt;catch&lt;/code&gt; — peu importe ce qu&#39;ont fait les autres.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; results &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; Promise&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;p1&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; p2&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; p3&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// → [résultat1, résultat2, résultat3]&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// ou rejet si l&#39;une échoue&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;À utiliser quand toutes les tâches sont indispensables — par exemple charger les données d&#39;un utilisateur et ses permissions en même temps. Si l&#39;une échoue, il n&#39;y a rien à afficher.&lt;/p&gt;
&lt;h2 id=&quot;promise-any&quot;&gt;Promise.any&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Se résout dès qu&#39;une promesse réussit. Échoue seulement si toutes sont rejetées.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;L&#39;inverse de &lt;code&gt;all&lt;/code&gt; en quelque sorte. La première promesse qui réussit gagne, les autres sont ignorées. Si toutes échouent, tu reçois une &lt;code&gt;AggregateError&lt;/code&gt; qui regroupe toutes les erreurs.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; Promise&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;p1&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; p2&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; p3&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// → le résultat de la 1ère promesse résolue&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// ou AggregateError si toutes échouent&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Utile pour des stratégies de fallback — par exemple essayer plusieurs sources de données et prendre la première qui répond.&lt;/p&gt;
&lt;h2 id=&quot;promise-race&quot;&gt;Promise.race&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Se résout ou se rejette en fonction de la première promesse qui se termine, qu&#39;elle réussisse ou échoue.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Là où &lt;code&gt;any&lt;/code&gt; attend une réussite, &lt;code&gt;race&lt;/code&gt; réagit à n&#39;importe quel résultat — succès ou échec. Le premier arrivé l&#39;emporte.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; Promise&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;race&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;p1&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; p2&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; p3&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// → résultat ou erreur de la 1ère promesse terminée&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Cas d&#39;usage classique : implémenter un timeout. On met en course la vraie requête contre une promesse qui rejette après N secondes — si la requête est trop lente, le timeout l&#39;emporte.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; timeout &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;_&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; reject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;reject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Timeout&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; Promise&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;race&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fetchData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; timeout&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;promise-allsettled&quot;&gt;Promise.allSettled&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Se résout toujours. Retourne un tableau avec le statut de chaque promesse, succès ou échec.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Contrairement aux autres, &lt;code&gt;allSettled&lt;/code&gt; n&#39;abandonne jamais. Il attend que toutes les promesses soient terminées et te donne un bilan complet — ce qui a réussi, ce qui a échoué, et pourquoi.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; results &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; Promise&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;allSettled&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;p1&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; p2&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; p3&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// → [&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//   { status: &quot;fulfilled&quot;, value: ... },&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//   { status: &quot;rejected&quot;, reason: ... },&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//   { status: &quot;fulfilled&quot;, value: ... },&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// ]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;C&#39;est le combinateur le plus &amp;quot;safe&amp;quot;. Utile quand les tâches sont indépendantes et qu&#39;on veut traiter chaque résultat même en cas d&#39;échec partiel — envoyer plusieurs notifications, ou déclencher des actions en parallèle sans que l&#39;une bloque les autres.&lt;/p&gt;
&lt;h2 id=&quot;en-resume&quot;&gt;En résumé&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;text-align:left&quot;&gt;Combinateur&lt;/th&gt;
&lt;th style=&quot;text-align:left&quot;&gt;Se résout si...&lt;/th&gt;
&lt;th style=&quot;text-align:left&quot;&gt;Échoue si...&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:left&quot;&gt;&lt;code&gt;Promise.all&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align:left&quot;&gt;toutes réussissent&lt;/td&gt;
&lt;td style=&quot;text-align:left&quot;&gt;au moins une échoue&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:left&quot;&gt;&lt;code&gt;Promise.any&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align:left&quot;&gt;au moins une réussit&lt;/td&gt;
&lt;td style=&quot;text-align:left&quot;&gt;toutes échouent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:left&quot;&gt;&lt;code&gt;Promise.race&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align:left&quot;&gt;la 1ère se termine (succès)&lt;/td&gt;
&lt;td style=&quot;text-align:left&quot;&gt;la 1ère se termine (échec)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:left&quot;&gt;&lt;code&gt;Promise.allSettled&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align:left&quot;&gt;toujours&lt;/td&gt;
&lt;td style=&quot;text-align:left&quot;&gt;jamais&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Le code source et le showcase interactif sont dispo sur &lt;a href=&quot;https://github.com/sir-kain/promise-combinator&quot;&gt;github.com/sir-kain/promise-combinator&lt;/a&gt; — la démo permet de rejouer les scénarios pour voir les résultats en conditions réelles.&lt;/p&gt;
&lt;h2 id=&quot;pour-aller-plus-loin&quot;&gt;Pour aller plus loin&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise&quot;&gt;MDN — Promise combinators&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://promise-combinator.netlify.app/&quot;&gt;Démo interactive&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/sir-kain/promise-combinator&quot;&gt;Code source&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Discussion sur &lt;a href=&quot;https://www.linkedin.com/posts/ndiaye-ahmadou-waly-a61056ba_javascript-activity-7230581701834346496-ZfB2?utm_source=share&amp;amp;utm_medium=member_desktop&amp;amp;rcm=ACoAABlHo2kBLy8KE-CT5FHx-VPzPxL6RDQ_SQI&quot;&gt;LinkedIn&lt;/a&gt; et &lt;a href=&quot;https://x.com/_sir_kane/status/1824800762536382596&quot;&gt;Twitter/X&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
</feed>