<?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>Fri, 05 Jun 2026 17:05:38 GMT</lastBuildDate>
        <atom:link href="https://code-garage.com/blog/rss" rel="self" type="application/rss+xml"/>
        <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>
        <item>
            <title><![CDATA[Découvrez BullMQ, une MessageQueue simple avec NodeJS]]></title>
            <description><![CDATA[Dans une application moderne, certaines opérations peuvent être longues et bloquer l’application principale, on utilise alors souvent des files de tâches. BullMQ est une solution simple pour gérer ce type de traitement en arrière-plan.]]></description>
            <link>https://code-garage.com/blog/decouvrez-bullmq-une-message-queue-simple-avec-nodejs</link>
            <guid isPermaLink="true">https://code-garage.com/blog/decouvrez-bullmq-une-message-queue-simple-avec-nodejs</guid>
            <category><![CDATA[Asynchrone]]></category>
            <category><![CDATA[Redis]]></category>
            <category><![CDATA[NodeJS]]></category>
            <category><![CDATA[Python]]></category>
            <category><![CDATA[PHP]]></category>
            <dc:creator><![CDATA[NicolasBrondinBernard]]></dc:creator>
            <pubDate>Mon, 09 Mar 2026 09:20:06 GMT</pubDate>
            <content:encoded><![CDATA[<p>Imaginez une application web qui doit un exporter un zip, puis l’envoyer par e-mail, <strong>pour qu’un utilisateur puisse télécharger des données.</strong></p>
<p>Si votre serveur attend que <strong>le zip soit compressé puis envoyé</strong> avant de répondre à l’utilisateur :</p>
<ul>
<li>la requête devient lente</li>
<li>votre serveur peut bloquer</li>
<li>la requête peut échouer à cause d’un timeout</li>
</ul>
<blockquote>
<p>La solution consiste à <strong>déléguer ce travail à un système de tâches asynchrones</strong>.</p>
</blockquote>
<p>Au lieu de créer le zip directement, l’application ajoute une tâche dans une file :</p>
<pre><code class="language-plaintext">(1) Exporter données (user@example.com) -- En cours...
(2) Exporter données (user2@test.com)   -- En attente
(3) Exporter données (user3@fake.com)   -- Tâche ajoutée
</code></pre>
<p>L’utilisateur, lui, va recevoir une confirmation immédiate du traitement de sa demande, et un autre processus (parfois un autre serveur, conteneur,…) <strong>se chargera de traiter la demande et d’envoyer l’email.</strong></p>
<p>Comme ceci :</p>
<pre><code class="language-plaintext">Lire la tâche en cours
|
Récupérer les données
|
Créer l'archive zip
|
Envoyer l'email (user@example.com)
|
Valider la tâche
</code></pre>
<blockquote>
<p>Tant qu’il y a des tâches en cours, le processus les traitera les unes à la suite des autres, <strong>dans l’ordre d’arrivée (First In - First Out ou FIFO)</strong></p>
</blockquote>
<p>De cette manière, <strong>notre serveur web n’est pas bloqué par des tâches longues ou coûteuses</strong>, il peut continuer à traiter le reste de ses requêtes facilement !</p>
<h2>Qu’est-ce que BullMQ ?</h2>
<p><a href="https://bullmq.io/"><strong>BullMQ</strong></a> est une bibliothèque permettant de gérer ce type de file de tâches.</p>
<p>Elle repose sur <a href="https://code-garage.com/tags/redis"><strong>Redis</strong></a>, <strong>une base de données en mémoire très rapide</strong> qui sert à stocker et coordonner les tâches.</p>
<blockquote>
<p>Si vous ne connaissez pas Redis, on vous a préparé <a href="https://code-garage.com/blog/redis-une-base-de-donnees-rapide-comme-l-eclair">un article dédié !</a></p>
</blockquote>
<p>Le fonctionnement repose sur trois éléments :</p>
<ul>
<li><strong>La queue (file)</strong> : l’endroit où les tâches sont ajoutées</li>
<li><strong>Les workers</strong> : des processus qui exécutent les tâches</li>
<li><strong>Redis</strong> : le moteur qui stocke les jobs et leur état</li>
</ul>
<p>Le flux ressemble généralement à ceci :</p>
<ol>
<li>L’application ajoute une tâche dans la queue</li>
<li>Redis stocke cette tâche</li>
<li>Un worker récupère la tâche</li>
<li>Le worker exécute l’action (ex : envoyer un email)</li>
</ol>
<blockquote>
<p>Ce modèle permet de <strong>séparer la logique métier principale des traitements lourds</strong>.</p>
</blockquote>
<p>Attention, BullMQ n’est pas un MessageBroker, c’est simplement une file d’attente ! On va voir la différence un peu plus loin avec RabbitMQ par exemple.</p>
<h3>Un exemple simple</h3>
<p>Voici un exemple minimal avec Node.js pour <strong>ajouter une tâche dans une queue</strong> :</p>
<pre><code class="language-js">import { Queue } from &quot;bullmq&quot;;

const emailQueue = new Queue(&quot;email-queue&quot;, {
  connection: {
    host: &quot;localhost&quot;,
    port: 6379
  }
});

await emailQueue.add(&quot;send-welcome-email&quot;, {
  email: &quot;user@example.com&quot;,
  name: &quot;Alice&quot;
});
</code></pre>
<blockquote>
<p>Ce code ajoute une tâche appelée <code>send-welcome-email</code> dans Redis.</p>
</blockquote>
<p>Et voici un exemple d’un Worker qui traite les tâches :</p>
<pre><code class="language-js">import { Worker } from &quot;bullmq&quot;;

const worker = new Worker(
  &quot;email-queue&quot;,
  async job =&gt; {
    const { email, name } = job.data;

    console.log(`Envoi de l'email de bienvenue à ${name} (${email})`);

    // Ici on pourrait appeler un service SMTP
    // sendEmail(email, ...)
  },
  {
    connection: {
      host: &quot;localhost&quot;,
      port: 6379
    }
  }
);
</code></pre>
<blockquote>
<p>Dès qu’une tâche est ajoutée, le worker la récupère et exécute le traitement.</p>
</blockquote>
<h3>Cas d’usage typiques</h3>
<p>Les files de tâches comme BullMQ sont utilisées pour :</p>
<ul>
<li>envoyer des emails</li>
<li>générer des rapports ou documents</li>
<li>traiter des images ou vidéos</li>
<li>importer de grandes quantités de données</li>
<li>exécuter des tâches planifiées</li>
<li>lancer des traitements lourds en arrière-plan</li>
</ul>
<blockquote>
<p>Dès qu’une opération peut prendre du temps ou échouer temporairement, une queue devient utile.</p>
</blockquote>
<h2>Les forces et faiblesses de BullMQ</h2>
<p>BullMQ présente <strong>plusieurs avantages importants</strong> : il est performant, gèrent les “retries” en cas d’échecs, mais possède surtout une très bonne DX et <strong>n’a besoin que d’une dépendance d’infrastructure (Une base Redis).</strong></p>
<p>Mais cela reste néanmoins une solution relativement simple, avec ses limites : <strong>limité à NodeJS, Python et PHP</strong>, il est également mois adapté aux architectures très distribuées.</p>
<h2>Et RabbitMQ alors ?</h2>
<p>La différence principale entre BullMQ et RabbitMQ est leur rôle :</p>
<ul>
<li>BullMQ est une <strong>bibliothèque de gestion de tâches</strong>.</li>
<li>RabbitMQ est un <strong>message broker</strong>, conçu pour faire communiquer plusieurs services entre eux.</li>
</ul>
<p>Avec RabbitMQ, chaque service peut envoyer des messages sur la Queue, et chaque service est libre de traiter un message comme il l’entend. <strong>BullMQ permet simplement d’envoyer une tâche de manière unilatérale</strong>, et avec une seule source de vérité (même si autant de Worker peuvent écouter les tâches).</p>
<blockquote>
<p><strong>RabbitMQ est aussi plus lourd à mettre en place</strong>, avec une infrastructure dédiée, et son protocol basé sur AMQP.</p>
</blockquote>
<h2>Note supplémentaire</h2>
<p>Il est important de rappeler que BullMQ est capable de garder les tâches en mémoire à long terme, <strong>uniquement si la persistence est activée sur votre base de données Redis !</strong></p>
]]></content:encoded>
            <media:content url="https://code-garage-strapi-bucket-production.cellar-c2.services.clever-cloud.com/nicolasbrondinbernard_A_game_of_Jenga_with_a_bull_running_towar_73661975_0c7a_463e_8028_8743ca2870b5_6d0f824c54.jpg" medium="image"/>
        </item>
        <item>
            <title><![CDATA[Comment récupérer les variables d’environnement en COBOL ?]]></title>
            <description><![CDATA[Même si COBOL est un langage ancien, il reste encore utilisé dans de nombreux systèmes critiques. Mais comment faire pour adapter son comportement selon l’environnement, par exemple, passer du mode développement au mode production ? La réponse passe par les variables d’environnement.]]></description>
            <link>https://code-garage.com/blog/comment-recuperer-les-variables-environnement-en-cobol</link>
            <guid isPermaLink="true">https://code-garage.com/blog/comment-recuperer-les-variables-environnement-en-cobol</guid>
            <category><![CDATA[Cobol]]></category>
            <dc:creator><![CDATA[NicolasBrondinBernard]]></dc:creator>
            <pubDate>Mon, 02 Mar 2026 16:42:26 GMT</pubDate>
            <content:encoded><![CDATA[<h2>Les variables d’environnement, c’est quoi ?</h2>
<p>Une <strong>variable d’environnement</strong> est une valeur stockée par le système d’exploitation et accessible par les programmes.</p>
<p>Elles servent à définir le <strong>contexte d’exécution</strong> d’une application :</p>
<ul>
<li>nom du serveur</li>
<li>chemin vers une base de données</li>
<li>mode de fonctionnement (DEV / PROD)</li>
<li>etc...</li>
</ul>
<blockquote>
<p>En COBOL, on peut y accéder grâce à l’instruction <code>ACCEPT</code>.</p>
</blockquote>
<h2>Lire une variable d’environnement en COBOL</h2>
<p>Voici un exemple simple pour <strong>récupérer la variable d’environnement</strong> <code>APP_MODE</code> :</p>
<pre><code class="language-plaintext">       IDENTIFICATION DIVISION.
       PROGRAM-ID. EnvExample.

       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01  APP-MODE       PIC X(10).

       PROCEDURE DIVISION.
           ACCEPT APP-MODE FROM ENVIRONMENT &quot;APP_MODE&quot;
           DISPLAY &quot;Mode d'exécution : &quot; APP-MODE
           STOP RUN.

</code></pre>
<ul>
<li><code>ACCEPT</code> permet de <strong>lire une entrée externe</strong>.</li>
<li>En précisant <code>FROM ENVIRONMENT &quot;APP_MODE&quot;</code>, on demande à COBOL de lire la variable d’environnement correspondante.</li>
<li>La valeur est stockée dans la variable <code>APP-MODE</code>.</li>
</ul>
<h3>Exemple pratique</h3>
<p>Imaginons que vous vouliez exécuter certaines instructions selon l’environnement :</p>
<pre><code class="language-plaintext">       IF APP-MODE = &quot;DEV&quot;
           DISPLAY &quot;Connexion à la base de test...&quot;
       ELSE
           DISPLAY &quot;Connexion à la base de production...&quot;
       END-IF.
</code></pre>
<blockquote>
<p>Mais avant d’exécuter votreprogramme, tu peux définir la variable selon le contexte :</p>
</blockquote>
<pre><code>Mode d'exécution : DEV
Connexion à la base de test...
</code></pre>
<h2>Gérer les cas particuliers</h2>
<h3>Les valeurs numériques</h3>
<p>Une chose à retenir, c’est qu’une variable d’environnement est toujours passée à un programme sous forme de <code>string</code>. Il est possible de la convertir automatiquement en COBOL, en la déclarant comme une valeur valeur numérique, comme ceci avec <code>port</code> qui serait égal à <code>3000</code> :</p>
<pre><code class="language-plaintext">01 PORT PIC 9(4).
ACCEPT PORT FROM ENVIRONMENT &quot;PORT&quot;
</code></pre>
<blockquote>
<p>Mais ce n’est pas conseillé.</p>
</blockquote>
<p>Si votre votre variable contient par erreur une valeur qui ne peut pas être parsée, alors il y a de fortes chances que votre programme crash (en fonction de votre environnement).</p>
<p>Il vaut mieux lire une valeur alpha-numérique, pour ensuite vérifier et convertir, comme ceci :</p>
<pre><code class="language-plaintext">01 PORT-STR PIC X(10).
01 PORT     PIC 9(4).

ACCEPT PORT-STR FROM ENVIRONMENT &quot;PORT&quot;

IF PORT-STR IS NUMERIC
    MOVE PORT-STR TO PORT
ELSE
    DISPLAY &quot;PORT invalide&quot;
END-IF
</code></pre>
<h3>Les valeurs vides</h3>
<p>Si une variable d’environnement est lue, mais quelle est vide (ou simplement non définie), alors votre programme ne recevras qu’un ensemble d’espaces équivalent à la longueur de votre variables.</p>
<p>Pour vérifier si votre variable est définie ou non, et lui assigner une valeur par défaut, il vous suffira de faire ceci :</p>
<pre><code class="language-plaintext">ACCEPT APP-MODE FROM ENVIRONMENT &quot;APP_MODE&quot;
IF APP-MODE = SPACES
    MOVE &quot;DEV&quot; TO APP-MODE
DISPLAY &quot;Mode d'exécution : &quot; APP-MODE
STOP RUN.
</code></pre>
<blockquote>
<p>La constante SPACES est une constante “figurative”, qui s’adapte au contexte, et elle correspond au nombre d’espaces nécessaires pour remplir votre variable.</p>
</blockquote>
]]></content:encoded>
            <media:content url="https://code-garage-strapi-bucket-production.cellar-c2.services.clever-cloud.com/nicolasbrondinbernard_COBOL_environment_a487796549.jpg" medium="image"/>
        </item>
        <item>
            <title><![CDATA[Diplôme, Titre RNCP, Bachelor, Mastère… quelles différences ?]]></title>
            <description><![CDATA[Vous cherchez votre future école et vous êtes perdu dans toute l'offre de diplômes, titres et certifications en tout genre ?]]></description>
            <link>https://code-garage.com/blog/differences-diplome-titre-rncp-bachelor-mastere</link>
            <guid isPermaLink="true">https://code-garage.com/blog/differences-diplome-titre-rncp-bachelor-mastere</guid>
            <category><![CDATA[Education]]></category>
            <category><![CDATA[Etudes & Ecoles]]></category>
            <dc:creator><![CDATA[NicolasBrondinBernard]]></dc:creator>
            <pubDate>Mon, 23 Feb 2026 13:16:04 GMT</pubDate>
            <content:encoded><![CDATA[<p>Lorsque vous cherchez une formation en informatique, en initial ou en reconversion, on vous parle de diplômes, de titres RNCP, de Bachelors, Mastères, certifications…</p>
<blockquote>
<p>Tout semble équivalent. En réalité, derrière ces termes se cachent des significations bien différentes.</p>
</blockquote>
<p>Alors on vous a préparé un guide pour éclaircir tout ça !</p>
<h2>Les diplôme d’Etat</h2>
<p>Un diplôme d’État est délivré par une université ou un établissement habilité par l’État (comme une école d’ingénieur). Il s’inscrit dans le système LMD (Licence - Master - Doctorat) et donne <strong>des crédits ECTS reconnus en Europe.</strong></p>
<p>Exemples :</p>
<ul>
<li>BUT Informatique (anciennement DUT)</li>
<li>Licence Informatique</li>
<li>Master Informatique</li>
<li>Diplôme d’ingénieur (Bac +5 réservé aux écoles d’ingénieurs)</li>
</ul>
<p>Ces formations offrent généralement <strong>une base théorique solide</strong> : algorithmique, systèmes, structures de données, parfois mathématiques avancées.</p>
<p>Elles sont particulièrement adaptées si vous souhaitez :</p>
<ul>
<li>Continuer vers un Bac+5 ou un doctorat</li>
<li>Garder une reconnaissance académique forte</li>
<li>Travailler à l’international</li>
</ul>
<blockquote>
<p>En revanche, elles peuvent être plus longues et parfois moins professionalisantes.</p>
</blockquote>
<h2>Les titres professionnels (RNCP)</h2>
<p>Un titre RNCP (Répertoire National des Certifications Professionnelles) est <strong>une certification professionnelle reconnue par l’État.</strong></p>
<p>Il ne s’agit pas d’un diplôme universitaire, mais d’<strong>une validation de compétences</strong> liées à un métier précis.</p>
<p>Chaque titre possède un niveau (5 = Bac+2, 6 = Bac+3/4, 7 = Bac+5) et un référentiel de compétences.</p>
<p>Pour un développeur, vous verrez souvent des titres comme :</p>
<ul>
<li>Développeur web et web mobile (niveau 5)</li>
<li>Concepteur développeur d’applications (niveau 6)</li>
<li>Expert en ingénierie logicielle (niveau 7)</li>
</ul>
<blockquote>
<p>Il en existe d’autres, et elles peuvent changer en fonction des années mais celles-ci sont les plus courantes</p>
</blockquote>
<p>Ces formations reconnues par l’état sont généralement plus professionnalisantes, <strong>avec beaucoup de projets concrets et souvent de l’alternance.</strong></p>
<p>Mais elles vous forment également à <strong>la réalité d’un métier à un instant T</strong>, sans toujours apporter les bases les plus solides pour s’adapter à de futurs changement, contrairement à la voie universitaire.</p>
<h2>Bachelor et Mastère : des termes marketing</h2>
<p>En France, les mots “Bachelor” et “Mastère” ne sont pas protégés.</p>
<p>Cela signifie qu’une école peut appeler sa formation “Bachelor Développeur Web” <strong>sans que cela corresponde à un diplôme d’État.</strong></p>
<p>Ce qui compte réellement, ce n’est pas le nom, mais :</p>
<ul>
<li>Existe-t-il un titre RNCP associé ?</li>
<li>À quel niveau est-il enregistré ?</li>
</ul>
<blockquote>
<p>Un Bachelor ou un Mastère peut être très sérieux… ou simplement marketing. <strong>Il faut toujours faire attention.</strong></p>
</blockquote>
<p>Vous aurez noté la différence entre un “Master” (universitaire) et un “Mastère” (non-reconnu par l’état), beaucoup de personnes confondent les deux chaque année.</p>
<h2>Les certifications</h2>
<p>Une certification n’est ni un diplôme ni un titre RNCP.</p>
<p>Il s’agit d’une validation ciblée de compétences, par exemple :</p>
<ul>
<li>Certification React</li>
<li>Certification AWS</li>
<li>Certification Scrum</li>
</ul>
<blockquote>
<p>Ces certifications peuvent valoriser un profil, mais elles <strong>ne remplacent pas une formation complète.</strong></p>
</blockquote>
<h2>Trouvez votre future école</h2>
<p>La réalité du marché d'aujourd'hui fait que <strong>ce n'est pas simplement le diplôme qui fera de vous un.e professionnel.le</strong>, mais surtout la qualité des apprentissages, des cours et des projets dispensés à l'école qui pourront vous donner une longueur d'avance.</p>
<p>C'est pour cela qu'on a lancé <strong>notre référentiel national des écoles d'informatique en France</strong>, pour que chaque étudiant.e puisse laisser un ou plusieurs avis pour guider les futurs étudiants !</p>
<blockquote>
<p>Découvrez <a href="https://code-garage.com/schools/search">notre référentiel complet</a></p>
</blockquote>
]]></content:encoded>
            <media:content url="https://code-garage-strapi-bucket-production.cellar-c2.services.clever-cloud.com/nicolasbrondinbernard_The_main_building_of_Harvard_Campus_in_a_907113a1_9ab3_47a0_82c8_6b33bc6b28ba_copy_7e864ab1e2.jpg" medium="image"/>
        </item>
        <item>
            <title><![CDATA[Générer des PDFs à partir de HTML avec SecretPDF]]></title>
            <description><![CDATA[Apprenez à générer des PDF depuis du HTML avec un seul call d'API !]]></description>
            <link>https://code-garage.com/blog/generer-des-pdfs-a-partir-de-html-avec-secretpdf</link>
            <guid isPermaLink="true">https://code-garage.com/blog/generer-des-pdfs-a-partir-de-html-avec-secretpdf</guid>
            <category><![CDATA[Outils]]></category>
            <category><![CDATA[SaaS]]></category>
            <category><![CDATA[API]]></category>
            <dc:creator><![CDATA[NicolasBrondinBernard]]></dc:creator>
            <pubDate>Tue, 17 Feb 2026 13:46:21 GMT</pubDate>
            <content:encoded><![CDATA[<p>Générer un PDF en 2026, c’est censé ne plus être un problème technique. Mais le faire <strong>simplement, proprement, de manière maintenable, scalable et prête pour la production…</strong> ça, c’est une autre histoire.</p>
<blockquote>
<p>Dans cet article, nous allons voir comment générer des PDFs à partir d’un template HTML de la manière la plus simple possible avec <strong><a href="https://www.secretpdf.io">SecretPDF</a>.</strong></p>
</blockquote>
<h2>Pourquoi générer des PDFs est souvent complexe ?</h2>
<p>Le format PDF est à la fois simple et complexe. Il est simple d’utilisation, car portable (il inclut toutes les ressources nécessaire pour le rendu), mais il est complexe à produire.</p>
<blockquote>
<p>Un PDF peut contenir du texte, des polices d’écriture, des images, du vectoriel, etc…</p>
</blockquote>
<p>Il est possible de générer un fichier PDF directement depuis le navigateur, <strong>mais dès que l’on a besoin d’un rendu légèrement complexe (autrement dit “joli”)</strong>, c’est un casse-tête, surtout sur mobile.</p>
<p>Si votre objectif est de :</p>
<ul>
<li>Générer un vrai document</li>
<li>Avec un design intéressant</li>
<li>Du contenu texte sélectionnable (pas seulement une image)</li>
<li>Sans hack CSS obscur</li>
</ul>
<p><strong>Alors vous devez générer des PDF côté serveur</strong>, ce qui implique de trouver la solution qui convient à vos contrainte, monter une architecture, la dimensionner, faire en sorte que cela n’impacte pas les performances de vos autres applications.</p>
<blockquote>
<p>C’est là qu’arrive SecretPDF !</p>
</blockquote>
<p>::: image
<img src="https://code-garage-strapi-bucket-production.cellar-c2.services.clever-cloud.com/Capture_d_ecran_2026_02_17_a_11_12_20_6fa0af2297.png" alt="">
:::</p>
<h2>SecretPDF, c’est quoi ?</h2>
<p><strong>SecretPDF</strong> est un SaaS facile d’utilisation, avec <strong>une API moderne pour générer des documents PDF à partir de HTML.</strong></p>
<p>Vous lui envoyez :</p>
<ul>
<li>du HTML/CSS (même des classes Tailwind pour le design si vous voulez)</li>
<li>des données dynamiques</li>
<li>un format de page</li>
</ul>
<p>Il vous renvoie :</p>
<ul>
<li>un PDF prêt à télécharger</li>
</ul>
<blockquote>
<p>Et en plus l’outil est RGPD-compliant et neutre en carbone. Que demander de plus ?</p>
</blockquote>
<h3>Le tarif</h3>
<p>SecretPDF fonctionne <strong>avec un système de crédits</strong> (1 pdf = 1 crédit pour les PDF &lt;2Mo)</p>
<p>Vous avez :</p>
<ul>
<li>10 crédits gratuits tous les mois</li>
<li>Puis 0.01$ par crédit</li>
</ul>
<blockquote>
<p>C’est idéal pour les startups et les SaaS : Pas de document généré, pas de paiement.</p>
</blockquote>
<p>D’ailleurs vous n’êtes même <strong>pas obligé de rentrer votre carte bancaire</strong> pour commencer.</p>
<p>À noter également que vous pouvez <strong>générer autant de documents de test que vous désirez</strong>, grâce à une option “sandbox” qui vous permet de tester vos templates gratuitement !</p>
<h2>Etape 1 : Créer un compte</h2>
<p><strong>Pour créer un compte</strong>, il suffit de connecter son compte Github, <a href="https://app.secretpdf.io/sign-in">en un seul clic !</a></p>
<p>Ensuite, vous serez guidé vers la création <strong>de votre premier template et de votre première clé d’API</strong>. L’un des gros avantages de SecretPDF est qu’il vous permet de créer vos templates directement de puis l’interface (avec une preview) ou bien depuis l’API :</p>
<p>::: image
<img src="https://code-garage-strapi-bucket-production.cellar-c2.services.clever-cloud.com/Capture_d_ecran_2026_02_17_a_13_30_54_55010d1bf7.png" alt="">
:::</p>
<h2>Étape 2 :  Installer le client</h2>
<p>Vous pouvez utiliser l’API avec n’importe quel langage ou framework en suivant <a href="https://www.secretpdf.io/docs/">la documentation officielle</a>, mais vous pouvez également utiliser le client NodeJS dédié pour vous faciliter la vie.</p>
<p>Dans votre projet Node.js <strong>exécutez la commande suivante :</strong></p>
<pre><code class="language-bash">npm install @secretpdf/sdk
</code></pre>
<p>Puis dans votre code, initialisez-le :</p>
<pre><code class="language-jsx">import SecretPDF from &quot;@secretpdf/sdk&quot;;

const client = new SecretPDF({
  apiKey: &quot;&lt;secret&gt;&quot;,
});
</code></pre>
<blockquote>
<p>Il est évidemment conseillé de définir votre clé API dans vos variables d’environnement</p>
</blockquote>
<h2>Etape 3 (optionnelle) : Créer un template depuis l’API</h2>
<p>Si vous préférez créer votre premier template directement depuis l’API, c’est possible, comme ceci :</p>
<pre><code class="language-jsx">const response = await client.createTemplate({
  name: &quot;Facture&quot;,
  size: &quot;A4&quot;,
  content: `
    &lt;main class=&quot;p-10&quot;&gt;
      &lt;h1 class=&quot;text-3xl font-bold text-blue-600&quot;&gt;
        Facture
      &lt;/h1&gt;
      &lt;p&gt;Prestataire : {{name}} (SIRET {{siret}})&lt;/p&gt;
      &lt;p&gt;Montant: {{amount}}€&lt;/p&gt;
      &lt;p class=&quot;mt-4 text-gray-700&quot;&gt;
        Merci pour votre confiance.
      &lt;/p&gt;
    &lt;/main&gt;
  `,
});

const templateId = response.data.id;
</code></pre>
<blockquote>
<p>Je vous conseille quand même d’utiliser l’interface, cela vous facilitera la vie.</p>
</blockquote>
<h2>Étape 4 : Générer votre premier PDF</h2>
<p>Voici l’exemple le plus simple possible pour <strong>générer un PDF à partir de votre template</strong> :</p>
<pre><code class="language-jsx">const response = await client.generate({
  sandbox: true,
  templateId: &quot;&lt;template_id&gt;&quot;,
  data: {
    name: &quot;Nicolas Brondin-Bernard&quot;,
    siret: &quot;784 671 695 00103&quot;,
    amount: 139.99,
    date: new Date()
  }
});
</code></pre>
<blockquote>
<p><code>sandbox</code> permet de générer un document de test avec un watermark par dessus, <strong>ce qui ne consommera aucun crédit.</strong></p>
</blockquote>
<p>La réponse contient une simple propriété <code>data</code> avec le contenu du fichier généré (encodé en Base64), c’est aussi simple que ça !</p>
<h2>Étape 5 (optionnelle) : Sauvegarder le fichier sur disque</h2>
<p><strong>Rien en vous oblige à stocker le fichier généré</strong>, vous pouvez par exemple l’envoyer en réponse HTTP à votre utilisateur, mais si vous souhaitez le faire, rien de plus simple :</p>
<pre><code class="language-jsx">import fs from &quot;fs&quot;;

const response = await client.generate({
  //...
});

const pdfBuffer = Buffer.from(result.content, 'base64');
fs.writeFileSync('output.pdf', pdfBuffer);
</code></pre>
<blockquote>
<p>Et voilà, le tour est joué !</p>
</blockquote>
]]></content:encoded>
            <media:content url="https://code-garage-strapi-bucket-production.cellar-c2.services.clever-cloud.com/nicolasbrondinbernard_A_factory_that_produces_sheets_of_paper_de2ace28db.jpg" medium="image"/>
        </item>
    </channel>
</rss>