[{"data":1,"prerenderedAt":346},["ShallowReactive",2],{"i-lucide:sun":3,"i-lucide:moon":8,"i-lucide:menu":10,"i-lucide:x":12,"i-social:linkedin":14,"i-social:github":17,"i-social:dailydev":21,"projet-theme-vscode":23,"projet-theme-vscode-autres":64,"i-lucide:chevron-right":340,"i-lucide:external-link":342,"i-lucide:check":344},{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":7},0,24,false,"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Ccircle cx=\"12\" cy=\"12\" r=\"4\"\u002F>\u003Cpath d=\"M12 2v2m0 16v2M4.93 4.93l1.41 1.41m11.32 11.32l1.41 1.41M2 12h2m16 0h2M6.34 17.66l-1.41 1.41M19.07 4.93l-1.41 1.41\"\u002F>\u003C\u002Fg>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":9},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":11},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 5h16M4 12h16M4 19h16\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":13},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M18 6L6 18M6 6l12 12\"\u002F>",{"left":4,"top":4,"width":15,"height":15,"rotate":4,"vFlip":6,"hFlip":6,"body":16},44.856,"\u003Cpath fill=\"currentColor\" d=\"M39.376,0a5.483,5.483,0,0,1,5.48,5.48v33.9a5.483,5.483,0,0,1-5.48,5.48H5.48A5.483,5.483,0,0,1,0,39.376V5.48A5.483,5.483,0,0,1,5.48,0h33.9ZM14.058,37.084V17.308H7.484V37.084Zm23.7,0V25.743c0-6.074-3.243-8.9-7.568-8.9a6.529,6.529,0,0,0-5.924,3.265v-2.8H17.7c.087,1.856,0,19.775,0,19.775h6.573V26.04a4.494,4.494,0,0,1,.217-1.6,3.6,3.6,0,0,1,3.372-2.4c2.377,0,3.33,1.814,3.33,4.471V37.084H37.76ZM10.815,7.773a3.426,3.426,0,1,0-.087,6.834h.042a3.428,3.428,0,1,0,.045-6.834Z\"\u002F>",{"left":4,"top":4,"width":18,"height":19,"rotate":4,"vFlip":6,"hFlip":6,"body":20},46.142,44.459,"\u003Cpath fill=\"currentColor\" d=\"M55.071,32a22.76,22.76,0,0,0-7.292,44.422c1.154.208,1.576-.5,1.576-1.1,0-.546-.021-1.975-.031-3.88-6.417,1.379-7.776-3.057-7.776-3.057a6.079,6.079,0,0,0-2.565-3.335c-2.091-1.419.154-1.389.154-1.389a4.825,4.825,0,0,1,3.533,2.352c2.06,3.483,5.4,2.481,6.715,1.9a4.829,4.829,0,0,1,1.463-3.047c-5.119-.576-10.506-2.531-10.506-11.264a8.739,8.739,0,0,1,2.369-6.113,8.107,8.107,0,0,1,.227-6.034s1.936-.615,6.345,2.332a22.227,22.227,0,0,1,11.556,0c4.408-2.948,6.334-2.332,6.334-2.332a8.107,8.107,0,0,1,.227,6.034A8.775,8.775,0,0,1,69.769,53.6c0,8.753-5.4,10.679-10.536,11.244A5.418,5.418,0,0,1,60.8,69.058c0,3.047-.031,5.508-.031,6.252,0,.605.412,1.32,1.586,1.092A22.747,22.747,0,0,0,55.071,32Z\" transform=\"translate(-32 -32)\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":22},"\u003Cpath fill=\"currentColor\" d=\"M18.29 5.706a1.405 1.405 0 0 0-1.987 0L4.716 17.296l1.324-2.65-2.65-2.649 3.312-3.311 2.65 2.65 1.986-1.988-3.642-3.642a1.405 1.405 0 0 0-1.987 0L.411 11.004a1.404 1.404 0 0 0 0 1.987l4.305 4.304.993.993a1.405 1.405 0 0 0 1.987 0L19.285 6.7l-.993-.994Zm-.332 3.647 2.65 2.65-4.306 4.305a1.404 1.404 0 1 0 1.986 1.986l5.299-5.298a1.404 1.404 0 0 0 0-1.987l-4.305-4.304-1.324 2.648Z\"\u002F>",{"id":24,"title":25,"body":26,"context":40,"contributions":41,"cover":44,"coverAlt":45,"description":32,"extension":46,"featured":47,"links":48,"meta":50,"navigation":47,"order":51,"outcome":52,"path":53,"period":54,"role":55,"seo":56,"stack":57,"status":60,"stem":61,"summary":62,"__hash__":63},"projets\u002Fprojets\u002Ftheme-vscode.md","Dark Theme The New",{"type":27,"value":28,"toc":36},"minimark",[29,33],[30,31,32],"p",{},"Le thème tient dans un fichier JSON de quelques centaines de lignes.\nL'essentiel du travail a consisté à décider quoi colorer : un mot-clé, un nom\nde variable et un commentaire ne se lisent pas avec la même attention, et la\ncouleur est le principal levier pour le signaler.",[30,34,35],{},"Le parti pris est donc restrictif : peu de teintes, réservées à ce qui porte du\nsens, et un contraste suffisant pour une lecture prolongée.",{"title":37,"searchDepth":38,"depth":38,"links":39},"",3,[],"Aucun thème existant ne me convenait vraiment : trop de couleurs en concurrence, ou pas assez de contraste sur les commentaires et les chaînes de caractères.",[42,43],"Définition de la palette et des règles de coloration syntaxique.","Publication et maintenance de l'extension sur le Marketplace.","\u002Fimages\u002Fprojets\u002Ftheme-vscode.jpg","Éditeur VS Code affichant du code avec le thème sombre","md",true,{"demo":49},"https:\u002F\u002Fmarketplace.visualstudio.com\u002Fitems?itemName=BaptisteCrouzet.dark-theme-the-new",{},5,"TODO: nombre d'installations, si le chiffre est intéressant.","\u002Fprojets\u002Ftheme-vscode","TODO: année de publication","Conception et développement, seul",{"title":25,"description":32},[58,59],"JSON","VS Code Extension API","live","projets\u002Ftheme-vscode","Thème sombre pour Visual Studio Code, publié sur le Marketplace officiel.","0a_cDx77j12HlcaLQz0aaTxLCaCcMO_ZgS8PLaiaxX0",[65,110,151,165,197,232,266,307],{"id":66,"title":67,"body":68,"context":87,"contributions":88,"cover":91,"coverAlt":92,"description":72,"extension":46,"featured":47,"links":93,"meta":95,"navigation":47,"order":96,"outcome":97,"path":98,"period":99,"role":100,"seo":101,"stack":102,"status":60,"stem":107,"summary":108,"__hash__":109},"projets\u002Fprojets\u002Fkosmood.md","Kosmood",{"type":27,"value":69,"toc":85},[70,73,76],[30,71,72],{},"Kosmood est allé plus loin que les autres projets de cette période : il a été\nmis en production, avec ce que cela suppose de déploiements, de montées de\nversion et de correctifs sur du code déjà utilisé.",[30,74,75],{},"Le back-end Symfony expose une API, le front-end Vue.js la consomme. Le moteur\nde templates de Symfony aurait suffi pour une première version et représentait\nmoins de travail. Nous avons préféré séparer les deux, ce qui a permis de les\nfaire évoluer indépendamment par la suite.",[30,77,78,79,84],{},"L'infrastructure Docker du projet fait l'objet d'",[80,81,83],"a",{"href":82},"\u002Fprojets\u002Fdocker-kosmood","une fiche à\npart",".",{"title":37,"searchDepth":38,"depth":38,"links":86},[],"Projet d'équipe mené dans un cadre scolaire, puis mis en production. L'équipe a choisi sa stack et son organisation, sans consigne imposée.",[89,90],"TODO: ce que tu as développé précisément (modules, API, écrans…)","TODO: ta part dans les choix techniques et l’organisation","\u002Fimages\u002Fprojets\u002Fkosmood.jpg","Capture d'écran de l'interface de Kosmood",{"demo":94},"https:\u002F\u002Fwww.kosmood.com",{},1,"TODO: le résultat concret — mise en production, nombre d'utilisateurs, ce que le projet a changé dans ta pratique.","\u002Fprojets\u002Fkosmood","TODO: préciser la période, par exemple 2020 — 2021","Développeur full-stack, en équipe",{"title":67,"description":72},[103,104,105,106],"Symfony 5","PHP 8","Vue.js","Vuetify","projets\u002Fkosmood","Application web de gestion mise en production, développée en équipe avec Symfony et Vue.js.","sogPeD6E5U0Hnr8vTTxYjBNu4aioDnx-7oqQZ4BOHCc",{"id":111,"title":112,"body":113,"context":128,"contributions":129,"cover":133,"coverAlt":134,"description":117,"extension":46,"featured":47,"links":135,"meta":137,"navigation":47,"order":138,"outcome":139,"path":82,"period":140,"role":141,"seo":142,"stack":143,"status":60,"stem":148,"summary":149,"__hash__":150},"projets\u002Fprojets\u002Fdocker-kosmood.md","Infrastructure Docker pour Kosmood",{"type":27,"value":114,"toc":126},[115,118],[30,116,117],{},"La configuration passe par des variables d'environnement, et non par un fichier\ndupliqué puis modifié à la main sur chaque machine. Même image, mêmes services,\nseuls les paramètres changent.",[30,119,120,121,125],{},"Le ",[122,123,124],"code",{},"docker-compose.yml"," n'a rien de remarquable en soi. Son intérêt est d'avoir\nrapproché la configuration du serveur de celle des postes de travail.",{"title":37,"searchDepth":38,"depth":38,"links":127},[],"À plusieurs sur une application Symfony et Vue.js, sans environnement commun, on finit par passer plus de temps à comprendre pourquoi le code tourne chez l'un et pas chez l'autre qu'à écrire des fonctionnalités.",[130,131,132],"Découpage en services et rédaction des Dockerfile.","Orchestration via Docker Compose, avec configuration par variables d'environnement.","Documentation de la procédure de démarrage pour l'équipe.","\u002Fimages\u002Fprojets\u002Fdocker-kosmood.jpg","Logo de Docker",{"repo":136},"https:\u002F\u002Fgithub.com\u002FBaptisteCrouzet\u002FDocker-for-Kosmood",{},4,"Le même environnement pour tout le monde, montable en une commande. Le déploiement reprend la même configuration.","TODO: année","Conception et réalisation, seul",{"title":112,"description":117},[144,145,146,147],"Docker","Docker Compose","NGINX","PHP-FPM","projets\u002Fdocker-kosmood","Environnement conteneurisé reproductible pour le développement et le déploiement de Kosmood.","E2H18dLneMrrj3P8iYbdG_X-vnrf5iX11J_yu4pqU3o",{"id":24,"title":25,"body":152,"context":40,"contributions":160,"cover":44,"coverAlt":45,"description":32,"extension":46,"featured":47,"links":161,"meta":162,"navigation":47,"order":51,"outcome":52,"path":53,"period":54,"role":55,"seo":163,"stack":164,"status":60,"stem":61,"summary":62,"__hash__":63},{"type":27,"value":153,"toc":158},[154,156],[30,155,32],{},[30,157,35],{},{"title":37,"searchDepth":38,"depth":38,"links":159},[],[42,43],{"demo":49},{},{"title":25,"description":32},[58,59],{"id":166,"title":167,"body":168,"context":178,"contributions":179,"cover":183,"coverAlt":37,"description":172,"extension":46,"featured":6,"links":184,"meta":186,"navigation":47,"order":187,"outcome":188,"path":189,"period":140,"role":141,"seo":190,"stack":191,"status":60,"stem":194,"summary":195,"__hash__":196},"projets\u002Fprojets\u002Fdocker-site-statique.md","Docker pour site statique",{"type":27,"value":169,"toc":176},[170,173],[30,171,172],{},"Certbot renouvelle les certificats, NGINX recharge sa configuration. C'est le\nseul périmètre de ce dépôt, et c'est ce qui le rend réutilisable tel quel.",[30,174,175],{},"Il a hébergé la version précédente de ce site pendant cinq ans, et le\ndéploiement actuel repart de la même base.",{"title":37,"searchDepth":38,"depth":38,"links":177},[],"Mettre un site statique en ligne sur un serveur dédié suppose de gérer le serveur web, le HTTPS et le renouvellement des certificats. Autant l'écrire une fois correctement.",[180,181,182],"Configuration NGINX pour servir des fichiers statiques.","Automatisation de l'obtention et du renouvellement des certificats.","Assemblage des services via Docker Compose.",null,{"repo":185},"https:\u002F\u002Fgithub.com\u002FBaptisteCrouzet\u002FDocker-Static-Simple-Site",{},6,"Le socle qui a servi à héberger la première version de ce portfolio, et réutilisable tel quel pour n'importe quel site statique.","\u002Fprojets\u002Fdocker-site-statique",{"title":167,"description":172},[144,146,192,193],"Certbot","Let's Encrypt","projets\u002Fdocker-site-statique","Socle de déploiement conteneurisé avec NGINX et renouvellement automatique des certificats.","kuDHpe9wEjC3r5AGsc2k3zzasTV_Zze28HCDb1_WCsU",{"id":198,"title":199,"body":200,"context":210,"contributions":211,"cover":214,"coverAlt":215,"description":204,"extension":46,"featured":6,"links":216,"meta":219,"navigation":47,"order":220,"outcome":221,"path":222,"period":140,"role":223,"seo":224,"stack":225,"status":60,"stem":229,"summary":230,"__hash__":231},"projets\u002Fprojets\u002Ftic-tac-toe.md","Tic-tac-toe",{"type":27,"value":201,"toc":208},[202,205],[30,203,204],{},"Tachyons est rapide à écrire et ne laisse pas de CSS mort derrière lui. En\nrevanche, sans mécanisme de composition, trois cases qui partagent le même\nstyle représentent trois listes de classes identiques à maintenir à la main.",[30,206,207],{},"Le jeu lui-même est volontairement minimal : il ne sert qu'à mettre l'outil en\nsituation.",{"title":37,"searchDepth":38,"depth":38,"links":209},[],"Le CSS utilitaire n'était pas encore courant. Je voulais me faire un avis sur Tachyons en écrivant quelque chose avec, pas en lisant sa documentation.",[212,213],"Logique de jeu et détection des combinaisons gagnantes.","Interface entièrement construite avec des classes utilitaires.","\u002Fimages\u002Fprojets\u002Ftic-tac-toe.jpg","Grille de morpion affichée dans un navigateur",{"demo":217,"repo":218},"https:\u002F\u002Fbaptistecrouzet.github.io\u002FTic-Tac-Toe\u002F","https:\u002F\u002Fgithub.com\u002FBaptisteCrouzet\u002FTic-Tac-Toe",{},7,"Un avis étayé sur le coût de l'approche utilitaire sans système de composants : le balisage devient difficile à lire dès que les états se multiplient.","\u002Fprojets\u002Ftic-tac-toe","Développement, seul",{"title":199,"description":204},[226,227,228],"JavaScript","Tachyons.css","HTML","projets\u002Ftic-tac-toe","Petit jeu en JavaScript, prétexte à évaluer Tachyons et son approche utilitaire du CSS.","2nDKrrwb_dmRpBOFdlnFd73zZlUkqi6h10f6DL9CasM",{"id":233,"title":234,"body":235,"context":245,"contributions":246,"cover":250,"coverAlt":251,"description":239,"extension":46,"featured":6,"links":252,"meta":254,"navigation":47,"order":255,"outcome":256,"path":257,"period":140,"role":55,"seo":258,"stack":259,"status":262,"stem":263,"summary":264,"__hash__":265},"projets\u002Fprojets\u002Fgulp-boilerplate.md","Boilerplate Gulp",{"type":27,"value":236,"toc":243},[237,240],[30,238,239],{},"Gulp orchestrait la plupart des chaînes d'assets de l'époque. Vite assure\naujourd'hui le même travail sans configuration, et ce socle n'a plus d'usage\npratique.",[30,241,242],{},"Il reste publié parce qu'il a produit un gain mesurable : une demi-journée de\nmise en place par projet, ramenée à quelques minutes.",{"title":37,"searchDepth":38,"depth":38,"links":244},[],"Repartir de zéro à chaque projet coûtait une demi-journée de configuration pour un résultat toujours identique.",[247,248,249],"Chaîne de compilation Sass, autoprefixing et minification.","Serveur de développement avec rechargement automatique.","Structure de dossiers et documentation d'utilisation.","\u002Fimages\u002Fprojets\u002Fgulp-boilerplate.jpg","Logo de Gulp",{"repo":253},"https:\u002F\u002Fgithub.com\u002FBaptisteCrouzet\u002FGulp-boilerplate",{},8,"Le temps de démarrage d'un nouveau projet est passé d'une demi-journée à quelques minutes.","\u002Fprojets\u002Fgulp-boilerplate",{"title":234,"description":239},[260,261,226],"Gulp","Sass","archived","projets\u002Fgulp-boilerplate","Socle de projet front-end réutilisable, avec compilation des assets et rechargement automatique.","JBW9fXZ1a6z3pANgjup83eRxoiDeC6pLAl9oRWiysow",{"id":267,"title":268,"body":269,"context":286,"contributions":287,"cover":291,"coverAlt":292,"description":273,"extension":46,"featured":6,"links":293,"meta":295,"navigation":47,"order":296,"outcome":297,"path":298,"period":299,"role":55,"seo":300,"stack":301,"status":262,"stem":304,"summary":305,"__hash__":306},"projets\u002Fprojets\u002Fportfolio-webpack.md","Portfolio Webpack",{"type":27,"value":270,"toc":284},[271,274,277],[30,272,273],{},"Cinq pages HTML et cinq domaines tiers contactés au chargement, dont trois\nbloquaient le rendu. Le contenu vivait dans le balisage : corriger une phrase\nimposait de rouvrir l'éditeur et de relancer un build.",[30,275,276],{},"Le site a rempli son rôle pendant cinq ans. Ce n'est pas Webpack qui l'a rendu\nobsolète, mais cette accumulation de dépendances et la rigidité du contenu.",[30,278,279,280,84],{},"Le détail de la migration est ",[80,281,283],{"href":282},"\u002Fblog\u002Fmigrer-webpack-vers-nuxt","dans le blog",{"title":37,"searchDepth":38,"depth":38,"links":285},[],"Avant cette refonte, le site était entièrement écrit à la main : cinq pages HTML, du Sass, la grille de Bootstrap et une configuration Webpack montée pièce par pièce. Le but était de comprendre chaque maillon de la chaîne plutôt que de déléguer à un framework.",[288,289,290],"Configuration Webpack complète : compilation, minification, conversion des images en WebP, purge du CSS inutilisé.","Intégration des maquettes et gestion du responsive.","Mise en place du mode PWA avec service worker.","\u002Fimages\u002Fprojets\u002Fportfolio-webpack.png","Logo de Webpack",{"repo":294},"https:\u002F\u002Fgithub.com\u002FBaptisteCrouzet\u002FWebpackPortfolio",{},9,"Une bonne compréhension de ce qu'un bundler fait réellement, et de ce que les frameworks apportent une fois qu'on a monté la chaîne soi-même.","\u002Fprojets\u002Fportfolio-webpack","2021 — 2026",{"title":268,"description":273},[302,261,226,303],"Webpack 5","PWA","projets\u002Fportfolio-webpack","Version précédente de ce site, faite à la main avec Webpack, Sass et du JavaScript sans framework.","sLiDM6AyyRQkfCJOWOqosufA0SyS2BT7rt70r2j5Cps",{"id":308,"title":309,"body":310,"context":320,"contributions":321,"cover":325,"coverAlt":326,"description":314,"extension":46,"featured":6,"links":327,"meta":329,"navigation":47,"order":330,"outcome":331,"path":332,"period":140,"role":223,"seo":333,"stack":334,"status":262,"stem":337,"summary":338,"__hash__":339},"projets\u002Fprojets\u002Fplayer-musique.md","Lecteur de musique PWA",{"type":27,"value":311,"toc":318},[312,315],[30,313,314],{},"Mettre en cache une feuille de style est trivial. Mettre en cache des fichiers\naudio de plusieurs mégaoctets impose de trancher des questions concrètes : quoi\nconserver, pendant combien de temps, et quel comportement adopter lorsque le\nquota du navigateur est atteint.",[30,316,317],{},"Il n'existe pas de réponse générique. J'ai retenu les derniers morceaux lus et\npurgé le reste : la stratégie convient à une playlist personnelle et ne\ntiendrait pas sur un catalogue complet.",{"title":37,"searchDepth":38,"depth":38,"links":319},[],"Un prétexte pour aller au bout du modèle PWA : installation sur l'écran d'accueil, fonctionnement hors ligne et lecture qui survit à la mise en arrière-plan de l'onglet.",[322,323,324],"Interface de lecture et gestion de la file de morceaux.","Service worker et stratégie de mise en cache des fichiers audio.","Manifeste d'application pour l'installation.","\u002Fimages\u002Fprojets\u002Fplayer-musique.png","Interface du lecteur de musique",{"demo":328},"https:\u002F\u002Fpwa-songs-playlist-plsv4qp7c-baptistecrouzet.vercel.app\u002F",{},10,"Une application installable qui fonctionne sans réseau, et une vision précise des limites du modèle PWA.","\u002Fprojets\u002Fplayer-musique",{"title":309,"description":314},[105,303,335,336],"Service Worker","Web Audio","projets\u002Fplayer-musique","Lecteur audio en Vue.js, installable comme une application et fonctionnel hors connexion grâce à un service worker.","sPLQLBBAXYpk0IvCoMPBlFIwcL0zTqpQOaXfenZAQvQ",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":341},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"m9 18l6-6l-6-6\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":343},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M15 3h6v6m-11 5L21 3m-3 10v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":345},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M20 6L9 17l-5-5\"\u002F>",1791663008601]