[{"data":1,"prerenderedAt":871},["ShallowReactive",2],{"i-simple-icons:github":3,"i-simple-icons:linkedin":8,"blog-\u002Fblog\u002Fvue-3-ce-que-j-utilise-vraiment":11,"blog-others-\u002Fblog\u002Fvue-3-ce-que-j-utilise-vraiment":536},{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":7},0,24,false,"\u003Cpath fill=\"currentColor\" d=\"M12 .297c-6.63 0-12 5.373-12 12c0 5.303 3.438 9.8 8.205 11.385c.6.113.82-.258.82-.577c0-.285-.01-1.04-.015-2.04c-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729c1.205.084 1.838 1.236 1.838 1.236c1.07 1.835 2.809 1.305 3.495.998c.108-.776.417-1.305.76-1.605c-2.665-.3-5.466-1.332-5.466-5.93c0-1.31.465-2.38 1.235-3.22c-.135-.303-.54-1.523.105-3.176c0 0 1.005-.322 3.3 1.23c.96-.267 1.98-.399 3-.405c1.02.006 2.04.138 3 .405c2.28-1.552 3.285-1.23 3.285-1.23c.645 1.653.24 2.873.12 3.176c.765.84 1.23 1.91 1.23 3.22c0 4.61-2.805 5.625-5.475 5.92c.42.36.81 1.096.81 2.22c0 1.606-.015 2.896-.015 3.286c0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":9,"hidden":10},"\u003Cpath fill=\"currentColor\" d=\"M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037c-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85c3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433a2.06 2.06 0 0 1-2.063-2.065a2.064 2.064 0 1 1 2.063 2.065m1.782 13.019H3.555V9h3.564zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0z\"\u002F>",true,{"id":12,"title":13,"body":14,"date":521,"description":522,"extension":523,"meta":524,"navigation":10,"path":525,"readingTime":114,"seo":526,"seoTitle":527,"stem":528,"tags":529,"tone":533,"updated":534,"__hash__":535},"blog\u002Fblog\u002Fvue-3-ce-que-j-utilise-vraiment.md","Vue 3 au quotidien, ce que j’utilise vraiment",{"type":15,"value":16,"toc":508},"minimark",[17,21,30,37,43,47,220,235,242,260,375,382,386,389,411,414,423,438,444,448,455,458,462,497,501,504],[18,19,20],"p",{},"Quand on apprend Vue, on a l’impression qu’il faut tout connaître : les deux API, les mixins, les directives personnalisées, les render functions, Pinia, les plugins. En pratique, sur les projets que je livre, j’utilise une partie assez réduite de tout ça. Elle tient dans cet article.",[22,23,25,29],"h2",{"id":24},"script-setup-et-rien-dautre",[26,27,28],"code",{},"\u003Cscript setup>"," et rien d’autre",[18,31,32,33,36],{},"Tous mes composants sont écrits en ",[26,34,35],{},"\u003Cscript setup lang=\"ts\">",". Pas d’Options API, même dans un vieux projet qu’on reprend : je migre le composant que je touche, et je laisse les autres jusqu’à ce que je les touche.",[18,38,39,40,42],{},"La raison n’est pas la mode. C’est que le code se lit de haut en bas, que TypeScript comprend tout sans annotation, et qu’un composable s’appelle comme une fonction ordinaire. Un composant de cinquante lignes en ",[26,41,28],{}," se comprend en une lecture.",[22,44,46],{"id":45},"des-props-typées-pas-des-objets-de-configuration","Des props typées, pas des objets de configuration",[48,49,55],"pre",{"className":50,"code":51,"filename":52,"language":53,"meta":54,"style":54},"language-vue shiki shiki-themes github-light github-dark","\u003Cscript setup lang=\"ts\">\nimport type { Project } from '~\u002Fdata\u002Fprojects'\n\nconst props = defineProps\u003C{\n  project: Project\n  compact?: boolean\n}>()\n\nconst emit = defineEmits\u003C{\n  open: [slug: string]\n}>()\n\u003C\u002Fscript>\n","ProjectCard.vue","vue","",[26,56,57,87,106,112,131,144,156,162,167,182,205,210],{"__ignoreMap":54},[58,59,62,66,70,74,77,80,84],"span",{"class":60,"line":61},"line",1,[58,63,65],{"class":64},"sVt8B","\u003C",[58,67,69],{"class":68},"s9eBZ","script",[58,71,73],{"class":72},"sScJk"," setup",[58,75,76],{"class":72}," lang",[58,78,79],{"class":64},"=",[58,81,83],{"class":82},"sZZnC","\"ts\"",[58,85,86],{"class":64},">\n",[58,88,90,94,97,100,103],{"class":60,"line":89},2,[58,91,93],{"class":92},"szBVR","import",[58,95,96],{"class":92}," type",[58,98,99],{"class":64}," { Project } ",[58,101,102],{"class":92},"from",[58,104,105],{"class":82}," '~\u002Fdata\u002Fprojects'\n",[58,107,109],{"class":60,"line":108},3,[58,110,111],{"emptyLinePlaceholder":10},"\n",[58,113,115,118,122,125,128],{"class":60,"line":114},4,[58,116,117],{"class":92},"const",[58,119,121],{"class":120},"sj4cs"," props",[58,123,124],{"class":92}," =",[58,126,127],{"class":72}," defineProps",[58,129,130],{"class":64},"\u003C{\n",[58,132,134,138,141],{"class":60,"line":133},5,[58,135,137],{"class":136},"s4XuR","  project",[58,139,140],{"class":92},":",[58,142,143],{"class":72}," Project\n",[58,145,147,150,153],{"class":60,"line":146},6,[58,148,149],{"class":136},"  compact",[58,151,152],{"class":92},"?:",[58,154,155],{"class":120}," boolean\n",[58,157,159],{"class":60,"line":158},7,[58,160,161],{"class":64},"}>()\n",[58,163,165],{"class":60,"line":164},8,[58,166,111],{"emptyLinePlaceholder":10},[58,168,170,172,175,177,180],{"class":60,"line":169},9,[58,171,117],{"class":92},[58,173,174],{"class":120}," emit",[58,176,124],{"class":92},[58,178,179],{"class":72}," defineEmits",[58,181,130],{"class":64},[58,183,185,188,190,193,196,199,202],{"class":60,"line":184},10,[58,186,187],{"class":136},"  open",[58,189,140],{"class":92},[58,191,192],{"class":64}," [",[58,194,195],{"class":72},"slug",[58,197,198],{"class":64},": ",[58,200,201],{"class":120},"string",[58,203,204],{"class":64},"]\n",[58,206,208],{"class":60,"line":207},11,[58,209,161],{"class":64},[58,211,213,216,218],{"class":60,"line":212},12,[58,214,215],{"class":64},"\u003C\u002F",[58,217,69],{"class":68},[58,219,86],{"class":64},[18,221,222,223,226,227,230,231,234],{},"Deux habitudes ici. D’abord, le type vient du modèle de données, pas d’une redéfinition locale : si ",[26,224,225],{},"Project"," change, le composant le sait. Ensuite, ",[26,228,229],{},"defineEmits"," avec des types nommés. L’éditeur complète l’événement et son argument, et une faute de frappe dans un ",[26,232,233],{},"@open"," devient une erreur à la compilation.",[22,236,238,241],{"id":237},"definemodel-pour-tout-ce-qui-se-saisit",[26,239,240],{},"defineModel"," pour tout ce qui se saisit",[18,243,244,245,248,249,252,253,256,257,259],{},"Avant, un champ contrôlé demandait une prop ",[26,246,247],{},"modelValue",", un événement ",[26,250,251],{},"update:modelValue"," et un ",[26,254,255],{},"computed"," pour relier les deux. Depuis ",[26,258,240],{},", c’est une ligne :",[48,261,264],{"className":50,"code":262,"filename":263,"language":53,"meta":54,"style":54},"\u003Cscript setup lang=\"ts\">\nconst phone = defineModel\u003Cstring>({ default: '' })\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cinput v-model=\"phone\" type=\"tel\" inputmode=\"tel\" autocomplete=\"tel\">\n\u003C\u002Ftemplate>\n","PhoneField.vue",[26,265,266,282,307,315,319,328,367],{"__ignoreMap":54},[58,267,268,270,272,274,276,278,280],{"class":60,"line":61},[58,269,65],{"class":64},[58,271,69],{"class":68},[58,273,73],{"class":72},[58,275,76],{"class":72},[58,277,79],{"class":64},[58,279,83],{"class":82},[58,281,86],{"class":64},[58,283,284,286,289,291,294,296,298,301,304],{"class":60,"line":89},[58,285,117],{"class":92},[58,287,288],{"class":120}," phone",[58,290,124],{"class":92},[58,292,293],{"class":72}," defineModel",[58,295,65],{"class":64},[58,297,201],{"class":120},[58,299,300],{"class":64},">({ default: ",[58,302,303],{"class":82},"''",[58,305,306],{"class":64}," })\n",[58,308,309,311,313],{"class":60,"line":108},[58,310,215],{"class":64},[58,312,69],{"class":68},[58,314,86],{"class":64},[58,316,317],{"class":60,"line":114},[58,318,111],{"emptyLinePlaceholder":10},[58,320,321,323,326],{"class":60,"line":133},[58,322,65],{"class":64},[58,324,325],{"class":68},"template",[58,327,86],{"class":64},[58,329,330,333,336,339,341,344,346,348,351,354,356,358,361,363,365],{"class":60,"line":146},[58,331,332],{"class":64},"  \u003C",[58,334,335],{"class":68},"input",[58,337,338],{"class":72}," v-model",[58,340,79],{"class":64},[58,342,343],{"class":82},"\"phone\"",[58,345,96],{"class":72},[58,347,79],{"class":64},[58,349,350],{"class":82},"\"tel\"",[58,352,353],{"class":72}," inputmode",[58,355,79],{"class":64},[58,357,350],{"class":82},[58,359,360],{"class":72}," autocomplete",[58,362,79],{"class":64},[58,364,350],{"class":82},[58,366,86],{"class":64},[58,368,369,371,373],{"class":60,"line":158},[58,370,215],{"class":64},[58,372,325],{"class":68},[58,374,86],{"class":64},[18,376,377,378,381],{},"Le composant parent fait ",[26,379,380],{},"\u003CPhoneField v-model=\"form.phone\" \u002F>"," et tout circule. Je l’utilise pour chaque champ de formulaire, chaque interrupteur, chaque sélecteur.",[22,383,385],{"id":384},"les-composables-pour-une-seule-raison","Les composables, pour une seule raison",[18,387,388],{},"Un composable, chez moi, existe quand la même logique réactive apparaît dans deux composants. Pas avant. Les trois que j’emporte de projet en projet :",[390,391,392,399,405],"ul",{},[393,394,395,398],"li",{},[26,396,397],{},"useMediaQuery('(min-width: 1024px)')",", pour adapter un comportement, pas un style (le style, c’est le rôle du CSS).",[393,400,401,404],{},[26,402,403],{},"useTheme()",", qui lit et écrit la préférence clair ou sombre.",[393,406,407,410],{},[26,408,409],{},"useScrub(el, offset)",", qui transforme la position de défilement d’un élément en une valeur entre 0 et 1, pour les animations liées au scroll.",[18,412,413],{},"Ils font chacun moins de trente lignes. Un composable de deux cents lignes est en général un composant qui s’ignore.",[22,415,417,419,420],{"id":416},"computed-plutôt-que-watch",[26,418,255],{}," plutôt que ",[26,421,422],{},"watch",[18,424,425,426,428,429,431,432,434,435,437],{},"Chaque fois que je suis tentée d’écrire un ",[26,427,422],{}," pour recalculer une valeur, je vérifie si un ",[26,430,255],{}," ne suffit pas. Neuf fois sur dix, oui. Le ",[26,433,255],{}," dit ce qu’est la valeur ; le ",[26,436,422],{}," dit quand la recalculer, et c’est là que les bugs de synchronisation se cachent.",[18,439,440,441,443],{},"Je garde ",[26,442,422],{}," pour les effets de bord : appeler une API, écrire dans le stockage, lancer une animation.",[22,445,447],{"id":446},"le-state-global-le-plus-tard-possible","Le state global, le plus tard possible",[18,449,450,451,454],{},"Pinia est très bien. Mais la plupart des données d’un écran appartiennent à cet écran. Je commence toujours par un ",[26,452,453],{},"ref"," local, je passe des props vers le bas et des événements vers le haut, et je ne crée un store que quand deux pages éloignées ont vraiment besoin de la même donnée vivante : la session de l’utilisateur, un panier, un brouillon qui doit survivre à la navigation.",[18,456,457],{},"Un projet avec un seul store de vingt lignes est souvent en meilleure santé qu’un projet avec douze stores.",[22,459,461],{"id":460},"ce-que-je-nutilise-presque-jamais","Ce que je n’utilise presque jamais",[390,463,464,471,483,489],{},[393,465,466,470],{},[467,468,469],"strong",{},"Les mixins."," Un composable fait la même chose en lisible.",[393,472,473,482],{},[467,474,475,478,479],{},[26,476,477],{},"provide"," et ",[26,480,481],{},"inject"," en dehors des bibliothèques de composants. Dans une application, c’est du state global qui ne dit pas son nom.",[393,484,485,488],{},[467,486,487],{},"Les render functions."," Utiles dans une bibliothèque, inutiles dans une page.",[393,490,491,496],{},[467,492,493],{},[26,494,495],{},"v-html"," avec du contenu qui ne vient pas de moi.",[22,498,500],{"id":499},"le-mot-de-la-fin","Le mot de la fin",[18,502,503],{},"Vue permet beaucoup de choses, et c’est tant mieux. Mais un projet qu’on peut reprendre six mois plus tard est un projet qui utilise peu de choses, toujours de la même façon. Ce que je décris ici tient sur une page, et c’est volontaire : c’est ce qu’un nouveau venu doit lire pour contribuer dès le premier jour.",[505,506,507],"style",{},"html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":54,"searchDepth":89,"depth":89,"links":509},[510,512,513,515,516,518,519,520],{"id":24,"depth":89,"text":511},"\u003Cscript setup> et rien d’autre",{"id":45,"depth":89,"text":46},{"id":237,"depth":89,"text":514},"defineModel pour tout ce qui se saisit",{"id":384,"depth":89,"text":385},{"id":416,"depth":89,"text":517},"computed plutôt que watch",{"id":446,"depth":89,"text":447},{"id":460,"depth":89,"text":461},{"id":499,"depth":89,"text":500},"2026-07-08","Vue a beaucoup d’outils. Après plusieurs projets en production, voici la petite partie que j’utilise tous les jours, et pourquoi j’ai laissé le reste de côté.","md",{},"\u002Fblog\u002Fvue-3-ce-que-j-utilise-vraiment",{"title":13,"description":522},"Vue 3 : bonnes pratiques que j’utilise vraiment en production","blog\u002Fvue-3-ce-que-j-utilise-vraiment",[530,531,532],"Vue","TypeScript","Front-end","lavender",null,"0O26clxhidAgvGmev5M7U7TBcllDY5ikZroUt0k2rHg",[537,697],{"id":538,"title":539,"body":540,"date":685,"description":686,"extension":523,"meta":687,"navigation":10,"path":688,"readingTime":114,"seo":689,"seoTitle":690,"stem":691,"tags":692,"tone":533,"updated":534,"__hash__":696},"blog\u002Fblog\u002Fcoder-avec-une-ia-sans-perdre-la-main.md","Coder avec une IA sans perdre la main",{"type":15,"value":541,"toc":678},[542,545,548,552,555,558,561,565,571,577,583,589,593,599,605,611,623,627,660,668,672,675],[18,543,544],{},"Il y a deux façons de rater le virage des assistants de code. La première est de les ignorer et de taper à la main ce qu’une machine écrit mieux et plus vite. La seconde est de tout leur laisser et de ne plus savoir ce qui tourne en production. Entre les deux, il y a une pratique, et elle se construit.",[18,546,547],{},"Voici la mienne, telle qu’elle est aujourd’hui, après un an de projets livrés avec Claude Code dans l’éditeur.",[22,549,551],{"id":550},"une-boucle-pas-une-baguette","Une boucle, pas une baguette",[18,553,554],{},"L’erreur la plus courante est de voir l’IA comme un générateur : on décrit, on reçoit, on colle. Ce n’est pas comme ça que ça marche bien. Ce qui marche, c’est une boucle courte où chaque étape a un responsable.",[556,557],"demo-loop",{},[18,559,560],{},"L’IA n’intervient qu’à une étape. Tout le reste, c’est du travail d’ingénierie classique, et c’est lui qui fait la qualité du résultat. Si le brief est flou, la génération est floue. Si la relecture est bâclée, les bugs passent. Si les tests n’existent pas, personne ne sait si la troisième itération a cassé la première.",[22,562,564],{"id":563},"ce-que-je-lui-confie","Ce que je lui confie",[18,566,567,570],{},[467,568,569],{},"Le code qui a déjà été écrit mille fois."," Un formulaire avec validation, un composant de liste avec ses états, une fonction qui formate des dates en français, la configuration d’un module Nuxt. L’IA connaît ces motifs par cœur et les écrit sans faute de frappe. Je gagne vingt minutes par occurrence, et il y en a beaucoup dans une journée.",[18,572,573,576],{},[467,574,575],{},"Les tâches larges et peu risquées."," Renommer un composant dans tout le projet, extraire un composable, ajouter un type manquant, écrire les premiers tests d’un fichier. Ce sont des tâches où l’erreur se voit tout de suite.",[18,578,579,582],{},[467,580,581],{},"La première version de quelque chose."," Quand je ne sais pas encore à quoi va ressembler un écran, je lui demande trois propositions. Je n’en garde jamais une telle quelle, mais je choisis plus vite.",[18,584,585,588],{},[467,586,587],{},"Les explications."," Un code hérité que personne ne commente, une erreur de build incompréhensible, une API que je n’ai jamais utilisée. Demander « explique-moi ce fichier » avant de le modifier m’a évité pas mal de casse.",[22,590,592],{"id":591},"ce-que-je-garde","Ce que je garde",[18,594,595,598],{},[467,596,597],{},"Les décisions."," L’architecture, le découpage en composants, le choix d’une bibliothèque, ce qui va dans le state global et ce qui n’y va pas. L’IA peut argumenter, elle ne tranche pas. C’est moi qui porterai la décision dans six mois.",[18,600,601,604],{},[467,602,603],{},"La relecture, ligne par ligne."," Je ne fusionne rien que je n’ai pas lu. Pas survolé : lu. Si une ligne me paraît magique, je demande pourquoi elle est là, et si la réponse ne me convainc pas, elle saute. Un code que je ne comprends pas est un code que je ne pourrai pas corriger à deux heures du matin.",[18,606,607,610],{},[467,608,609],{},"Tout ce qui touche à la sécurité et à l’argent."," Authentification, paiement, droits d’accès, données personnelles. L’IA écrit ce code aussi bien qu’un autre, mais là, je vérifie deux fois plus, et j’écris les tests moi-même.",[18,612,613,616,617,622],{},[467,614,615],{},"L’interface finale."," Les détails qu’un humain remarque sans savoir les nommer, j’en parle dans ",[618,619,621],"a",{"href":620},"\u002Fblog\u002Fce-que-l-ia-ne-voit-pas-dans-une-interface","un autre article",". Ils ne viennent pas de la génération, ils viennent de la relecture avec les yeux de l’utilisateur.",[22,624,626],{"id":625},"les-règles-que-je-me-suis-fixées","Les règles que je me suis fixées",[628,629,630,636,642,648,654],"ol",{},[393,631,632,635],{},[467,633,634],{},"Un fichier de conventions à la racine du projet."," Nom des composants, structure des dossiers, langue des commentaires, format des commits. L’assistant le lit à chaque session, et le code qu’il produit ressemble au mien. Sans ce fichier, chaque génération part dans une direction différente.",[393,637,638,641],{},[467,639,640],{},"Une tâche à la fois."," « Ajoute le champ téléphone au formulaire de contact, avec la validation et le test » est une tâche. « Améliore le formulaire » n’en est pas une. Plus la demande est bornée, plus la réponse est juste, et plus la relecture est rapide.",[393,643,644,647],{},[467,645,646],{},"Les tests tournent avant que je regarde."," Si la suite Cypress est rouge, je ne lis même pas le diff. Ça m’oblige à garder des tests fiables, et ça m’évite de perdre du temps sur un code qui ne marche pas.",[393,649,650,653],{},[467,651,652],{},"Je relis dans l’éditeur, pas dans la conversation."," Le diff dans Git, avec la coloration, le contexte autour, et la possibilité de lancer le projet. La conversation sert à discuter, pas à valider.",[393,655,656,659],{},[467,657,658],{},"Je garde une trace de ce qui a été généré."," Pas pour m’en excuser, mais parce que si un bug apparaît dans trois semaines, savoir qu’un bloc est sorti d’une génération rapide oriente la recherche.",[661,662,665],"callout",{"title":663,"type":664},"Le test du lendemain","tip",[18,666,667],{},"Avant de fusionner un gros morceau généré, je me pose une question simple : si cette fonction casse demain et que je n’ai plus accès à l’assistant, est-ce que je sais la réparer ? Si la réponse est non, ce n’est pas prêt.",[22,669,671],{"id":670},"ce-que-ça-change-concrètement","Ce que ça change, concrètement",[18,673,674],{},"Je livre plus vite, c’est vrai, mais ce n’est pas le plus intéressant. Ce qui a changé, c’est où va mon attention. Moins de temps sur la syntaxe et la plomberie, plus de temps sur ce que l’utilisateur voit et ressent. Plus de temps aussi sur les tests, parce qu’ils sont devenus la vraie garantie, celle qui ne dépend pas de qui a écrit le code.",[18,676,677],{},"Et je comprends toujours ce que je livre. C’était la condition, et elle tient.",{"title":54,"searchDepth":89,"depth":89,"links":679},[680,681,682,683,684],{"id":550,"depth":89,"text":551},{"id":563,"depth":89,"text":564},{"id":591,"depth":89,"text":592},{"id":625,"depth":89,"text":626},{"id":670,"depth":89,"text":671},"2026-10-21","J’utilise Claude Code tous les jours. Voici ce que je lui confie, ce que je garde, et les règles qui m’évitent de livrer du code que je ne comprends pas.",{},"\u002Fblog\u002Fcoder-avec-une-ia-sans-perdre-la-main",{"title":539,"description":686},"Coder avec Claude Code sans perdre la main : ma méthode","blog\u002Fcoder-avec-une-ia-sans-perdre-la-main",[693,694,695],"IA","Méthode","Claude Code","v2_5veRBSuqiUYQJU5moplrHaQM26kKEITUIO4IdjOU",{"id":698,"title":699,"body":700,"date":860,"description":861,"extension":523,"meta":862,"navigation":10,"path":620,"readingTime":114,"seo":863,"seoTitle":864,"stem":865,"tags":866,"tone":869,"updated":534,"__hash__":870},"blog\u002Fblog\u002Fce-que-l-ia-ne-voit-pas-dans-une-interface.md","Ce qu’une IA ne voit pas dans une interface",{"type":15,"value":701,"toc":851},[702,705,708,712,715,718,721,747,751,754,762,766,777,788,792,795,798,802,805,808,812,815,821,825,828,848],[18,703,704],{},"Demandez à un assistant de code « une page de liste de projets avec un bouton pour en créer un ». Vous aurez une page propre, des cartes alignées, un bouton bleu. Elle marchera. Et elle sera incomplète d’une façon que personne ne remarque dans la conversation, mais que tout le monde remarque en l’utilisant.",[18,706,707],{},"Ce n’est pas une critique des outils. C’est la nature du problème : une interface se juge dans la main, pas sur une capture d’écran. Voici ce que je regarde systématiquement sur un écran généré, et que je trouve presque toujours à corriger.",[22,709,711],{"id":710},"les-états-que-personne-na-demandés","Les états que personne n’a demandés",[18,713,714],{},"Un écran n’existe pas dans un seul état. Il se charge, il peut être vide, il peut échouer, et seulement ensuite il montre quelque chose. Une génération produit l’état « succès » parce que c’est celui du brief. Les trois autres restent à écrire.",[716,717],"demo-states",{},[18,719,720],{},"Pour chacun, la question est la même : qu’est-ce que la personne comprend, et qu’est-ce qu’elle peut faire ?",[390,722,723,729,735,741],{},[393,724,725,728],{},[467,726,727],{},"Chargement"," : montrer la forme de ce qui arrive, pas un spinner au milieu du vide. Un squelette garde la page stable et dit « ça vient ».",[393,730,731,734],{},[467,732,733],{},"Vide"," : ce n’est pas une erreur. Dire qu’il n’y a rien encore, et proposer la première action.",[393,736,737,740],{},[467,738,739],{},"Erreur"," : dire ce qui s’est passé sans jargon, rassurer sur ce qui n’a pas été perdu, et offrir une sortie. « Une erreur est survenue » n’aide personne.",[393,742,743,746],{},[467,744,745],{},"Succès"," : c’est le seul qu’on obtient gratuitement.",[22,748,750],{"id":749},"le-retour-à-laction","Le retour à l’action",[18,752,753],{},"Un bouton généré change de couleur au survol, et c’est tout. Il ne réagit pas à l’appui, il ne confirme rien, il ne dit pas si l’action est en cours. Sur mobile, où il n’y a pas de survol, il ne donne aucun signe de vie.",[18,755,756,757,761],{},"J’ai écrit ",[618,758,760],{"href":759},"\u002Fblog\u002Fun-bouton-qui-repond","un article entier"," sur ce seul point, parce qu’il change la sensation de toute l’interface. Le résumé : le retour visuel part à l’appui, l’action part au relâchement, et la confirmation arrive après.",[22,763,765],{"id":764},"le-clavier","Le clavier",[18,767,768,769,772,773,776],{},"Essayez de parcourir l’écran avec la touche Tab. Souvent, l’ordre de parcours ne suit pas l’ordre visuel, le focus n’est pas visible, et la carte cliquable n’est pas atteignable parce que c’est un ",[26,770,771],{},"div"," avec un ",[26,774,775],{},"@click",". Rien de tout ça ne se voit sur une capture.",[18,778,779,780,783,784,787],{},"Les corrections sont petites : un vrai ",[26,781,782],{},"button"," ou un vrai lien, un ",[26,785,786],{},":focus-visible"," dessiné, l’ordre du DOM aligné sur l’ordre de lecture. Mais il faut les faire, et il faut y penser.",[22,789,791],{"id":790},"le-texte","Le texte",[18,793,794],{},"Les textes générés sont corrects et interchangeables. « Gérer vos projets », « Commencer maintenant », « Une erreur est survenue ». Ils remplissent la case. Un texte qui aide est spécifique : il nomme ce qui va se passer, dans les mots de la personne qui lit.",[18,796,797],{},"Je réécris presque tous les libellés d’un écran généré. C’est le poste qui prend le plus de temps après les états, et c’est celui qui se voit le plus.",[22,799,801],{"id":800},"les-écrans-intermédiaires","Les écrans intermédiaires",[18,803,804],{},"Entre 375 et 1440 pixels, il y a des largeurs où tout casse : une grille à trois colonnes qui devient illisible à 800, un titre qui déborde à 390, un tableau qui force le défilement horizontal. Les générations sont testées sur un écran, le vôtre, et c’est souvent le seul qui marche.",[18,806,807],{},"Je redimensionne la fenêtre lentement, de la plus étroite à la plus large, et je note chaque endroit où quelque chose saute. Ça prend deux minutes et ça évite les retours clients.",[22,809,811],{"id":810},"le-mode-sombre","Le mode sombre",[18,813,814],{},"Si le projet a un thème sombre, le code généré oublie une couleur sur trois. Un fond blanc codé en dur dans une carte, une ombre invisible, un texte gris sur gris. La solution est en amont : ne jamais écrire une couleur dans un composant, toujours passer par les variables du thème. Une fois la règle dans le fichier de conventions, l’assistant la suit.",[661,816,818],{"type":817},"note",[18,819,820],{},"Tout ce qui précède tient en une idée : l’IA produit ce qu’on lui décrit, et personne ne décrit les états vides, le focus clavier ou le texte d’erreur dans un brief. Ce sont les angles morts de la description, pas de l’outil.",[22,822,824],{"id":823},"ma-liste","Ma liste",[18,826,827],{},"Avant qu’un écran généré n’aille plus loin, je passe ces points dans l’ordre :",[628,829,830,833,836,839,842,845],{},[393,831,832],{},"Les quatre états existent et disent quoi faire.",[393,834,835],{},"Chaque action a un retour à l’appui et une confirmation.",[393,837,838],{},"Tout est atteignable au clavier, dans le bon ordre, avec un focus visible.",[393,840,841],{},"Chaque libellé nomme ce qui va se passer.",[393,843,844],{},"L’écran tient à 390, 768, 1024 et 1440 pixels.",[393,846,847],{},"Aucune couleur n’est écrite en dur.",[18,849,850],{},"Six points, dix minutes. C’est la différence entre un écran qui fonctionne et un écran qu’on a envie d’utiliser.",{"title":54,"searchDepth":89,"depth":89,"links":852},[853,854,855,856,857,858,859],{"id":710,"depth":89,"text":711},{"id":749,"depth":89,"text":750},{"id":764,"depth":89,"text":765},{"id":790,"depth":89,"text":791},{"id":800,"depth":89,"text":801},{"id":810,"depth":89,"text":811},{"id":823,"depth":89,"text":824},"2026-10-07","Une IA génère un écran correct en quelques secondes. Les détails qui le rendent agréable, ou simplement utilisable, viennent après. Liste de ce que je vérifie à la main.",{},{"title":699,"description":861},"Interface générée par IA : 6 points à vérifier à la main","blog\u002Fce-que-l-ia-ne-voit-pas-dans-une-interface",[693,867,868],"Interface","Accessibilité","slate","h6PnK0QzuO576IsiV6s7VYyIjKFmKVXSJ2Lu4TYMc0M",1793214702905]