<?xml version="1.0" encoding="UTF-8"?><rss 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" version="2.0" xmlns:media="http://search.yahoo.com/mrss/">
    <channel>
        <title><![CDATA[Code-Garage]]></title>
        <description><![CDATA[Code-Garage]]></description>
        <link>https://code-garage.com</link>
        <generator>RSS for Node</generator>
        <lastBuildDate>Thu, 16 Jul 2026 09:49:18 GMT</lastBuildDate>
        <atom:link href="https://code-garage.com/blog/rss" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Comprendre l’authentification avec Github (OAuth) ]]></title>
            <description><![CDATA[Découvrez comment fonctionne la connexion avec GitHub grâce à OAuth et apprenez à implémenter simplement un bouton "Se connecter avec GitHub" dans votre application.]]></description>
            <link>https://code-garage.com/blog/comprendre-l-authentification-avec-github-oauth </link>
            <guid isPermaLink="true">https://code-garage.com/blog/comprendre-l-authentification-avec-github-oauth </guid>
            <category><![CDATA[GitHub]]></category>
            <category><![CDATA[Authentification]]></category>
            <dc:creator><![CDATA[NicolasBrondinBernard]]></dc:creator>
            <pubDate>Wed, 15 Jul 2026 09:44:13 GMT</pubDate>
            <content:encoded><![CDATA[<p>Proposer un bouton <strong>&quot;Se connecter avec GitHub&quot;</strong> dans une application est un super moyen d’optimiser son taux de conversion : C'est pratique pour l'utilisateur, <strong>qui n'a pas besoin de créer un nouveau mot de passe.</strong></p>
<p>::: image
<img src="https://code-garage-strapi-bucket-production.cellar-c2.services.clever-cloud.com/Capture_d_ecran_2026_07_15_105702_94b38518f3.png" alt="">
:::</p>
<p>Mais aussi pour le développeur, qui délègue l'authentification à GitHub. Pourtant, beaucoup de développeurs utilisent OAuth <strong>sans réellement comprendre ce qu'il se passe derrière.</strong></p>
<p>Votre application ne connaît jamais le mot de passe GitHub de l'utilisateur. À la place, elle laisse GitHub vérifier son identité, puis récupère uniquement les informations dont elle a besoin.</p>
<blockquote>
<p>C'est tout le principe d'OAuth : déléguer l'authentification à un service tiers.</p>
</blockquote>
<h2>Implémenter Github Connect</h2>
<h3>Créer une OAuth App</h3>
<p>La première étape consiste à créer une application sur GitHub.</p>
<p>Pour cela, rendez-vous dans les paramètres de votre compte, puis dans <strong>Developer settings &gt; OAuth Apps</strong>.</p>
<p>::: image
<img src="https://code-garage-strapi-bucket-production.cellar-c2.services.clever-cloud.com/Capture_d_ecran_2026_07_15_105805_8352d16af5.png" alt="">
:::
Vous devrez notamment renseigner :</p>
<ul>
<li>le nom de votre application ;</li>
<li>son URL ;</li>
<li>une URL de callback.</li>
</ul>
<p>Par exemple :</p>
<pre><code>http://localhost:3000/auth/github/callback
</code></pre>
<p>Une fois l'application créée, GitHub vous fournit deux informations importantes :</p>
<pre><code>Client ID
Client Secret
</code></pre>
<p>Le <strong>Client ID</strong> identifie votre application.</p>
<p>Le <strong>Client Secret</strong>, lui, est confidentiel.</p>
<blockquote>
<p>Il ne doit jamais être envoyé au navigateur ni intégré dans votre code frontend.</p>
</blockquote>
<h4>Astuce</h4>
<p>Vous pouvez créer autant d’application que vous voulez, donc il est au moins recommandé d’en créer une pour votre environnement de production, et une pour le local.</p>
<blockquote>
<p>Vous pouvez l’appeler “MonApp (local)” par exemple.</p>
</blockquote>
<h3>Rediriger l'utilisateur vers GitHub</h3>
<p>Lorsque l'utilisateur clique sur <strong>&quot;Se connecter avec GitHub&quot;</strong>, votre application ne tente pas de l'authentifier elle-même.</p>
<p>Elle le redirige simplement vers GitHub.</p>
<p>Par exemple :</p>
<pre><code class="language-jsx">const params = new URLSearchParams({
  client_id: process.env.GITHUB_CLIENT_ID,
  redirect_uri: &quot;http://localhost:3000/auth/github/callback&quot;,
  scope: &quot;read:user user:email&quot;,
  state: crypto.randomUUID(),
});

response.redirect(
  `https://github.com/login/oauth/authorize?${params}`
);
</code></pre>
<p>Le paramètre <code>scope</code> indique les informations que votre application souhaite récupérer.</p>
<p>Le paramètre <code>state</code> est un identifiant aléatoire permettant de protéger le flux contre certaines attaques. Il doit être enregistré avant la redirection puis vérifié lorsque GitHub renvoie l'utilisateur.</p>
<h3>GitHub authentifie l'utilisateur</h3>
<p>L'utilisateur arrive alors sur GitHub et s'il n'est pas déjà connecté, <strong>GitHub lui demande de s'authentifier.</strong></p>
<p>GitHub lui affiche ensuite les permissions demandées par votre application et lui demande de les accepter. <strong>Votre application ne voit jamais cette étape.</strong></p>
<blockquote>
<p>Elle attend simplement que GitHub renvoie l'utilisateur vers l'URL de callback.</p>
</blockquote>
<p>::: image
<img src="https://code-garage-strapi-bucket-production.cellar-c2.services.clever-cloud.com/Capture_d_ecran_2026_07_15_110351_5677edbb00.png" alt="">
:::</p>
<h3>Récupérer un code temporaire</h3>
<p>Une fois les permissions acceptées, <strong>GitHub redirige le navigateur</strong> vers votre callback.</p>
<p>L'URL ressemble à ceci :</p>
<pre><code>/auth/github/callback?code=...&amp;state=...
</code></pre>
<blockquote>
<p><strong>Le <code>code</code> est un identifiant temporaire.</strong> À lui seul, il ne permet pas d'appeler l'API GitHub.</p>
</blockquote>
<p>Votre serveur doit d'abord l'échanger contre un <strong>Access Token</strong>.</p>
<pre><code class="language-jsx">const tokenResponse = await fetch(
  &quot;https://github.com/login/oauth/access_token&quot;,
  {
    method: &quot;POST&quot;,
    headers: {
      Accept: &quot;application/json&quot;,
      &quot;Content-Type&quot;: &quot;application/json&quot;,
    },
    body: JSON.stringify({
      client_id: process.env.GITHUB_CLIENT_ID,
      client_secret: process.env.GITHUB_CLIENT_SECRET,
      code,
    }),
  }
);

const { access_token } = await tokenResponse.json();
</code></pre>
<blockquote>
<p>Cette requête doit toujours être effectuée côté serveur, <strong>car elle utilise votre Client Secret.</strong></p>
</blockquote>
<h3>Récupérer l'email de l'utilisateur</h3>
<p>Une fois le token obtenu, vous pouvez appeler l'API GitHub, par exemple pour récupérer les adresses email du compte :</p>
<pre><code class="language-jsx">const emailsResponse = await fetch(
  &quot;https://api.github.com/user/emails&quot;,
  {
    headers: {
      Authorization: `Bearer ${access_token}`,
      Accept: &quot;application/vnd.github+json&quot;,
    },
  }
);

const emails = await emailsResponse.json();

const primaryEmail = emails.find(
  (email) =&gt; email.primary &amp;&amp; email.verified
)?.email;
</code></pre>
<p>L'adresse email principale est généralement le meilleur identifiant à utiliser.</p>
<p><strong>En effet, si un utilisateur possède déjà un compte créé avec Google</strong> ou avec un email et un mot de passe, il est probable que cette adresse soit la même.</p>
<blockquote>
<p>Cela permet de proposer plusieurs méthodes de connexion <strong>tout en conservant un seul compte utilisateur.</strong></p>
</blockquote>
<h3>Générer le JWT de votre application</h3>
<p>À ce stade, GitHub a terminé son travail, <strong>votre application connaît désormais l'identité de l'utilisateur.</strong></p>
<blockquote>
<p>Il ne reste plus qu'à rechercher un utilisateur possédant cette adresse email.</p>
</blockquote>
<ul>
<li>S'il n'existe pas encore, vous pouvez <strong>lui créer un compte automatiquement.</strong></li>
<li>Sinon, on récupère simplement ses infos dans la base de données</li>
</ul>
<p>Une fois cette étape terminée, vous générez votre propre token JWT :</p>
<pre><code class="language-jsx">const token = jwt.sign(
  {
    userId: user.id,
    email: user.email,
  },
  process.env.JWT_SECRET,
  {
    expiresIn: &quot;7d&quot;,
  }
);
</code></pre>
<p>Ce JWT est ensuite renvoyé au navigateur, généralement <strong>dans un cookie sécurisé ou dans la réponse de votre API.</strong></p>
<blockquote>
<p>Le token GitHub sert uniquement à communiquer avec GitHub. Une fois l'utilisateur authentifié, c'est votre propre JWT qui permettra de l'identifier sur votre application.</p>
</blockquote>
<h3>Le fonctionnement résumé</h3>
<p>Même si OAuth peut sembler impressionnant au premier abord, le mécanisme est finalement assez simple :</p>
<ol>
<li>Votre application redirige l'utilisateur vers GitHub.</li>
<li>GitHub vérifie son identité et renvoie un code temporaire.</li>
<li>Votre serveur échange ce code contre un token, récupère l'adresse email de l'utilisateur, puis génère son propre JWT.</li>
<li>Au final, GitHub ne fait qu'une seule chose : <strong>confirmer l'identité de l'utilisateur</strong>.</li>
</ol>
<blockquote>
<p>Toute la gestion des comptes, des permissions et de l'authentification au sein de votre application reste sous votre responsabilité.</p>
</blockquote>
]]></content:encoded>
            <media:content url="https://code-garage-strapi-bucket-production.cellar-c2.services.clever-cloud.com/Chat_GPT_Image_13_juil_131b9e40cd.jpg" medium="image"/>
        </item>
        <item>
            <title><![CDATA[Créer des exécutables avec Node 25+]]></title>
            <description><![CDATA[Découvrez la nouvelle fonctionnalité de Node.js qui permet de créer des exécutables directement, sans utiliser de modules externes comme pkg ou nexe.]]></description>
            <link>https://code-garage.com/blog/creer-des-executables-avec-nodejs</link>
            <guid isPermaLink="true">https://code-garage.com/blog/creer-des-executables-avec-nodejs</guid>
            <category><![CDATA[NodeJS]]></category>
            <dc:creator><![CDATA[NicolasBrondinBernard]]></dc:creator>
            <pubDate>Fri, 10 Jul 2026 12:15:42 GMT</pubDate>
            <content:encoded><![CDATA[<p>Pendant longtemps, <a href="https://code-garage.com/courses/decouvrir-nodejs/creer-un-executable">créer un exécutable à partir d'une application</a> Node.js nécessitait un outil externe. Les plus connus étaient <code>pkg</code> ou <code>nexe</code>, capables de transformer une application JavaScript en un fichier <code>.exe</code> sous Windows, ou en un binaire exécutable sous Linux et macOS.</p>
<blockquote>
<p>L'objectif était simple : distribuer une application <strong>sans demander à l'utilisateur d'installer Node.js</strong>.</p>
</blockquote>
<p>Depuis sa version 18.16 (LTS), Node.js propose les <strong>Single Executable Applications (SEA)</strong>, un mécanisme permettant d'intégrer une application directement dans un exécutable Node.</p>
<p>Cette fonctionnalité a récemment franchi une nouvelle étape (depuis la 25.5) avec l'arrivée de la commande <code>--build-sea</code>, qui permet de générer un exécutable directement depuis la ligne de commande, sans passer par des outils externes.</p>
<blockquote>
<p>Autrement dit : <a href="https://nodejs.org/api/single-executable-applications.html">Node.js</a> sait désormais produire lui-même un exécutable.</p>
</blockquote>
<h2>Comment faire</h2>
<p>Il suffit de fournir un fichier de configuration JSON (ici <code>sea-config.json</code>) décrivant votre application.</p>
<p>Par exemple :</p>
<pre><code class="language-json">{
  &quot;main&quot;: &quot;./dist/index.js&quot;,
  &quot;output&quot;: &quot;./mon-application&quot;
}
</code></pre>
<p>Puis de lancer :</p>
<pre><code class="language-bash">node --build-sea sea-config.json
</code></pre>
<blockquote>
<p>Node.js génère alors un exécutable contenant à la fois le runtime et votre application.</p>
</blockquote>
<h2>Pourquoi est-ce une bonne nouvelle ?</h2>
<p><strong>Le principal avantage est la simplicité.</strong> Jusqu'à présent, il fallait souvent installer un outil supplémentaire, vérifier sa compatibilité avec votre version de Node.js et espérer qu'il continue d'être maintenu.</p>
<blockquote>
<p>Avec une solution officielle, tout cela disparaît.</p>
</blockquote>
<p>Vous bénéficiez d'une fonctionnalité développée directement par l'équipe Node.js, qui évoluera en même temps que le runtime.</p>
<h3>Une fonctionnalité encore jeune</h3>
<p>Il faut cependant garder une chose en tête : Même si cette fonctionnalité devient de plus en plus mature, elle reste marquée comme <strong>en développement actif</strong> dans la documentation officielle de Node.js.</p>
<blockquote>
<p>Certaines limitations existent encore.</p>
</blockquote>
<p>Par exemple, les premières versions de SEA ne supportaient que les applications CommonJS. Les versions récentes prennent désormais également en charge les modules ECMAScript (ESM), mais toutes les fonctionnalités d'un projet Node ne sont pas forcément compatibles selon votre configuration.</p>
<p>Si votre application dépend d'outils comme Puppeteer, <strong>de modules natifs ou de ressources externes, quelques ajustements peuvent encore être nécessaires.</strong></p>
<h3>Faut-il abandonner pkg ?</h3>
<p>Pour un nouveau projet, la réponse est probablement oui.</p>
<p>La fonctionnalité native de Node.js a vocation à remplacer progressivement les outils historiques de packaging. Elle est mieux intégrée au runtime et ne dépend plus d'un projet tiers qui pourrait cesser d'être maintenu.</p>
<blockquote>
<p>En revanche, si vous possédez déjà une chaîne de build basée sur <code>pkg</code> et qu'elle fonctionne parfaitement, il n'y a pas forcément d'urgence à la modifier.</p>
</blockquote>
<h3>À noter</h3>
<p>Node ne &quot;compile&quot; pas votre code JavaScript vers du code machine. Il <strong>embarque votre application dans un exécutable Node existant</strong>, qui est lui-même spécifique à un système d'exploitation et à une architecture (Windows, Linux, macOS, x64, ARM64, etc.).</p>
]]></content:encoded>
            <media:content url="https://code-garage-strapi-bucket-production.cellar-c2.services.clever-cloud.com/Chat_GPT_Image_10_juil_eb34c2da9e.jpg" medium="image"/>
        </item>
        <item>
            <title><![CDATA[Générer un App Password pour utiliser Gmail en IMAP/SMTP ]]></title>
            <description><![CDATA[Découvrez comment utiliser une adresse Gmail avec IMAP et SMTP grâce aux App Passwords de Google. Une solution simple pour connecter Gmail à vos applications, serveurs et outils d'envoi d'emails.]]></description>
            <link>https://code-garage.com/blog/generer-un-app-password-pour-utiliser-gmail-en-imap-smtp</link>
            <guid isPermaLink="true">https://code-garage.com/blog/generer-un-app-password-pour-utiliser-gmail-en-imap-smtp</guid>
            <category><![CDATA[Email]]></category>
            <category><![CDATA[Google]]></category>
            <dc:creator><![CDATA[NicolasBrondinBernard]]></dc:creator>
            <pubDate>Tue, 23 Jun 2026 08:29:07 GMT</pubDate>
            <content:encoded><![CDATA[<p>Lorsque vous développez <strong>une application qui doit envoyer ou recevoir des emails</strong>, une idée assez naturelle consiste à utiliser directement une adresse Gmail pour faire des tests.</p>
<p>Pendant longtemps, il suffisait d'utiliser son adresse email et son mot de passe. <strong>Mais aujourd'hui, cette méthode ne fonctionne plus.</strong></p>
<blockquote>
<p>Google <strong>bloque désormais l'accès aux comptes Gmail</strong> depuis la plupart des applications utilisant simplement un mot de passe classique.</p>
</blockquote>
<p>Heureusement, Google propose une solution : les <strong>App Passwords</strong>, ou mots de passe d'application.</p>
<h2>Qu'est-ce qu'un App Password ?</h2>
<p>Un App Password est <strong>un mot de passe généré par Google</strong> spécialement pour une application.</p>
<p>Contrairement à votre mot de passe principal :</p>
<ul>
<li>il est limité à un <strong>usage précis</strong></li>
<li>il peut être <strong>révoqué à tout moment</strong></li>
<li>il n'autorise <strong>pas l'accès complet</strong> à votre compte Google</li>
</ul>
<blockquote>
<p>L'idée est de permettre à une application de se connecter à Gmail sans lui donner votre véritable mot de passe.</p>
</blockquote>
<h2>Générer un App Password</h2>
<h3>Activer l'authentification à deux facteurs</h3>
<p>Avant de pouvoir créer un App Password, vous devez activer la validation en deux étapes sur votre compte Google.</p>
<p>Rendez-vous dans les paramètres de sécurité de votre compte Google puis <strong>activez l'authentification à deux facteurs.</strong></p>
<blockquote>
<p>Sans cette étape, le menu des App Passwords <strong>n'apparaîtra pas.</strong></p>
</blockquote>
<h3>Créer un mot de passe</h3>
<p>Une fois l'authentification à deux facteurs activée :</p>
<ul>
<li>ouvrez les <strong>paramètres de sécurité Google</strong></li>
<li>recherchez la section &quot;<strong>Mots de passe des applications</strong>&quot;</li>
<li>créez un nouveau mot de passe</li>
<li>choisissez un nom comme &quot;Serveur SMTP&quot; ou &quot;Application NodeJS&quot;</li>
</ul>
<blockquote>
<p>Vous pouvez aussi cliquer sur le <strong>lien direct</strong> : https://myaccount.google.com/apppasswords</p>
</blockquote>
<p>Google génère alors une chaîne ressemblant à ceci :</p>
<pre><code>abcd efgh ijkl mnop
</code></pre>
<blockquote>
<p>C'est ce mot de passe qu'il faudra utiliser dans votre application.</p>
</blockquote>
<h2>Utiliser votre App Password</h2>
<h3>Configuration SMTP</h3>
<p>Pour envoyer des emails avec Gmail, utilisez les paramètres suivants :</p>
<pre><code>Serveur SMTP : smtp.gmail.com
Port : 587
Sécurité : TLS / STARTTLS
Utilisateur : &lt;votre-adresse@gmail.com&gt;
Mot de passe : &lt;votre_app_password&gt;
</code></pre>
<h3>Configuration IMAP</h3>
<p>Si vous souhaitez recevoir ou lire des emails, vous devrez utiliser IMAP.</p>
<p>Les paramètres sont les suivants :</p>
<pre><code>Serveur IMAP : imap.gmail.com
Port : 993
Sécurité : SSL/TLS
Utilisateur : votre-adresse@gmail.com
Mot de passe : &lt;votre_app_password&gt;
</code></pre>
<h2>Les limites de Gmail</h2>
<p>Même si Gmail fonctionne très bien pour des tests ou de petits projets, il ne remplace pas un véritable service d'envoi transactionnel.</p>
<p>Google applique notamment :</p>
<ul>
<li>des limites d'envoi quotidiennes</li>
<li>des contrôles anti-spam</li>
<li>des restrictions sur certains usages automatisés</li>
</ul>
<blockquote>
<p>Pour un projet professionnel ou une application à fort volume, des solutions comme Brevo (français), Resend, Mailgun ou SendGrid seront généralement plus adaptées.</p>
</blockquote>
]]></content:encoded>
            <media:content url="https://code-garage-strapi-bucket-production.cellar-c2.services.clever-cloud.com/Chat_GPT_Image_22_juin_2026_14_07_22_b54d98bf3f.jpg" medium="image"/>
        </item>
        <item>
            <title><![CDATA[Interagir avec une boîte mail en Node.js avec ImapFlow et MailParser]]></title>
            <description><![CDATA[Découvrez comment lire et traiter les emails d’une boîte mail en Node.js avec ImapFlow et MailParser, en utilisant IMAP pour récupérer les messages.]]></description>
            <link>https://code-garage.com/blog/interagir-avec-une boite-mail-en-nodejs-avec-imapflow-et-mailparser</link>
            <guid isPermaLink="true">https://code-garage.com/blog/interagir-avec-une boite-mail-en-nodejs-avec-imapflow-et-mailparser</guid>
            <category><![CDATA[NodeJS]]></category>
            <category><![CDATA[Email]]></category>
            <category><![CDATA[IMAP]]></category>
            <dc:creator><![CDATA[NicolasBrondinBernard]]></dc:creator>
            <pubDate>Mon, 15 Jun 2026 07:46:04 GMT</pubDate>
            <content:encoded><![CDATA[<p>Envoyer des emails avec Node.js, c’est très simple avec des outils <strong>comme Nodemailer !</strong></p>
<blockquote>
<p><a href="https://code-garage.com/blog/tutoriel-comment-bien-envoyer-vos-emails-en-html-css-avec-nodejs">Notre article dédié</a> pour l’envoi d’email en Node.js</p>
</blockquote>
<p>Mais il existe aussi beaucoup de cas où l’on veut faire l’inverse : <strong>lire les emails reçus</strong>.</p>
<p>Par exemple, pour <strong>traiter automatiquement des demandes entrantes, récupérer des pièces jointes</strong>, analyser des réponses clients, ou déclencher une action lorsqu’un message arrive dans une boîte spécifique.</p>
<p>Pour cela, on utilise généralement un protocol dédié : <strong>IMAP (Internet Message Access Protocol).</strong></p>
<blockquote>
<p>IMAP permet à une application de se connecter à une boîte mail pour <strong>lire, parcourir et manipuler les messages.</strong></p>
</blockquote>
<p>En Node.js, deux bibliothèques sont particulièrement pratiques pour ce besoin : <code>ImapFlow</code> et <code>MailParser</code>.</p>
<p>ImapFlow est un client IMAP moderne pour Node.js, avec une API basée sur les Promises et <code>async/await</code> (<a href="https://imapflow.com/docs/">documentation officielle</a>).</p>
<p>MailParser, de son côté, permet de transformer un email brut en objet JavaScript exploitable. Sa fonction <code>simpleParser</code> est pratique pour les cas simples, tandis que la classe <code>MailParser</code> permet de traiter les gros messages sous forme de streams (<a href="https://nodemailer.com/extras/mailparser">documentation officielle</a>).</p>
<h2>Fonctionnement</h2>
<h3>Installer les dépendances</h3>
<p>On commence par installer les deux packages :</p>
<pre><code class="language-bash">npm install imapflow mailparser
</code></pre>
<p>Si vous utilisez TypeScript, ImapFlow fournit déjà ses propres types. Pour MailParser, vous pouvez ajouter :</p>
<pre><code class="language-bash">npm install -D @types/mailparser
</code></pre>
<h3>Se connecter à une boîte mail</h3>
<p>Voici un exemple avec Gmail, mais le principe est le même avec n’importe quel serveur IMAP.</p>
<pre><code class="language-jsx">import { ImapFlow } from &quot;imapflow&quot;;

const client = new ImapFlow({
  host: &quot;imap.gmail.com&quot;,
  port: 993,
  secure: true,
  auth: {
    user: &quot;votre-adresse@gmail.com&quot;,
    pass: &quot;votre-app-password&quot;,
  },
});

await client.connect();
</code></pre>
<p>Pour Gmail, il ne faut pas utiliser votre mot de passe principal.</p>
<blockquote>
<p>Il faut générer un App Password depuis votre compte Google, puis l’utiliser comme mot de passe IMAP.</p>
</blockquote>
<h3>Lire les derniers emails</h3>
<p>Une fois connecté, il faut ouvrir une boîte. La plus courante est <code>INBOX</code>.</p>
<pre><code class="language-jsx">const lock = await client.getMailboxLock(&quot;INBOX&quot;);

try {
  for await (const message of client.fetch(&quot;1:*&quot;, {
    envelope: true,
    source: true,
  })) {
    console.log(message.envelope.subject);
  }
} finally {
  lock.release();
}
</code></pre>
<p>Le <code>lock</code> évite que plusieurs opérations entrent en conflit sur la même boîte.</p>
<blockquote>
<p>C’est une bonne habitude avec ImapFlow : on verrouille, on travaille, puis on libère.</p>
</blockquote>
<p>Ici, <code>source: true</code> permet de récupérer l’email brut. C’est ce contenu que nous allons ensuite donner à MailParser.</p>
<h3>Parser un email avec MailParser</h3>
<p>Un email n’est pas un simple texte. Il peut contenir du HTML, du texte brut, des pièces jointes, des encodages différents, des headers, des destinataires, etc.</p>
<p>MailParser s’occupe de transformer tout cela en objet plus facile à manipuler :</p>
<pre><code class="language-jsx">import { simpleParser } from &quot;mailparser&quot;;

for await (const message of client.fetch(&quot;1:*&quot;, {
  envelope: true,
  source: true,
})) {
  const parsed = await simpleParser(message.source);

  console.log({
    subject: parsed.subject,
    from: parsed.from?.text,
    text: parsed.text,
    html: parsed.html,
  });
}
</code></pre>
<blockquote>
<p><code>simpleParser</code> charge le message en mémoire.</p>
</blockquote>
<p>C’est très pratique pour démarrer, mais si vous traitez de gros emails ou beaucoup de pièces jointes, il faudra plutôt utiliser l’API en streaming de MailParser.</p>
<h3>Lire uniquement les emails non lus</h3>
<p>Dans la vraie vie, vous ne voulez pas relire toute la boîte à chaque exécution.</p>
<p>Vous pouvez chercher uniquement les emails non lus :</p>
<pre><code class="language-jsx">for await (const message of client.fetch(
  { seen: false },
  { envelope: true, source: true }
)) {
  const parsed = await simpleParser(message.source);

  console.log(parsed.subject);
}
</code></pre>
<p>Ensuite, vous pouvez marquer le message comme lu :</p>
<pre><code class="language-jsx">await client.messageFlagsAdd(message.uid, [&quot;\\Seen&quot;], { uid: true });
</code></pre>
<blockquote>
<p>Cela permet de construire facilement un petit worker qui <strong>traite seulement les nouveaux emails.</strong></p>
</blockquote>
<h3>Exemple complet</h3>
<pre><code class="language-jsx">import { ImapFlow } from &quot;imapflow&quot;;
import { simpleParser } from &quot;mailparser&quot;;

const client = new ImapFlow({
  host: &quot;imap.gmail.com&quot;,
  port: 993,
  secure: true,
  auth: {
    user: process.env.MAIL_USER,
    pass: process.env.MAIL_PASSWORD,
  },
});

await client.connect();

const lock = await client.getMailboxLock(&quot;INBOX&quot;);

try {
  for await (const message of client.fetch(
    { seen: false },
    { uid: true, source: true }
  )) {
    const parsed = await simpleParser(message.source);

    console.log(&quot;Sujet :&quot;, parsed.subject);
    console.log(&quot;De :&quot;, parsed.from?.text);
    console.log(&quot;Texte :&quot;, parsed.text);

    await client.messageFlagsAdd(message.uid, [&quot;\\Seen&quot;], { uid: true });
  }
} finally {
  lock.release();
  await client.logout();
}
</code></pre>
]]></content:encoded>
            <media:content url="https://code-garage-strapi-bucket-production.cellar-c2.services.clever-cloud.com/Chat_GPT_Image_15_juin_2026_08_58_04_f06146f568.jpg" medium="image"/>
        </item>
        <item>
            <title><![CDATA[Découvrir VueUse : la boîte à outils indispensable pour Vue.js]]></title>
            <description><![CDATA[Découvrez VueUse, une collection de composables ultra pratiques pour Vue.js. Géolocalisation, presse-papiers, gamepads, état du réseau… gagnez du temps avec useClipboard, useGeolocation, useNetwork et useGamepad.]]></description>
            <link>https://code-garage.com/blog/decouvrir-vueuse-la-boite-a-outils-indispensable-pour-vuejs</link>
            <guid isPermaLink="true">https://code-garage.com/blog/decouvrir-vueuse-la-boite-a-outils-indispensable-pour-vuejs</guid>
            <category><![CDATA[VueJS]]></category>
            <dc:creator><![CDATA[NicolasBrondinBernard]]></dc:creator>
            <pubDate>Tue, 26 May 2026 15:15:39 GMT</pubDate>
            <content:encoded><![CDATA[<p>Quand on développe une application Vue, on finit souvent par réécrire les mêmes choses :</p>
<ul>
<li>écouter des évènements du navigateur</li>
<li>gérer des états réactifs</li>
<li>accéder aux APIs Web</li>
<li>nettoyer des listeners</li>
</ul>
<blockquote>
<p>C’est précisément le problème que résout VueUse.</p>
</blockquote>
<h2>Une bibliothèque de composables</h2>
<p>VueUse est une immense bibliothèque de composables prêts à l’emploi pour Vue.js.</p>
<p>Elle propose des centaines d’utilitaires pour :</p>
<ul>
<li>le navigateur</li>
<li>les animations</li>
<li>les capteurs</li>
<li>les raccourcis clavier</li>
<li>le stockage local</li>
<li>les APIs Web modernes</li>
</ul>
<p>Et surtout tous les utilitaires sont pensés pour fonctionner naturellement avec la réactivité de Vue.</p>
<p>L’installation est très simple :</p>
<pre><code class="language-bash">npm install @vueuse/core
</code></pre>
<blockquote>
<p>Ensuite, vous pouvez importer uniquement les composables dont vous avez besoin.</p>
</blockquote>
<h3>Copier du texte avec useClipboard</h3>
<p>L’API du presse-papiers du navigateur peut être un peu pénible à utiliser directement.</p>
<p>VueUse simplifie énormément cela avec <code>useClipboard</code>.</p>
<pre><code class="language-tsx">import { useClipboard } from &quot;@vueuse/core&quot;

const { copy, copied } = useClipboard()

const copyCode = async () =&gt; {
  await copy(&quot;Hello world&quot;)
}
</code></pre>
<p>Le booléen <code>copied</code> devient automatiquement <code>true</code> pendant quelques secondes après la copie.</p>
<p>Parfait pour afficher un message :</p>
<pre><code class="language-html">&lt;p v-if=&quot;copied&quot;&gt;Texte copié !&lt;/p&gt;
</code></pre>
<p>C’est idéal pour :</p>
<ul>
<li>des boutons “Copier”</li>
<li>des snippets de code</li>
<li>des liens de partage</li>
<li>des tokens API</li>
</ul>
<h3>Récupérer la position GPS avec useGeolocation</h3>
<p>VueUse propose aussi un accès très simple à la géolocalisation du navigateur.</p>
<pre><code class="language-tsx">import { useGeolocation } from &quot;@vueuse/core&quot;

const { coords, locatedAt, error } = useGeolocation()
</code></pre>
<p>Les coordonnées deviennent automatiquement réactives :</p>
<pre><code class="language-html">&lt;p&gt;Latitude : {{ coords.latitude }}&lt;/p&gt;
&lt;p&gt;Longitude : {{ coords.longitude }}&lt;/p&gt;
</code></pre>
<p>C’est particulièrement utile pour :</p>
<ul>
<li>une carte interactive</li>
<li>une application météo</li>
<li>du contenu localisé</li>
<li>du suivi de position</li>
</ul>
<p>Et contrairement à une implémentation manuelle, VueUse gère déjà :</p>
<ul>
<li>les listeners</li>
<li>la réactivité</li>
<li>le nettoyage automatique</li>
</ul>
<h3>Détecter l’état du réseau avec useNetwork</h3>
<p>Savoir si un utilisateur est hors ligne peut améliorer énormément l’expérience utilisateur.</p>
<p>Avec <code>useNetwork</code> :</p>
<pre><code class="language-tsx">import { useNetwork } from &quot;@vueuse/core&quot;

const { isOnline, downlink, effectiveType } = useNetwork()
</code></pre>
<p>Vous pouvez facilement afficher un message :</p>
<pre><code class="language-html">&lt;p v-if=&quot;!isOnline&quot;&gt;
  Vous êtes actuellement hors ligne.
&lt;/p&gt;
</code></pre>
<p>Mais aussi adapter l’application selon la qualité du réseau.</p>
<p>Par exemple :</p>
<ul>
<li>réduire la qualité des images</li>
<li>désactiver certaines animations</li>
<li>éviter des requêtes lourdes</li>
</ul>
<h3>Utiliser une manette avec useGamepad</h3>
<p>C’est probablement l’un des composables les plus amusants.</p>
<p><code>useGamepad</code> permet d’accéder aux manettes connectées au navigateur.</p>
<pre><code class="language-tsx">import { useGamepad } from &quot;@vueuse/core&quot;

const { gamepads } = useGamepad()
</code></pre>
<p>Vous pouvez ensuite lire les boutons et axes :</p>
<pre><code class="language-html">&lt;pre&gt;{{ gamepads }}&lt;/pre&gt;
</code></pre>
<p>Cela ouvre la porte à énormément de projets :</p>
<ul>
<li>mini jeux Vue.js</li>
<li>interfaces interactives</li>
<li>bornes tactiles</li>
<li>contrôles alternatifs</li>
</ul>
<blockquote>
<p>Et tout cela avec très peu de code.</p>
</blockquote>
]]></content:encoded>
            <media:content url="https://code-garage-strapi-bucket-production.cellar-c2.services.clever-cloud.com/Chat_GPT_Image_22_mai_2026_11_47_28_6b049842fe.jpg" medium="image"/>
        </item>
        <item>
            <title><![CDATA[Utiliser npm link pour tester un module localement]]></title>
            <description><![CDATA[Découvrez comment utiliser la commande npm link pour développer et tester un module NPM localement sans avoir à le publier à chaque modification.]]></description>
            <link>https://code-garage.com/blog/utiliser-npm-link-pour-tester-un-module-localement</link>
            <guid isPermaLink="true">https://code-garage.com/blog/utiliser-npm-link-pour-tester-un-module-localement</guid>
            <category><![CDATA[NodeJS]]></category>
            <category><![CDATA[NPM]]></category>
            <dc:creator><![CDATA[NicolasBrondinBernard]]></dc:creator>
            <pubDate>Sun, 17 May 2026 16:18:20 GMT</pubDate>
            <content:encoded><![CDATA[<p>Quand on <strong>développe un package NPM</strong>, il y a un problème très vite frustrant :</p>
<p>À chaque modification du module, il faudrait normalement :</p>
<ul>
<li>publier une nouvelle version</li>
<li>réinstaller le package dans le projet de test</li>
<li>relancer l’application</li>
</ul>
<blockquote>
<p>Heureusement, <code>npm link</code> existe justement pour éviter ça.</p>
</blockquote>
<h2>Fonctionnement</h2>
<p>Cette commande permet de <strong>créer un lien symbolique</strong> entre un package local et un autre projet.</p>
<blockquote>
<p>Autrement dit : votre projet utilise <strong>directement le code source local du module</strong>, comme s’il avait été installé depuis NPM.</p>
</blockquote>
<p>Le fonctionnement se fait en deux étapes. D’abord, dans le dossier du <strong>paquet NPM</strong> :</p>
<pre><code class="language-bash">npm link
</code></pre>
<blockquote>
<p>Cette commande enregistre le package globalement sur votre machine.</p>
</blockquote>
<p>Ensuite, dans le projet qui doit <strong>utiliser ce package</strong> :</p>
<pre><code class="language-bash">npm link nom-du-package
</code></pre>
<blockquote>
<p>À partir de ce moment-là, le dossier <code>node_modules</code> du projet pointera directement vers votre module local.</p>
</blockquote>
<h3>Un lien symbolique</h3>
<p>Le gros avantage, c’est que les modifications deviennent quasiment instantanées. Vous changez du code dans votre package… et <strong>votre projet de test utilise immédiatement la nouvelle version.</strong></p>
<p>Plus besoin de publier une version <code>0.0.1-dev-test-42</code>.</p>
<blockquote>
<p>Sous le capot, <code>npm link</code> utilise des liens symboliques (<code>symlink</code>) du système d’exploitation.</p>
</blockquote>
<h3>Un exemple concret</h3>
<p>Voici un exemple pour bien comprendre <strong>la marche à suivre</strong>. Vous avez deux projets :</p>
<pre><code>mon-package/
mon-app/
</code></pre>
<p>!!! well
Dans <code>mon-package</code> :</p>
<pre><code class="language-bash">npm link
</code></pre>
<p>!!!
!!! well
Puis dans <code>mon-app</code> :</p>
<pre><code class="language-bash">npm link mon-package
</code></pre>
<p>!!!</p>
<blockquote>
<p>Et voilà. Votre application utilise maintenant directement <strong>la version locale du package.</strong></p>
</blockquote>
]]></content:encoded>
            <media:content url="https://code-garage-strapi-bucket-production.cellar-c2.services.clever-cloud.com/bas_van_den_eijkhof_a_Jf_Ou_We_Nzko_unsplash_fa60b1506d.jpg" medium="image"/>
        </item>
        <item>
            <title><![CDATA[Qu’est-ce qu’un ADR (Architecture Decision Record) ?]]></title>
            <description><![CDATA[Découvrez ce qu’est un ADR (Architecture Decision Record), pourquoi il est utile dans un projet logiciel et comment documenter vos décisions techniques simplement.]]></description>
            <link>https://code-garage.com/blog/qu-est-ce-qu-un-adr-architecture-decision-record</link>
            <guid isPermaLink="true">https://code-garage.com/blog/qu-est-ce-qu-un-adr-architecture-decision-record</guid>
            <category><![CDATA[Documentation]]></category>
            <category><![CDATA[Architecture Logicielle]]></category>
            <dc:creator><![CDATA[NicolasBrondinBernard]]></dc:creator>
            <pubDate>Thu, 07 May 2026 07:37:03 GMT</pubDate>
            <content:encoded><![CDATA[<p>Dans beaucoup de projets, certaines décisions techniques <strong>finissent par devenir… mystérieuses.</strong></p>
<ul>
<li>Pourquoi ce framework a été choisi ?</li>
<li>Pourquoi ce calcul fonctionne de cette manière ?</li>
<li>Pourquoi utilise-t-on Redis ici, mais pas ailleurs ?</li>
</ul>
<p>Le problème, c’est qu’avec le temps, les développeurs changent, les discussions Slack disparaissent, et <strong>les décisions prises plusieurs mois auparavant deviennent difficiles à comprendre.</strong></p>
<blockquote>
<p>C’est précisément le rôle des ADR, pour <strong>Archicture Decision Record.</strong></p>
</blockquote>
<h2><strong>Architecture Decision Record</strong></h2>
<p>Un ADR est un document très simple qui sert à conserver <strong>une trace d’une décision technique</strong> importante dans un projet.</p>
<p>L’idée n’est pas de rédiger une énorme documentation, au contraire :</p>
<blockquote>
<p>Un ADR est généralement <strong>court, simple et centré sur une seule décision.</strong></p>
</blockquote>
<p>L’objectif est surtout de répondre à une question essentielle : <strong>Pourquoi cette décision a-t-elle été prise ?</strong></p>
<p>Un ADR contient souvent :</p>
<ul>
<li>le contexte ⇒ explique le problème rencontré.</li>
<li>la décision ⇒ décrit le choix effectué.</li>
<li>les conséquences ⇒ détaillent les avantages, limites ou compromis associés.</li>
</ul>
<p>Voici un exemple très simplifié :</p>
<pre><code class="language-markdown"># ADR-001 : Utilisation de PostgreSQL

## Context
Le projet nécessite des relations complexes entre les données.

## Decision
Utiliser PostgreSQL comme base principale.

## Consequences
- SQL puissant
- bonnes performances relationnelles
- infrastructure plus lourde qu’une base NoSQL
</code></pre>
<blockquote>
<p>Ce type de document peut sembler anodin… mais il devient extrêmement précieux avec le temps.</p>
</blockquote>
<h2>Pourquoi mettre en place des ADR ?</h2>
<p>Sans ADR, beaucoup de projets finissent <strong>avec des décisions “historiques”</strong> que plus personne ne comprend vraiment.</p>
<p>Et cela crée souvent des problèmes :</p>
<ul>
<li>duplication de solutions</li>
<li>remise en question permanente</li>
<li>peur de modifier certaines parties du projet</li>
<li>onboarding plus difficile</li>
</ul>
<blockquote>
<p>Et surtout cela rend encore plus <strong>critique le fameux “<a href="https://code-garage.com/blog/qu-est-ce-que-le-bus-factor-gestion-de-projet/">bus factor</a>”</strong></p>
</blockquote>
<p>Mettre en place des ADR est particulièrement utile dans :</p>
<ul>
<li>les projets longs</li>
<li>les équipes qui grandissent</li>
<li>les architectures complexes</li>
<li>les projets open source</li>
</ul>
<blockquote>
<p>La bonne nouvelle, c’est qu’<strong>on peut commencer, dès aujourd’hui, sans aucun outils</strong></p>
</blockquote>
<p>Beaucoup d’équipes stockent simplement leurs ADR dans un dossier :</p>
<pre><code>/docs/adr
</code></pre>
<p>Ou directement :</p>
<pre><code>/adr
</code></pre>
<blockquote>
<p>Le plus important n’est pas le format, mais de <strong>commencer à documenter le plus tôt possible.</strong></p>
</blockquote>
<p>Parce qu’en architecture logicielle, le problème n’est pas seulement de prendre de bonnes décisions. <strong>C’est aussi de comprendre, plusieurs années plus tard, pourquoi elles ont été prises.</strong></p>
]]></content:encoded>
            <media:content url="https://code-garage-strapi-bucket-production.cellar-c2.services.clever-cloud.com/bruno_fernandes_a_Izs0_Pp_VXY_unsplash_25dea52ff8.jpg" medium="image"/>
        </item>
        <item>
            <title><![CDATA[La différence entre RUN et CMD avec Docker]]></title>
            <description><![CDATA[Découvrez la différence entre RUN et CMD dans Docker, leur rôle dans un Dockerfile et comment éviter les erreurs courantes.]]></description>
            <link>https://code-garage.com/blog/la-difference-entre-run-et-cmd-avec-docker</link>
            <guid isPermaLink="true">https://code-garage.com/blog/la-difference-entre-run-et-cmd-avec-docker</guid>
            <category><![CDATA[Docker]]></category>
            <dc:creator><![CDATA[NicolasBrondinBernard]]></dc:creator>
            <pubDate>Tue, 31 Mar 2026 14:43:51 GMT</pubDate>
            <content:encoded><![CDATA[<p>Quand vous écrivez votre premier Dockerfile, les instructions <code>RUN</code> et <code>CMD</code> qui prêtent souvent à confusion.</p>
<blockquote>
<p>Elles peuvent sembler similaires… mais elles n’ont <strong>absolument pas le même rôle</strong>.</p>
</blockquote>
<p>À noter que <strong>si vous ne connaissez pas Docker</strong>, cet article ne vous sera pas très utile, mais vous pouvez toujours aller écouter notre introduction à Docker dans <a href="https://code-garage.com/podcast/classic/episode-145">un épisode dédié du podcast</a> !</p>
<h2>La commande RUN</h2>
<p><code>RUN</code> est utilisé <strong>lors de la construction de l’image Docker</strong>.</p>
<p>Par exemple :</p>
<pre><code class="language-docker">RUN apt-get update &amp;&amp; apt-get install -y curl
</code></pre>
<p>Cette commande est exécutée :</p>
<ul>
<li>pendant le <code>docker build</code></li>
<li>pour modifier l’image</li>
</ul>
<blockquote>
<p><code>RUN</code> sert à <strong>préparer l’image.</strong></p>
</blockquote>
<p>Chaque instruction <code>RUN</code> crée une nouvelle couche dans l’image Docker.</p>
<p>Typiquement, vous utilisez <code>RUN</code> pour :</p>
<ul>
<li>installer des dépendances</li>
<li>copier ou générer des fichiers</li>
<li>configurer l’environnement</li>
</ul>
<h2>La commande CMD</h2>
<p><code>CMD</code> est utilisée <strong>lors du lancement du conteneur</strong>.</p>
<p>Par exemple :</p>
<pre><code class="language-docker">CMD [&quot;node&quot;, &quot;server.js&quot;]
</code></pre>
<p>Cette commande est exécutée :</p>
<ul>
<li>quand vous faites <code>docker run</code></li>
<li>au démarrage du conteneur</li>
</ul>
<blockquote>
<p><code>CMD</code> sert à dire : “voilà ce que fait ce conteneur quand il démarre”.</p>
</blockquote>
<h2>La différence clé</h2>
<p>La différence principale tient en une phrase :  <code>RUN</code> s’exécute <strong>pendant le build</strong> tandis que <code>CMD</code> s’exécute <strong>au runtime</strong>.</p>
<p>Autrement dit :</p>
<ul>
<li><code>RUN</code> modifie l’image</li>
<li><code>CMD</code> définit le comportement du conteneur</li>
</ul>
<h3>Un exemple concret</h3>
<p>Prenons un Dockerfile simple :</p>
<pre><code class="language-docker">FROM node:18
WORKDIR /app
COPY package.json .
RUN npm install
COPY . .

CMD [&quot;node&quot;, &quot;index.js&quot;]
</code></pre>
<p>Ce qu’il se passe :</p>
<ol>
<li><code>RUN npm install</code> installe les dépendances <strong>dans l’image</strong></li>
<li><code>CMD [&quot;node&quot;, &quot;index.js&quot;]</code> lance l’application <strong>au démarrage</strong></li>
</ol>
<blockquote>
<p>Sans <code>CMD</code>, le conteneur ne ferait rien.</p>
</blockquote>
<h2>Pour aller plus loin</h2>
<h3>CMD peut être remplacé</h3>
<p>Par exemple :</p>
<pre><code class="language-bash">docker run mon-image echo &quot;Hello&quot;
</code></pre>
<p>Ici :</p>
<ul>
<li><code>CMD</code> est ignoré</li>
<li>la commande <code>echo &quot;Hello&quot;</code> est exécutée</li>
</ul>
<blockquote>
<p><code>CMD</code> est une valeur par défaut.</p>
</blockquote>
<h3>Le système de couches (layers)</h3>
<p>Chaque <code>RUN</code> ajoute une couche à votre image.</p>
<p>Par exemple :</p>
<pre><code class="language-docker">RUN apt-get update
RUN apt-get install -y curl
</code></pre>
<blockquote>
<p>Crée deux couches.</p>
</blockquote>
<p>Les différentes couches sont utilisées par Docker pour optimiser la mémoire utilisée par les images, car <strong>les couches similaires sont partagées entre les différents conteneurs !</strong></p>
<h2>Résumé de l'article</h2>
<p><code>RUN</code> et <code>CMD</code> sont complémentaires.</p>
<ul>
<li>utilisez <code>RUN</code> pour construire votre environnement (exécuté pendant le build)</li>
<li>utilisez <code>CMD</code> pour lancer votre application (exécuté au runtime)</li>
</ul>
<blockquote>
<p>Si vous les confondez, votre conteneur ne fera probablement pas ce que vous attendez.</p>
</blockquote>
]]></content:encoded>
            <media:content url="https://code-garage-strapi-bucket-production.cellar-c2.services.clever-cloud.com/nicolasbrondinbernard_pixel_art_scene_of_a_bakery_kitchen_where_3880f6c2_e944_4407_b1c9_8894f91a32c5_9435666357.jpg" medium="image"/>
        </item>
        <item>
            <title><![CDATA[Git : comment supprimer tous les fichiers en dehors de l’historique]]></title>
            <description><![CDATA[Découvrez comment supprimer les fichiers non suivis par Git après un git reset, avec git clean, les bonnes options et les précautions à connaître.]]></description>
            <link>https://code-garage.com/blog/git-comment-supprimer-tous-les-fichiers-en-dehors-de-l-historique</link>
            <guid isPermaLink="true">https://code-garage.com/blog/git-comment-supprimer-tous-les-fichiers-en-dehors-de-l-historique</guid>
            <category><![CDATA[Git]]></category>
            <dc:creator><![CDATA[NicolasBrondinBernard]]></dc:creator>
            <pubDate>Thu, 26 Mar 2026 09:57:15 GMT</pubDate>
            <content:encoded><![CDATA[<p>Quand on utilise Git, il y a une situation assez classique qui finit toujours par arriver.</p>
<blockquote>
<p>un <code>git reset</code>.</p>
</blockquote>
<p>Vous revenez en arrière, vous changez d’état, vous annulez un commit ou vous bougez votre branche… et là, en regardant votre projet, <strong>vous vous retrouvez avec plein de fichiers qui traînent.</strong></p>
<p>Parfois ce sont :</p>
<ul>
<li>des fichiers générés</li>
<li>des dossiers de build</li>
<li>des fichiers temporaires</li>
<li>des morceaux d’un ancien état du projet</li>
</ul>
<blockquote>
<p>Et dans <code>git status</code>, vous voyez apparaître <strong>une longue liste de fichiers “nouveaux”</strong>.</p>
</blockquote>
<p>Git ne les a pas supprimés, parce qu’ils ne font pas partie des fichiers suivis à cet instant. <strong>Mais si vous souhaitez vous en débarasser</strong> (autrement qu’en supprimant tout à la main), voilà comment faire !</p>
<h2>La bonne commande : git clean</h2>
<p>Pour supprimer les fichiers non suivis, Git propose cette commande :</p>
<pre><code class="language-bash">git clean -f
</code></pre>
<p>Cette commande supprime les fichiers non suivis du dossier courant.</p>
<p>Mais attention :</p>
<blockquote>
<p><code>git clean</code> est une commande destructive.</p>
<p>Une fois les fichiers supprimés, Git ne pourra pas les restaurer.</p>
</blockquote>
<h2>Le mode simulation</h2>
<p>Avant de lancer une suppression, le bon réflexe est d’utiliser :</p>
<pre><code class="language-bash">git clean -n
</code></pre>
<blockquote>
<p>Le <code>-n</code> signifie <em><strong>dry run</strong></em>. C’est probablement l’option la plus importante de toute la commande.</p>
</blockquote>
<p>Git affiche ce qu’il supprimerait, sans réellement le faire. Si vous avez beaucoup de fichiers apparus après un <code>git reset</code>, <strong>commencez toujours par là.</strong></p>
<h2>Supprimer les dossiers</h2>
<p>Par défaut, <code>git clean</code> ne supprime pas les dossiers non suivis.</p>
<p>Or après un reset, ce sont souvent justement des dossiers entiers qui traînent :</p>
<ul>
<li><code>dist/</code></li>
<li><code>build/</code></li>
<li><code>.cache/</code></li>
<li>anciens dossiers générés</li>
</ul>
<p>Pour inclure les dossiers, utilisez :</p>
<pre><code class="language-bash">git clean -fd
</code></pre>
<ul>
<li><code>f</code> pour forcer</li>
<li><code>d</code> pour inclure les répertoires</li>
</ul>
<blockquote>
<p>Dans beaucoup de cas, après un <code>git reset</code>, c’est cette commande qu’on cherche vraiment.</p>
</blockquote>
<h2>Inclure les fichiers ignorés par .gitignore</h2>
<p>Il y a un autre cas fréquent.</p>
<p>Vous faites un reset, puis vous voulez repartir d’un projet vraiment propre.</p>
<p>Mais certains fichiers sont ignorés par Git via <code>.gitignore</code> :</p>
<ul>
<li>dossiers de build</li>
<li>fichiers d’environnement</li>
<li>caches</li>
<li>dépendances générées</li>
</ul>
<p>Par défaut, <code>git clean</code> ne les supprime pas.</p>
<p>Si vous voulez aussi supprimer ces fichiers ignorés, il faut utiliser :</p>
<pre><code class="language-bash">git clean -fdx
</code></pre>
<p>Cette commande supprime :</p>
<ul>
<li>les fichiers non suivis</li>
<li>les dossiers non suivis</li>
<li>les fichiers ignorés par <code>.gitignore</code></li>
</ul>
<blockquote>
<p>Elle est très utile pour remettre un projet dans <strong>un état vraiment propre.</strong></p>
</blockquote>
<p>Mais elle doit être utilisée <strong>avec une grande prudence.</strong></p>
<h3>Supprimer UNIQUEMENT les fichiers ignorés</h3>
<p>Pour ne supprimer que les fichiers présents dans <code>.gitignore</code> ,on utilise le paramètre <code>-X</code> (à ne pas confondre avec <code>-x</code>) :</p>
<pre><code class="language-bash">git clean -fdX
</code></pre>
<blockquote>
<p>Supprime <strong>uniquement les fichiers ignorés</strong></p>
</blockquote>
<h2>Conclusion</h2>
<p>Retenez surtout ceci :</p>
<ul>
<li><code>git clean -n</code> permet de vérifier avant</li>
<li><code>git clean -fd</code> supprime fichiers + dossiers</li>
<li><code>git clean -fdx</code> fait le ménage complet</li>
</ul>
]]></content:encoded>
            <media:content url="https://code-garage-strapi-bucket-production.cellar-c2.services.clever-cloud.com/nicolasbrondinbernard_pixel_art_scene_of_a_cluttered_room_being_30f18ffc_8d51_4962_85d1_b4d864a4e024_351ab3051d.jpg" medium="image"/>
        </item>
        <item>
            <title><![CDATA[Comment ne pas exécuter les scripts tiers avec npm, pnpm et yarn]]></title>
            <description><![CDATA[Découvrez comment utiliser npm install --ignore-scripts pour empêcher l’exécution de scripts dangereux ou inutiles lors de l’installation des dépendances npm.]]></description>
            <link>https://code-garage.com/blog/comment-ne-pas-executer-les-scripts-tiers-avec-npm-pnpm-et-yarn</link>
            <guid isPermaLink="true">https://code-garage.com/blog/comment-ne-pas-executer-les-scripts-tiers-avec-npm-pnpm-et-yarn</guid>
            <category><![CDATA[NodeJS]]></category>
            <category><![CDATA[NPM]]></category>
            <category><![CDATA[PNPM]]></category>
            <category><![CDATA[Yarn]]></category>
            <category><![CDATA[Sécurité]]></category>
            <dc:creator><![CDATA[NicolasBrondinBernard]]></dc:creator>
            <pubDate>Tue, 17 Mar 2026 08:50:43 GMT</pubDate>
            <content:encoded><![CDATA[<p>Quand vous installez un projet Node.js, il y a un réflexe très courant :</p>
<pre><code class="language-bash">npm install
</code></pre>
<p>Cette commande semble anodine. Elle télécharge simplement les dépendances listées dans le <code>package.json</code>.</p>
<p>Mais en réalité, <strong>npm peut aussi exécuter du code</strong> pendant l’installation.</p>
<p>Beaucoup de développeurs l’ignorent, mais certains packages contiennent des scripts qui s’exécutent automatiquement lors de l’installation. Et dans certains cas, ces scripts peuvent poser problème : comportements inattendus, téléchargements lourds… ou pire, <strong>scripts malveillants</strong>.</p>
<p>Heureusement, npm propose une option simple pour éviter cela :</p>
<pre><code class="language-bash">npm install --ignore-scripts
</code></pre>
<blockquote>
<p>Cette option empêche npm d’exécuter les scripts définis dans les dépendances.</p>
</blockquote>
<h2>Les scripts exécutés automatiquement par npm</h2>
<p>Dans un <code>package.json</code>, un package peut définir plusieurs scripts.</p>
<p>Par exemple :</p>
<pre><code class="language-json">{
  &quot;scripts&quot;: {
    &quot;postinstall&quot;: &quot;node build.js&quot;
  }
}
</code></pre>
<blockquote>
<p>npm peut exécuter automatiquement certains scripts pendant l’installation.</p>
</blockquote>
<p>Les plus courants sont :</p>
<ul>
<li><code>preinstall</code></li>
<li><code>install</code></li>
<li><code>postinstall</code></li>
<li><code>prepare</code></li>
</ul>
<p>Ces scripts sont souvent utilisés pour compiler du code natif, télécharger des binaires, générer des fichiers nécessaires au package, préparer des assets, etc…</p>
<blockquote>
<p>Le problème, c’est que <strong>npm exécute ces scripts automatiquement</strong>, sans vous demander votre avis.</p>
</blockquote>
<h2>Le risque : exécuter du code sans le savoir</h2>
<p>L’écosystème npm est immense. On compte aujourd’hui <strong>plus de deux millions de packages</strong>.</p>
<blockquote>
<p>Et comme dans tout écosystème ouvert, il arrive que certains packages soient malveillants ou compromis.</p>
</blockquote>
<p>Plusieurs incidents ont déjà eu lieu :</p>
<ul>
<li>des packages abandonnés repris par des acteurs malveillants</li>
<li>des dépendances injectant du code espion</li>
<li>des scripts envoyant des informations système</li>
</ul>
<p>Les scripts <code>postinstall</code> sont particulièrement sensibles, car ils s’exécutent <strong>directement sur votre machine</strong> au moment de l’installation.</p>
<p>Concrètement, un script npm peut :</p>
<ul>
<li>accéder à votre système de fichiers</li>
<li>lire des variables d’environnement</li>
<li>envoyer des données vers Internet</li>
<li>modifier votre configuration</li>
</ul>
<blockquote>
<p>En d’autres termes : <strong>un simple <code>npm install</code> peut exécuter du code arbitraire</strong>.</p>
</blockquote>
<h2>Utiliser ignore-scripts pour garder le contrôle</h2>
<p>Pour éviter cela, npm propose une option très simple :</p>
<pre><code class="language-bash">npm install --ignore-scripts
</code></pre>
<p>Avec cette commande :</p>
<ul>
<li>npm télécharge les dépendances</li>
<li>npm les installe dans <code>node_modules</code></li>
<li><strong>mais aucun script n’est exécuté</strong></li>
</ul>
<p>Cela bloque :</p>
<ul>
<li><code>preinstall</code></li>
<li><code>install</code></li>
<li><code>postinstall</code></li>
<li><code>prepare</code></li>
</ul>
<p>Les packages sont installés <strong>sans exécution de code externe</strong>.</p>
<blockquote>
<p>⚠️ <strong>Attention : <code>--ignore-scripts</code> bloque absolument tous les scripts.</strong></p>
</blockquote>
<p>Il n’est pas possible de désactiver uniquement <code>postinstall</code> ou un script spécifique.</p>
<p>Si vous utilisez cette option, <strong>aucun script lifecycle ne sera exécuté</strong>, quel que soit le package.</p>
<p>Cette option est particulièrement utile dans plusieurs situations :</p>
<ul>
<li>audit de dépendances</li>
<li>analyse d’un projet inconnu</li>
<li>environnement sécurisé</li>
<li>pipeline CI/CD</li>
<li>installation de dépendances non fiables</li>
</ul>
<h2>Équivalent avec pnpm et yarn</h2>
<p>Si vous utilisez un autre gestionnaire de paquets, sachez que <strong>des options similaires existent</strong>.</p>
<h3>pnpm</h3>
<p>pnpm propose exactement la même option :</p>
<pre><code class="language-bash">pnpm install --ignore-scripts
</code></pre>
<blockquote>
<p>Le comportement est identique à npm : les dépendances sont installées mais <strong>aucun script lifecycle n’est exécuté</strong>.</p>
</blockquote>
<h3>Yarn</h3>
<p>Avec Yarn (v1 ou v3), l’option est également disponible :</p>
<pre><code class="language-bash">yarn install --ignore-scripts
</code></pre>
<blockquote>
<p>Comme pour npm et pnpm, cela bloque l’exécution des scripts <code>preinstall</code>, <code>install</code> et <code>postinstall</code>.</p>
</blockquote>
<p>Autrement dit, <strong>les trois principaux gestionnaires de paquets Node.js offrent ce mécanisme de sécurité</strong>.</p>
<h2>Réactiver les scripts si nécessaire</h2>
<p>Si un package a réellement besoin de ses scripts pour fonctionner, vous pouvez les relancer plus tard.</p>
<p>Par exemple :</p>
<pre><code class="language-bash">npm rebuild
</code></pre>
<p>Ou simplement relancer l’installation normalement :</p>
<pre><code class="language-bash">npm install
</code></pre>
<blockquote>
<p>L’avantage est que <strong>vous gardez le contrôle sur ce qui s’exécute sur votre machine</strong>.</p>
</blockquote>
<p>Dans un écosystème aussi vaste que npm, cette petite option peut éviter de nombreux problèmes.</p>
]]></content:encoded>
            <media:content url="https://code-garage-strapi-bucket-production.cellar-c2.services.clever-cloud.com/Chat_GPT_Image_Mar_13_2026_10_48_35_AM_copy_a7e3964495.jpg" medium="image"/>
        </item>
    </channel>
</rss>