<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Quentin Merle</title>
    <description>The latest articles on Forem by Quentin Merle (@quentin_merle).</description>
    <link>https://forem.com/quentin_merle</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3769613%2Ffcffc37d-fba3-4f3d-9cf5-7380528de781.jpg</url>
      <title>Forem: Quentin Merle</title>
      <link>https://forem.com/quentin_merle</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/quentin_merle"/>
    <language>en</language>
    <item>
      <title>🚀 L'IA locale en 2026 : Ma traversée du désert (Du Terminal au GPU)</title>
      <dc:creator>Quentin Merle</dc:creator>
      <pubDate>Thu, 26 Mar 2026 18:48:21 +0000</pubDate>
      <link>https://forem.com/quentin_merle/lia-locale-en-2026-ma-traversee-du-desert-du-terminal-au-gpu-2d0o</link>
      <guid>https://forem.com/quentin_merle/lia-locale-en-2026-ma-traversee-du-desert-du-terminal-au-gpu-2d0o</guid>
      <description>&lt;p&gt;🌐 English version here: &lt;a href="https://dev.to/quentin_merle/local-ai-in-2026-my-journey-through-the-desert-from-terminal-to-gpu-k35"&gt;Local AI in 2026: My Journey Through the Desert&lt;/a&gt;&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Disclaimer &amp;amp; Contexte :&lt;/strong&gt; Cet article est basé sur mon expérience personnelle avec un MacBook Pro M1 Pro (32 Go de RAM) et VS Code. Si j'utilise Claude comme référence principale pour l'IA Cloud (vu sa domination actuelle sur le code), la même logique s'applique à Gemini ou ChatGPT quand on compare la puissance du Cloud à l'efficacité du local.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Le point de départ : "&lt;em&gt;L'IA locale, c'est vraiment bien ? C'est compliqué à installer ?&lt;/em&gt;"&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Il y a quelques semaines, je n'y connaissais rien à &lt;strong&gt;&lt;a href="https://ollama.com/" rel="noopener noreferrer"&gt;Ollama&lt;/a&gt;&lt;/strong&gt;. Comme beaucoup de devs, je jonglais avec les quotas gratuits des géants du Cloud dans mon IDE. Puis, la curiosité m'a piqué avant que je ne sorte ma carte bleue : est-ce qu'on peut vraiment faire tourner un "cerveau" de classe mondiale sur un MacBook Pro M1 Pro de base en 2026 ?&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;1. La simplicité de l'installation&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Installer Ollama, c'est presque trop facile. Une commande, et boum : vous avez une IA dans votre terminal. Pas de compte, pas de clé API, pas de carte bancaire.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq4960bgmaz1asbcf577i.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq4960bgmaz1asbcf577i.webp" alt="Installer Ollama est très simple" width="800" height="453"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;2. DeepSeek, Qwen, Mistral... Quel "cerveau" choisir ?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Avant de lancer mon premier prompt, j'ai dû fouiller dans la bibliothèque. En 2026, trois familles dominent le marché :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Qwen (Alibaba) :&lt;/strong&gt; L'architecte du "Clean Code". Brillant avec React et Tailwind, il produit un code élégant et suit les meilleures pratiques.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DeepSeek :&lt;/strong&gt; Le "Sniper" de la logique. Redoutable pour les algorithmes complexes et le pur back-end.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mistral (France) &amp;amp; Llama (Meta) :&lt;/strong&gt; Les piliers. &lt;strong&gt;Mistral&lt;/strong&gt; est une superbe alternative européenne polyvalente, tandis que &lt;strong&gt;Llama&lt;/strong&gt; reste le couteau suisse universel de l'Open Source.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;2 bis. C’est quoi un "B" ? (Comprendre la taille du cerveau)&lt;/strong&gt;&lt;br&gt;
On voit des étiquettes partout : &lt;strong&gt;4B, 7B, 32B&lt;/strong&gt;. Le "B" signifie &lt;strong&gt;Billion (milliard)&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Le chiffre :&lt;/strong&gt; C'est le nombre de paramètres (connexions neuronales) de l'IA. Plus il est élevé, plus l'IA est "éduquée".&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;L'empreinte RAM :&lt;/strong&gt; En 2026, grâce à la "quantization" (compression), un modèle 1B consomme environ 0,8 Go de RAM. Un 4B prend ~3,5 Go. Un 32B engloutit ~20 Go... juste pour exister dans votre mémoire !&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;💡 Attendez, comment un modèle 9B tient dans 7,80 Go ? Tout est question de Quantification (précisément le format 4-bit ou Q4_K_M). C'est comme transformer une photo RAW ultra-lourde en un JPEG de haute qualité : on perd un tout petit peu de précision, mais on gagne une vitesse folle et un poids plume en mémoire.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;3. ⚠️ Le disclaimer "Claude Code" (Différence Agent VS Modèle)&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;On le voit partout en ce moment : &lt;em&gt;"Utilisez Claude gratuitement via Ollama !"&lt;/em&gt;. &lt;strong&gt;C'est à moitié vrai.&lt;/strong&gt; Claude Code est un outil génial (un agent en ligne de commande), mais ce n'est qu'une interface.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Par défaut, il se connecte aux modèles payants d'Anthropic (&lt;strong&gt;Sonnet, Opus, Haiku&lt;/strong&gt;).&lt;/li&gt;
&lt;li&gt;On peut le "brancher" sur Ollama (ex: &lt;code&gt;claude --model qwen3-coder&lt;/code&gt;). C'est gratuit et privé, vous profitez de l'ergonomie de Claude avec le cerveau de votre modèle local.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;4. Le mur de la réalité : Latence "Matrix" 🐌&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Pensant bien faire, j'ai chargé un &lt;strong&gt;Qwen 3 32B&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Le Crash :&lt;/strong&gt; Mon Mac a figé. L'IA mettait &lt;strong&gt;des minutes&lt;/strong&gt; pour sortir un seul mot.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Le coupable :&lt;/strong&gt; Mon système (Chrome, VS Code, Teams) occupait déjà &lt;strong&gt;20 Go&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Le calcul fatal :&lt;/strong&gt; 20 Go (Système) + 20 Go (IA) = &lt;strong&gt;40 Go&lt;/strong&gt;. Sur ma machine de 32 Go, le Mac a dû utiliser le SSD (&lt;strong&gt;Swap&lt;/strong&gt;). Résultat : une lenteur insupportable.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;J'ai essayé de coupler ça avec &lt;strong&gt;Roo Code&lt;/strong&gt; sur VS Code, mais chaque instruction envoyait trop de tokens de contexte. La RAM a saturé instantanément. C'est frustrant quand on est habitué à la réactivité instantanée du Cloud.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;5. L'art du compromis : "Découper" son setup&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Après avoir failli perdre patience, j'ai pivoté vers une approche hybride :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Qwen 2.5-coder 1.5B :&lt;/strong&gt; Pour l'auto-complétion (instantané).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Qwen 3.5 4B :&lt;/strong&gt; Mon "daily driver". C'est le &lt;strong&gt;Sweet Spot&lt;/strong&gt; pour 32 Go : il laisse assez de place à macOS pour respirer tout en restant très pertinent.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;💡 Conseil de pro :&lt;/strong&gt; Utiliser un petit modèle demande de &lt;strong&gt;réapprendre à prompter&lt;/strong&gt;. Les IA du Cloud "lisent entre les lignes" et devinent vos intentions vagues. &lt;strong&gt;En local avec un 4B, cette magie n'existe pas&lt;/strong&gt;. Il faut redevenir un artisan du prompt : précis, concis et structuré.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;📥 UPDATE : La surprise du lendemain (Le test du modèle 9B)&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Juste au moment où je pensais m'arrêter sur le 4B, j'ai tenté un démarrage à froid ce matin avec &lt;strong&gt;Qwen 3.5 9B&lt;/strong&gt;. Avec une RAM "propre" (pas de Docker, pas 50 onglets Chrome), la différence était flagrante : &lt;strong&gt;des réponses en moins de 10 secondes&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Le 9B semble être le vrai "Sweet Spot Pro" pour une machine de 32 Go (avec 20Go déjà occupés) :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Le calcul RAM :&lt;/strong&gt; Lors de mon test, le modèle 9B occupe exactement &lt;strong&gt;7,80 Go&lt;/strong&gt;. Sur un Mac de 32 Go, c'est parfaitement gérable si votre système n'est pas déjà saturé.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;L'expérience :&lt;/strong&gt; On a l'impression d'avoir le Copilot d'il y a quelques années. Il ne va pas encore refactoriser toute votre structure de fichiers tout seul, mais la logique est aiguisée et les blocs de code sont réellement prêts pour la prod.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Le revers de la médaille :&lt;/strong&gt; Cela demande une certaine discipline. On ne peut pas faire tourner un gros stack de dev et un modèle 9B simultanément sur 32 Go sans que ça commence à chauffer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Conclusion ?&lt;/strong&gt; Le 4B est votre "filet de sécurité" pour le multitâche intensif, mais le 9B est votre compagnon de "Deep Work" quand vous pouvez lui donner l'espace nécessaire pour respirer.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;6. L'outil indispensable : Can I Run AI&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Une découverte qui sauve la vie : &lt;a href="https://www.canirun.ai/" rel="noopener noreferrer"&gt;canirun.ai&lt;/a&gt;. Ce site simule la consommation de RAM d'un modèle en fonction de votre matériel avant même de le télécharger. C'est un passage obligé avant chaque &lt;code&gt;ollama pull&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;🦀 L'étape d'après : L'IA "Agentic" (OpenClaw)&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Pendant que je rédigeais ce retour d'expérience, j'ai poussé la réflexion jusqu'aux agents autonomes comme &lt;strong&gt;&lt;a href="https://openclaw.ai/" rel="noopener noreferrer"&gt;OpenClaw&lt;/a&gt;&lt;/strong&gt;, qui promettent d'automatiser vos tâches (mails, calendrier, scripts) directement depuis votre terminal. Mais attention : ici, la "coquille" est vide et le dilemme de la RAM se corse.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Le paradoxe de la vie privée :&lt;/strong&gt; Jusqu'ici, j'acceptais d'utiliser le Cloud pour des requêtes isolées. Mais donner un accès complet à mon système à un agent distant ? À l'heure où &lt;strong&gt;GitHub Copilot annonce utiliser par défaut vos prompts et contextes pour entraîner ses modèles&lt;/strong&gt;, l'ironie est totale. Confier l'intégralité de son contexte local à un tiers pour gagner dix minutes par jour devient un pari... audacieux.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Le prix de la liberté :&lt;/strong&gt; L'alternative est d'injecter une IA locale dans l'agent. Mais faire cohabiter l'infrastructure de l'agent + le modèle 9B + votre IDE sur &lt;strong&gt;32 Go de RAM&lt;/strong&gt; relève de l'exercice d'équilibriste. C'est le prix de la propriété de son code.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;🏁 Verdict : L'avenir est-il hybride ?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;J'ai réussi à faire coder un composant React complexe par mon petit modèle 9B. C'était fluide, propre et &lt;strong&gt;100% privé&lt;/strong&gt;. Mais soyons honnêtes un instant :&lt;/p&gt;

&lt;p&gt;Si vous avez été bluffés par la vitesse et la capacité de "lecture de pensée" de &lt;strong&gt;Claude Sonnet&lt;/strong&gt; ou &lt;strong&gt;Gemini Pro&lt;/strong&gt;, faire tourner une IA locale sur 32 Go de RAM donne encore un petit sentiment... de retour en arrière.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Intelligence :&lt;/strong&gt; Un 9B local est un super stagiaire. &lt;strong&gt;Claude&lt;/strong&gt; reste l'Architecte Senior.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vitesse &amp;amp; Confort :&lt;/strong&gt; La friction de la gestion de la RAM et les prompts qui doivent être plus "mâchés" font que l'expérience Cloud reste imbattable pour la productivité pure.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pour pousser le trait :&lt;/strong&gt; Parfois, je me surprends même à douter de la réponse de l'IA locale. J'ai presque envie de demander à Claude de vérifier la réponse de Qwen pour être sûr 🙃.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;del&gt;&lt;strong&gt;Est-ce que je vais continuer à utiliser mon Qwen 3.5 en local ?&lt;/strong&gt; Oui, mais surtout par curiosité, pour repousser ses limites et voir ce qu'il a dans le ventre. Mais pour mon travail de développement quotidien intensif ? Le confort, la vitesse et la pure intelligence d'une IA Cloud reste imbattable.&lt;/del&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;📥 Mise à jour depuis le succès du 9B&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Est-ce que je vais continuer à utiliser mon Qwen 3.5 en local ?&lt;/strong&gt; Absolument. Depuis que j'ai vu à quel point le modèle 9B tourne bien, je suis bien plus tenté de l'utiliser pour &lt;strong&gt;les tâches routinières du quotidien&lt;/strong&gt;. C'est parfait pour des checks de logique rapides ou du code boilerplate. Cependant, pour les sessions de "Gros Dev" qui demandent un raisonnement profond et une vision architecturale massive, je repasserai sur le Cloud.&lt;/p&gt;

&lt;p&gt;En 2026, la RAM est la nouvelle puissance CPU. Tant que je n'aurai pas 128 Go de mémoire unifiée sur mon bureau, les modèles massifs du Cloud restent indétrônables.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Et vous ? C’est quoi votre "Sweet Spot" ? Vous jouez la carte du local pour la vie privée, ou le Cloud reste votre seul co-pilote ?&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>french</category>
      <category>ai</category>
      <category>opensource</category>
      <category>productivity</category>
    </item>
    <item>
      <title>🚀 Local AI in 2026: My Journey Through the Desert (From Terminal to GPU)</title>
      <dc:creator>Quentin Merle</dc:creator>
      <pubDate>Mon, 23 Mar 2026 15:37:05 +0000</pubDate>
      <link>https://forem.com/quentin_merle/local-ai-in-2026-my-journey-through-the-desert-from-terminal-to-gpu-k35</link>
      <guid>https://forem.com/quentin_merle/local-ai-in-2026-my-journey-through-the-desert-from-terminal-to-gpu-k35</guid>
      <description>&lt;p&gt;🌐 Version française ici : &lt;a href="https://dev.to/quentin_merle/lia-locale-en-2026-ma-traversee-du-desert-du-terminal-au-gpu-2d0o"&gt;L'IA locale en 2026 : Ma traversée du désert&lt;/a&gt;&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Disclaimer &amp;amp; Context:&lt;/strong&gt; This article is based on my personal experience using a MacBook Pro M1 Pro with 32GB of RAM and VS Code. While I use Claude as the primary reference for Cloud AI (given its current leadership in coding tasks), the same logic applies to other giants like Gemini or ChatGPT when comparing Cloud performance vs. Local efficiency.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;&lt;strong&gt;The Starting Point: "Is Local AI actually good? And is it a pain to set up?"&lt;/strong&gt;&lt;br&gt;
A few weeks ago, I knew nothing about &lt;strong&gt;&lt;a href="https://ollama.com/" rel="noopener noreferrer"&gt;Ollama&lt;/a&gt;&lt;/strong&gt;. Like many devs, I was just juggling free quotas from the cloud giants in my IDE. Then, curiosity hit me before I reached for my credit card: can you actually run a world-class "brain" on a base MacBook Pro M1 Pro (32GB) in 2026?&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;1. The Installation Shock (Pure Euphoria)&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Installing Ollama is almost too easy. One command, and boom: you have an AI in your terminal. No account, no API key, no credit card.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6g7den1hhecu9cq47mj0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6g7den1hhecu9cq47mj0.png" alt="Install Ollama is the easy part" width="800" height="453"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;2. DeepSeek, Qwen, Mistral... Which "Brain" Should You Pick?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Before hitting my first prompt, I had to dig through the library. In 2026, three families dominate the game:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Qwen (Alibaba):&lt;/strong&gt; The "Clean Code" architect. Brilliant with React and Tailwind, it produces elegant code and follows best practices.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DeepSeek:&lt;/strong&gt; The logic "Sniper." Formidable for complex algorithms and pure backend tasks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mistral (France) &amp;amp; Llama (Meta):&lt;/strong&gt; The pillars. &lt;strong&gt;Mistral&lt;/strong&gt; is a superb, versatile European alternative, while &lt;strong&gt;Llama&lt;/strong&gt; remains the universal Swiss Army knife of Open Source.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;2 bis. What’s a "B"? (Understanding Brain Size)&lt;/strong&gt;&lt;br&gt;
You see labels everywhere like &lt;strong&gt;4B&lt;/strong&gt;, &lt;strong&gt;7B&lt;/strong&gt;, &lt;strong&gt;32B&lt;/strong&gt;. The "B" stands for &lt;strong&gt;Billion&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Number:&lt;/strong&gt; It’s the number of parameters (neural connections) in the AI. The higher the number, the more "educated" the AI is.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The RAM Footprint:&lt;/strong&gt; In 2026, thanks to "quantization", a &lt;strong&gt;1B&lt;/strong&gt; model consumes about &lt;strong&gt;0.8GB of RAM&lt;/strong&gt;.

&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;4B&lt;/strong&gt; model takes up ~3.5GB.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;32B&lt;/strong&gt; model eats ~20GB... just to exist in your memory!&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;💡 Wait, how does a 9B model fit into 7.80GB? It’s all about Quantization (specifically 4-bit or Q4_K_M). It’s like turning a heavy RAW image into a high-quality JPEG: you lose a tiny bit of precision, but you gain massive speed and a much smaller memory footprint.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;3. ⚠️ The "Claude Code" Disclaimer (Don’t Get Fooled)&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;You see it everywhere right now: &lt;em&gt;"Use Claude for free via Ollama!"&lt;/em&gt;. &lt;strong&gt;That's only half true.&lt;/strong&gt; Claude Code is a great tool (an agentic CLI), but it's just an interface.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;By default, it connects to Anthropic's paid models (&lt;strong&gt;Sonnet, Opus, Haiku&lt;/strong&gt;).&lt;/li&gt;
&lt;li&gt;You can "plug" it into Ollama (e.g., &lt;code&gt;claude --model qwen3-coder&lt;/code&gt;). It’s free and private, but you get the Claude UX with your local model's brain.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;4. The Reality Wall: "Matrix" Latency 🐌&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Thinking I was doing the right thing, I loaded a &lt;strong&gt;Qwen 3 32B&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Crash:&lt;/strong&gt; My Mac froze. The AI took &lt;strong&gt;minutes&lt;/strong&gt; to output a single word.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Culprit:&lt;/strong&gt; My system (Chrome, VS Code, Teams) was already hogging &lt;strong&gt;20GB&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Fatal Math:&lt;/strong&gt; 20GB (System) + 20GB (AI) = &lt;strong&gt;40GB&lt;/strong&gt;. On my 32GB RAM machine, the Mac had to use the SSD (&lt;strong&gt;Swap&lt;/strong&gt;). Result: unbearable slowness.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;I tried pairing this with &lt;strong&gt;Roo Code&lt;/strong&gt; (an open-source, AI-powered coding assistant) on VS Code, but every instruction sent too many context tokens. The RAM saturated instantly. It’s frustrating when you're used to the instant reactivity of the Cloud.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;5. The Art of Compromise: "Slicing" Your Setup&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;After nearly losing my mind, I pivoted to a hybrid approach:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Qwen 2.5-coder 1.5B:&lt;/strong&gt; For autocomplete (instant).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Qwen 3.5 4B:&lt;/strong&gt; My "daily driver." This is the &lt;strong&gt;Sweet Spot&lt;/strong&gt; for 32GB: it leaves enough room for macOS to breathe while remaining highly relevant.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;💡 Pro Tip:&lt;/strong&gt; Using a smaller model requires &lt;strong&gt;re-learning how to prompt&lt;/strong&gt;. Cloud AIs "read between the lines" and guess your vague intentions. &lt;strong&gt;In local with a 4B, that magic doesn't exist.&lt;/strong&gt; You have to become a prompt craftsman again: be precise, concise, and structured.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;📥 UPDATE: The "Morning Surprise" (Testing the 9B Model)&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Just when I thought I was settled on the 4B model, I tried a fresh boot this morning with &lt;strong&gt;Qwen 3.5 9B&lt;/strong&gt;. With "clean" RAM (no Docker, no 50 Chrome tabs), the difference was night and day: &lt;strong&gt;Responses in under 10 seconds&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The 9B feels like the true "Pro" sweet spot for a 32GB machine:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The RAM Math:&lt;/strong&gt; In my test, the 9B model takes up exactly &lt;strong&gt;7.80GB of RAM&lt;/strong&gt;. On a 32GB Mac, this is perfectly manageable if your system isn't already saturated.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Experience:&lt;/strong&gt; It feels like the high-end Copilot we had a few years ago. It won’t automatically refactor your entire file structure yet, but the logic is sharp, and the code blocks are actually production-ready.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Catch:&lt;/strong&gt; It requires a disciplined environment. You can't run a heavy dev stack and a 9B model simultaneously on 32GB without feeling the heat.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Final takeaway?&lt;/strong&gt; The 4B is your "safety net" for heavy multitasking, but the 9B is your "deep work" companion when you can afford to give it the room it needs to breathe.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;6. The Essential Tool: Can I Run AI&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;A life-saving discovery: &lt;a href="https://www.canirun.ai/" rel="noopener noreferrer"&gt;canirun.ai&lt;/a&gt;. This site simulates the RAM consumption of a model based on your hardware before you download it. It’s a mandatory stop before every &lt;code&gt;ollama pull&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;🦀 The Next Frontier: "Agentic" AI (OpenClaw)&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;While I was writing this review, I pushed my research into autonomous agents like &lt;strong&gt;&lt;a href="https://openclaw.ai/" rel="noopener noreferrer"&gt;OpenClaw&lt;/a&gt;&lt;/strong&gt;, which promise to automate your tasks (emails, calendar, scripts) directly from your terminal. But beware: here, the "shell" is empty, and the RAM dilemma gets even tougher.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Privacy Paradox:&lt;/strong&gt; Until now, I was okay with using the Cloud for isolated queries. But giving full system access to a remote agent? At a time when &lt;strong&gt;GitHub Copilot has just announced that, starting April 24, your prompts and contexts will be used by default to train their models&lt;/strong&gt;, the irony is peak. Handing over your entire local context to a third party just to save ten minutes a day is... a bold bet.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Price of Freedom:&lt;/strong&gt; The alternative is to inject a &lt;strong&gt;Local AI&lt;/strong&gt; into the agent. This is total sovereignty: what happens on the Mac stays on the Mac.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Balancing Act:&lt;/strong&gt; But freedom comes at a hardware cost. Running the agent infrastructure (Node.js/Docker) + the 9B model + your IDE on &lt;strong&gt;32GB of RAM&lt;/strong&gt; is a high-wire act. That's the literal price of owning your code.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;🏁 Verdict: Is the Future Hybrid?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;I managed to have my little 9B model code a complex React component. It was smooth, clean, and &lt;strong&gt;100% private&lt;/strong&gt;. But let’s be honest for a second:&lt;/p&gt;

&lt;p&gt;If you’ve been spoiled by the speed and "mind-reading" capabilities of &lt;strong&gt;Claude Sonnet&lt;/strong&gt; or &lt;strong&gt;Gemini Pro&lt;/strong&gt;, running local AI on a 32GB machine still feels a bit... outdated. It’s like switching back to a manual car after years of driving an automatic.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Intelligence:&lt;/strong&gt; A local 9B is a great intern. &lt;strong&gt;Claude&lt;/strong&gt; remains the Senior Architect.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Speed &amp;amp; Comfort:&lt;/strong&gt; The sheer friction of managing your RAM and dealing with slightly "dumber" prompts makes the Cloud experience unbeatable for pure productivity.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;To put it bluntly:&lt;/strong&gt; Sometimes, I even find myself doubting the local AI's output. To stretch the point, I almost feel the urge to ask Claude to double-check Qwen's answer just to be sure 🙃.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;del&gt;&lt;strong&gt;Will I keep using my local Qwen 3.5?&lt;/strong&gt; Yes, but mostly out of curiosity—to push its limits and see what it has in its gut. But for my heavy-duty daily dev work? The comfort, speed, and sheer brilliance of a Cloud AI aren't going anywhere.&lt;/del&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;📥 Update since 9b run well&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Will I keep using my local Qwen 3.5?&lt;/strong&gt; Definitely. Since discovering how well the 9B model runs, I’m much more tempted to use it for &lt;strong&gt;everyday, routine tasks&lt;/strong&gt;. It’s perfect for quick logic checks or boilerplate code. However, for "Heavy Dev" sessions that require deep reasoning and a massive architectural vision, I’ll still switch back to Cloud AI.&lt;/p&gt;

&lt;p&gt;In 2026, RAM is the new CPU power. Until I have 128GB of Unified Memory on my desk, the giants still own the crown.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What about you? What’s your "Sweet Spot"? Are you playing the local card for privacy, or is the Cloud still your only co-pilot?&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>ollama</category>
      <category>productivity</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Cabin Analytics: Ditch the Cookie Banner and Embrace Ethical Tracking</title>
      <dc:creator>Quentin Merle</dc:creator>
      <pubDate>Fri, 20 Feb 2026 15:26:42 +0000</pubDate>
      <link>https://forem.com/quentin_merle/cabin-analytics-ditch-the-cookie-banner-and-embrace-ethical-tracking-a51</link>
      <guid>https://forem.com/quentin_merle/cabin-analytics-ditch-the-cookie-banner-and-embrace-ethical-tracking-a51</guid>
      <description>&lt;p&gt;While browsing the website of &lt;strong&gt;&lt;a href="https://www.mightybytes.com/" rel="noopener noreferrer"&gt;MightyBytes&lt;/a&gt;&lt;/strong&gt;—the agency behind the famous &lt;strong&gt;&lt;a href="https://ecograder.com/" rel="noopener noreferrer"&gt;Ecograder&lt;/a&gt;&lt;/strong&gt; and a true authority in digital sustainability—I noticed an interesting detail in their stack: they use &lt;strong&gt;&lt;a href="https://withcabin.com/" rel="noopener noreferrer"&gt;Cabin Analytics&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Intrigued by this choice from Green IT experts, I decided to give it a spin. Here’s why I believe it’s a serious contender for your next projects, especially if you’re tired of forcing intrusive consent banners on your users.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Privacy First: Ending "Consent Fatigue"
&lt;/h2&gt;

&lt;p&gt;Cabin’s core strength is being &lt;strong&gt;privacy-first by design&lt;/strong&gt;. Unlike traditional tracking methods, Cabin uses zero cookies and collects no Personally Identifiable Information (PII).&lt;br&gt;
&lt;strong&gt;Why is this a game-changer?&lt;/strong&gt; Because according to their documentation and GDPR (&lt;em&gt;CCPA, PIPEDA etc…&lt;/em&gt;) frameworks, the absence of individual tracking means you can &lt;strong&gt;completely remove your cookie consent banner&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;VS Google Analytics (GA4):&lt;/strong&gt; GA4 remains a complex "black box" that frequently faces scrutiny from data protection authorities (like the CNIL in France) due to transatlantic data transfers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;VS Matomo:&lt;/strong&gt; While Matomo is a great alternative, it requires very specific and rigorous configuration to be legally exempt from consent.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With Cabin, compliance is the starting point, not a configuration option. The result? A cleaner UX and higher data accuracy, as you no longer lose stats from users who (rightfully) block or decline tracking.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnvhixoxyg12byl72h10z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnvhixoxyg12byl72h10z.png" alt="Cabin homepage screenshot" width="800" height="453"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  2. Performance &amp;amp; Sustainability: 1.5 KB for your Web Vitals
&lt;/h2&gt;

&lt;p&gt;In a world where page weight is exploding, every kilobyte counts. This is where Cabin shines through digital sobriety. Its script is ultra-lightweight: approximately &lt;strong&gt;1.5 KB&lt;/strong&gt;.&lt;br&gt;
To put that in perspective, that’s practically the weight of a favicon. Cabin doesn't just stay light; it actively helps you measure your site's carbon footprint directly from its dashboard.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Google Analytics:&lt;/strong&gt; Often exceeds &lt;strong&gt;50 KB&lt;/strong&gt;. That’s significant dead weight that can negatively impact your LCP (Largest Contentful Paint) score.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Matomo:&lt;/strong&gt; Expect between &lt;strong&gt;20 and 30 KB&lt;/strong&gt;. Better, but still nowhere near Cabin’s featherweight status.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By choosing such a lean tool, you’re not only boosting your SEO performance but also reducing the energy consumed by your visitors' devices.&lt;/p&gt;
&lt;h2&gt;
  
  
  3. Simplicity vs. Complexity: Getting Back to Basics
&lt;/h2&gt;

&lt;p&gt;We often install Google Analytics out of habit, only to use 5% of its features. GA4 has become a "bloatware" ecosystem filled with AI and complex predictive reports. Matomo, on the other hand, offers impressive power (Heatmaps, A/B Testing) that can feel intimidating for a simple project.&lt;/p&gt;

&lt;p&gt;Cabin takes a radically different approach: a &lt;strong&gt;single, unified dashboard&lt;/strong&gt;. Everything is visual, clear, and accessible at a glance:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unique visitors and page views.&lt;/li&gt;
&lt;li&gt;Traffic sources and localization.&lt;/li&gt;
&lt;li&gt;Device types and browsers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Don't let the simplicity fool you: Cabin handles event tracking (clicks, form submissions) and campaign parameters (UTMs) out-of-the-box, allowing you to track conversions without cluttering your code with complex logic. See &lt;a href="https://docs.withcabin.com/" rel="noopener noreferrer"&gt;docs&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- HTML --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"menu.pdf"&lt;/span&gt; &lt;span class="na"&gt;data-cabin-event=&lt;/span&gt;&lt;span class="s"&gt;"Download Menu"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Download Menu&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Javascript&lt;/span&gt;
&lt;span class="nx"&gt;cabin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;event&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Download Menu&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Setup takes exactly 30 seconds. No complex container configurations or endless Tag Manager triggers. You just need to drop this snippet into your site's &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; section:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;async&lt;/span&gt; &lt;span class="na"&gt;defer&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://scripts.withcabin.com/hello.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s it. No additional configuration is required to start seeing your first real-time metrics roll in.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion: Which one belongs in your stack?
&lt;/h2&gt;

&lt;p&gt;Choosing your analytics tool shouldn't be a default choice; it should be a decision based on your project's actual needs.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Choose &lt;strong&gt;Cabin Analytics&lt;/strong&gt; if you prioritize speed, eco-design, and a beautiful, "no-nonsense" interface. It’s the perfect candidate for blogs, portfolios, and ethical landing pages.
Cabin follows a transparent and sustainable model. The Free tier is perfect for starting out, allowing 1 website with a 30-day data retention and data export.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;If you're scaling, the Pro version removes all limits: unlimited websites &amp;amp; data retention, weekly email reports, custom subdomains, custom events and CO₂ reporting.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;Choose &lt;strong&gt;Matomo&lt;/strong&gt; if you need total control over your data (self-hosting) and advanced marketing features.&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;Google Analytics&lt;/strong&gt; if your business model relies heavily on the Google Ads ecosystem and requires complex cross-channel tracking.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are also other serious challengers like &lt;a href="https://plausible.io/" rel="noopener noreferrer"&gt;Plausible&lt;/a&gt;, &lt;a href="https://usefathom.com/" rel="noopener noreferrer"&gt;Fathom&lt;/a&gt;, or the excellent &lt;a href="https://pirsch.io/" rel="noopener noreferrer"&gt;Pirsch.io&lt;/a&gt; that I haven’t had the chance to fully stress-test yet, but they all share this same philosophy of user respect.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Are you ready to delete your cookie banner in favor of a leaner, greener approach?&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>privacy</category>
      <category>performance</category>
      <category>greenit</category>
    </item>
    <item>
      <title>Javascript in 2026: 11 Under-the-Radar Browser APIs</title>
      <dc:creator>Quentin Merle</dc:creator>
      <pubDate>Mon, 16 Feb 2026 13:24:42 +0000</pubDate>
      <link>https://forem.com/quentin_merle/javascript-in-2026-11-under-the-radar-browser-apis-27gh</link>
      <guid>https://forem.com/quentin_merle/javascript-in-2026-11-under-the-radar-browser-apis-27gh</guid>
      <description>&lt;p&gt;The other day, I was chatting with a friend about retrieving request data for a script outside the main project without re-triggering a &lt;code&gt;fetch&lt;/code&gt;. We hit a wall: &lt;strong&gt;how do we do this cleanly?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;After some digging, I stumbled upon &lt;code&gt;Cache.match()&lt;/code&gt; on MDN. It was exactly what we needed. It reminded me of something we all face: &lt;em&gt;the "comfort zone" trap&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;We often code by reflex or to save time (which isn't a bad thing), but we forget that browsers are evolving fast. Here is a selection of native APIs that are worth your attention in 2026.&lt;/p&gt;

&lt;h2&gt;
  
  
  📦 &lt;strong&gt;Replacing Dependencies&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Intl.RelativeTimeFormat&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;Replaces: dayjs, moment.js&lt;/em&gt;&lt;br&gt;
&lt;a href="https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Global_Objects/Intl/RelativeTimeFormat" rel="noopener noreferrer"&gt;MDN Documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This API turns raw data into human-readable phrases.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rtf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Intl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;RelativeTimeFormat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;numeric&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;auto&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;// 'auto' enables phrases like "yesterday" instead of "1 day ago"&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;formatRelative&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;diffInMs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;date&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;now&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// Convert milliseconds to days&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;diffInDays&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;diffInMs&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;rtf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;diffInDays&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;day&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Tests&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;yesterday&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;yesterday&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setDate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;yesterday&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getDate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;longAgo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;longAgo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setDate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;longAgo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getDate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;formatRelative&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;yesterday&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// "yesterday" (thanks to numeric: 'auto')&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;formatRelative&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;longAgo&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;   &lt;span class="c1"&gt;// "5 days ago"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; it doesn’t calculate the units for you (yet—wait for the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal" rel="noopener noreferrer"&gt;Temporal API&lt;/a&gt; to be fully stable). You need to tell it if you’re dealing with minutes, hours, etc.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rtf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Intl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;RelativeTimeFormat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;numeric&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;auto&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Define thresholds in seconds&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;UNITS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;unit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;month&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="na"&gt;seconds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2592000&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;unit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;day&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="na"&gt;seconds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;86400&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;unit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hour&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="na"&gt;seconds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3600&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;unit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;minute&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;seconds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;unit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;second&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;seconds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;formatAutoRelative&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;diffInSeconds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Find the unit corresponding to the first threshold reached&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;unit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;seconds&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;UNITS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;diffInSeconds&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nx"&gt;seconds&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;unit&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;second&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;diffInSeconds&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;seconds&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;rtf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;unit&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// --- Tests ---&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;formatAutoRelative&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;       &lt;span class="c1"&gt;// "5 seconds ago"&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;formatAutoRelative&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;3600000&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;    &lt;span class="c1"&gt;// "1 hour ago"&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;formatAutoRelative&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;86400000&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;   &lt;span class="c1"&gt;// "tomorrow"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;Pro-tip:&lt;/strong&gt; Couple it with &lt;code&gt;Intl.DateTimeFormat&lt;/code&gt; for a "fallback" strategy. If the delay exceeds 7 days, switch from relative time to a full date.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;&lt;strong&gt;2. structuredClone()&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;Replaces: &lt;code&gt;lodash.cloneDeep&lt;/code&gt;, &lt;code&gt;JSON.parse(JSON.stringify(obj))&lt;/code&gt;&lt;/em&gt;&lt;br&gt;
&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/structuredClone" rel="noopener noreferrer"&gt;MDN Documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The JSON method is what we call "lossy cloning." It works for simple objects but destroys anything it doesn't understand (Dates, Maps, Sets, RegEx).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;original&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;([[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;key&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;value&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]]),&lt;/span&gt;
  &lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
  &lt;span class="na"&gt;regex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/hello/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;undefinedVal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// ❌ BEFORE (Hack JSON)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fakeClone&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;original&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fakeClone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// "2026-02-10T..." (Converted to a STRING, not a Date object anymore!)&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fakeClone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// {} (Empty, Maps are lost)&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fakeClone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;regex&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// {} (Lost)&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fakeClone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;undefinedVal&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Gone (the key no longer exists)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;original&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;([[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;key&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;value&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]]),&lt;/span&gt;
  &lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
  &lt;span class="na"&gt;regex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/hello/g&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// ✅ NOW (2026 Standard)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;realClone&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;structuredClone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;original&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;realClone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// true&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;realClone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;key&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;       &lt;span class="c1"&gt;// "value"&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;realClone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;regex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hello&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;  &lt;span class="c1"&gt;// true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; It won’t clone functions or DOM elements, as they are bound to their execution context.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  ⚡ &lt;strong&gt;Mastering Data Flow&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;3. AbortController&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://developer.mozilla.org/fr/docs/Web/API/AbortController" rel="noopener noreferrer"&gt;MDN Documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Think of this as the "Emergency Stop" button for your code. If a user frantically clicks a "Category" filter, without AbortController, you fire X fetch requests. Even if you only display the last one, the previous ones still consume bandwidth and CPU in the background.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;currentController&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fetchData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// 1. Cancel the previous request if it exists&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentController&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;currentController&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;abort&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// 2. Create a new signal for the current request&lt;/span&gt;
  &lt;span class="nx"&gt;currentController&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;AbortController&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;currentController&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;signal&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;AbortError&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Silent, this is an intentional cancellation&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; It's versatile! You can use it with Event Listeners or setTimeout to clean up side effects.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;controller&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;AbortController&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Attach the signal to multiple events&lt;/span&gt;
&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;resize&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Resized&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;signal&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;scroll&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Scrolled&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;signal&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="c1"&gt;// To delete everything at once: controller.abort();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;strong&gt;4. BroadcastChannel&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://developer.mozilla.org/fr/docs/Web/API/BroadcastChannel" rel="noopener noreferrer"&gt;MDN Documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Allows different navigation contexts (tabs, windows, iframes) from the same origin to communicate in real-time without a server or complex localStorage hacks. Perfect for syncing a shopping cart or handling a global logout.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// --- Shared Logic ---&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cartChannel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BroadcastChannel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;shop_cart_sync&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// --- TAB A (The "Emitter") ---&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;addToCart&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// 1. Business Logic: save to localStorage for persistence&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cart&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;cart&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cart&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cart&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

  &lt;span class="c1"&gt;// 2. Update the UI of the current tab&lt;/span&gt;
  &lt;span class="nf"&gt;updateCartUI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cart&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// 3. Notify all other tabs instantly&lt;/span&gt;
  &lt;span class="nx"&gt;cartChannel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;postMessage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;CART_UPDATED&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cart&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;lastAdded&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// --- TAB B, C, D (The "Listeners") ---&lt;/span&gt;
&lt;span class="nx"&gt;cartChannel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onmessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;CART_UPDATED&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Update the cart counter in the header&lt;/span&gt;
    &lt;span class="nf"&gt;updateCartUI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Bonus: Show a little toast notification&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`An item (&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lastAdded&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;) was added from another tab!`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;Pro-tip:&lt;/strong&gt; In a SPA, always remember to close the channel when the component is unmounted: &lt;code&gt;bc.close();&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;&lt;strong&gt;5. Navigator.sendBeacon()&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://developer.mozilla.org/fr/docs/Web/API/Navigator/sendBeacon" rel="noopener noreferrer"&gt;MDN Documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;How do you send data to the server just before a user leaves the page? Standard fetch often fails because the browser kills the process before the request finishes. &lt;code&gt;sendBeacon()&lt;/code&gt; is asynchronous and guaranteed to finish in the background.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Prepare analytics data&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;analyticsData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;articleId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;123&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;timeSpent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;450&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;completion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.85&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Use visibilitychange event (more reliable than 'unload' in 2026)&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;visibilitychange&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;visibilityState&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hidden&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Convert data to Blob or FormData&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;blob&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Blob&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;analyticsData&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="c1"&gt;// The "fire and forget" magic&lt;/span&gt;
    &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendBeacon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/analytics&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;blob&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🎨 &lt;strong&gt;Performance &amp;amp; Native UI&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;6. Intersection Observer API&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://developer.mozilla.org/fr/docs/Web/API/Intersection_Observer_API" rel="noopener noreferrer"&gt;MDN Documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The ultimate tool for lazy-loading and scroll-based animations without killing your performance.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;data-src=&lt;/span&gt;&lt;span class="s"&gt;"high-res-photo.jpg"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"placeholder.jpg"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"lazy-load"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Description"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// 1. Configuration: trigger when 10% of the element is visible&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;root&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// use browser viewport&lt;/span&gt;
  &lt;span class="na"&gt;threshold&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.1&lt;/span&gt; 
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// 2. Observer creation&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;observer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;IntersectionObserver&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// If the element is within the viewport&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isIntersecting&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;img&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

      &lt;span class="c1"&gt;// Replace placeholder with the actual image&lt;/span&gt;
      &lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fade-in&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Adding a subtle, optional animation.&lt;/span&gt;

      &lt;span class="c1"&gt;// Once loaded, stop observing this image (performance gain)&lt;/span&gt;
      &lt;span class="nx"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unobserve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// 3. Start observing all "lazy" images&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.lazy-load&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;observe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;strong&gt;7. Cache.match()&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://developer.mozilla.org/fr/docs/Web/API/Cache/match" rel="noopener noreferrer"&gt;MDN Documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Need to share API data between two independent scripts without a global variable or a second network call? This is exactly how I solved my problem the other day.&lt;/p&gt;

&lt;p&gt;⚠️ &lt;strong&gt;Important Note:&lt;/strong&gt; Don't confuse this with standard HTTP caching. While the browser manages the "HTTP Cache" automatically via headers, the Cache API is entirely programmable. You are the one deciding exactly what to store, update, or delete.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Fetch and cache&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;fetchAndCacheConfig&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;caches&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-resources&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/user-config&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// We must clone the response because a response body can only be read once&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clone&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// No fetch, check if it is in cache&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getExistingData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;caches&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-resources&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Check if a request matching this URL exists in the cache&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cachedResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/user-config&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cachedResponse&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;cachedResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Data retrieved from cache with no new network call:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Cache miss: no data found.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Like most modern web APIs, this is only available in HTTPS contexts (and localhost)&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;&lt;strong&gt;8. DocumentFragment (Old but gold)&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;Specific to Vanilla JS or Web Components&lt;/em&gt;&lt;br&gt;
&lt;a href="https://developer.mozilla.org/fr/docs/Web/API/DocumentFragment" rel="noopener noreferrer"&gt;MDN Documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A lightweight, "off-screen" DOM container. Use it to batch DOM injections and avoid multiple expensive reflows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#ul-list&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fragment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createDocumentFragment&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Apple&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Pear&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Banana&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fruit&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;li&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;li&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;li&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fruit&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;fragment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;li&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// No rendering here yet&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fragment&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// A single reflow for all 3 elements!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🛠️ &lt;strong&gt;Dev Comfort &amp;amp; Debugging&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;9. console.table()&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://developer.mozilla.org/fr/docs/Web/API/console/table_static" rel="noopener noreferrer"&gt;MDN Documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Stop squinting at messy object logs. Use &lt;code&gt;console.table(data)&lt;/code&gt; for a clean, sortable grid in your devtools.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;10. URLSearchParams&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://developer.mozilla.org/fr/docs/Web/API/URLSearchParams" rel="noopener noreferrer"&gt;MDN Documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Stop using RegEx to parse URLs.&lt;br&gt;
&lt;code&gt;new URLSearchParams(window.location.search).get('id')&lt;/code&gt; is all you need.&lt;/p&gt;


&lt;h2&gt;
  
  
  🧪 &lt;strong&gt;The Experimental One&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;11. EyeDropper API&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/EyeDropper_API" rel="noopener noreferrer"&gt;MDN Documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Adding this one for the 'cool factor'.&lt;/strong&gt; A native color picker that can grab colors from anywhere on the user's screen—even outside the browser.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;pickColor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EyeDropper&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Not supported&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dropper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;EyeDropper&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;dropper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Opens the system color picker (magnifying glass)&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sRGBHex&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Ex: #ff0000&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Cancel&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The browser's &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API" rel="noopener noreferrer"&gt;Web API list&lt;/a&gt; is massive. I encourage you to browse it regularly.&lt;/p&gt;

&lt;p&gt;Which one is your favorite? Do you have any other native 'hidden gems'?&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>frontend</category>
      <category>performance</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
