[{"data":1,"prerenderedAt":763},["ShallowReactive",2],{"page-\u002Fpratiques\u002Fqualite-et-mise-en-ligne":3,"pieces-pratiques":721,"autour-\u002Fpratiques\u002Fqualite-et-mise-en-ligne":746,"prerequis-\u002Fpratiques\u002Fqualite-et-mise-en-ligne":750,"plan-pratiques":752},{"id":4,"title":5,"body":6,"description":683,"extension":684,"ligne":685,"meta":686,"motsCles":687,"navigation":256,"niveau":691,"path":692,"prerequis":693,"ressources":695,"seo":706,"sources":707,"stem":719,"__hash__":720},"docs\u002Fpratiques\u002F06.qualite-et-mise-en-ligne.md","Qualité et mise en ligne",{"type":7,"value":8,"toc":671},"minimark",[9,14,27,31,35,39,46,72,79,109,112,116,122,167,185,189,196,203,319,322,335,350,354,361,364,385,392,396,399,414,421,425,432,439,495,513,519,523,526,622,625,629,667],[10,11,13],"h2",{"id":12},"ce-que-tu-vas-apprendre","Ce que tu vas apprendre",[15,16,17,21,24],"ul",{},[18,19,20],"li",{},"Détecter les erreurs et uniformiser le style automatiquement avec ESLint et Prettier.",[18,22,23],{},"Écrire un premier test et faire relire ton code par une pull request.",[18,25,26],{},"Préparer une mise en ligne : build, variables d'environnement de production et vérifications.",[10,28,30],{"id":29},"laisser-les-outils-vérifier-à-ta-place","Laisser les outils vérifier à ta place",[32,33,34],"p",{},"Relire chaque ligne à la main est long et fatigant. Des outils le font en quelques secondes. Ils attrapent les fautes de frappe, les variables inutilisées et les différences de style avant qu'un humain n'ait à s'en occuper.",[10,36,38],{"id":37},"eslint-repérer-les-problèmes","ESLint : repérer les problèmes",[32,40,41,45],{},[42,43,44],"strong",{},"ESLint"," analyse ton code JavaScript sans l'exécuter et signale les erreurs probables : variable jamais utilisée, nom inexistant, mauvaise habitude. Pour l'installer dans un projet, la documentation propose :",[47,48,53],"pre",{"className":49,"code":50,"language":51,"meta":52,"style":52},"language-bash shiki shiki-themes github-light-default github-dark-default github-dark-default","npm init @eslint\u002Fconfig@latest\n","bash","",[54,55,56],"code",{"__ignoreMap":52},[57,58,61,65,69],"span",{"class":59,"line":60},"line",1,[57,62,64],{"class":63},"sIXEE","npm",[57,66,68],{"class":67},"shWOn"," init",[57,70,71],{"class":67}," @eslint\u002Fconfig@latest\n",[32,73,74,75,78],{},"Un assistant pose quelques questions et crée le fichier de configuration ",[54,76,77],{},"eslint.config.js",". Ensuite, lance l'analyse :",[47,80,82],{"className":49,"code":81,"language":51,"meta":52,"style":52},"npx eslint .\nnpx eslint . --fix\n",[54,83,84,95],{"__ignoreMap":52},[57,85,86,89,92],{"class":59,"line":60},[57,87,88],{"class":63},"npx",[57,90,91],{"class":67}," eslint",[57,93,94],{"class":67}," .\n",[57,96,98,100,102,105],{"class":59,"line":97},2,[57,99,88],{"class":63},[57,101,91],{"class":67},[57,103,104],{"class":67}," .",[57,106,108],{"class":107},"s5iOY"," --fix\n",[32,110,111],{},"La seconde commande corrige automatiquement ce qui peut l'être. Le reste est à corriger à la main, en lisant le message : chaque règle a un nom, et la documentation l'explique.",[10,113,115],{"id":114},"prettier-un-style-unique","Prettier : un style unique",[32,117,118,121],{},[42,119,120],{},"Prettier"," réécrit ton code avec une mise en forme cohérente : indentation, guillemets, retours à la ligne. Plus de débats sur le style dans une équipe.",[47,123,125],{"className":49,"code":124,"language":51,"meta":52,"style":52},"npm install --save-dev --save-exact prettier\nnpx prettier . --write\nnpx prettier . --check\n",[54,126,127,143,155],{"__ignoreMap":52},[57,128,129,131,134,137,140],{"class":59,"line":60},[57,130,64],{"class":63},[57,132,133],{"class":67}," install",[57,135,136],{"class":107}," --save-dev",[57,138,139],{"class":107}," --save-exact",[57,141,142],{"class":67}," prettier\n",[57,144,145,147,150,152],{"class":59,"line":97},[57,146,88],{"class":63},[57,148,149],{"class":67}," prettier",[57,151,104],{"class":67},[57,153,154],{"class":107}," --write\n",[57,156,158,160,162,164],{"class":59,"line":157},3,[57,159,88],{"class":63},[57,161,149],{"class":67},[57,163,104],{"class":67},[57,165,166],{"class":107}," --check\n",[32,168,169,172,173,176,177,180,181,184],{},[54,170,171],{},"--write"," modifie les fichiers. ",[54,174,175],{},"--check"," vérifie sans rien changer, ce qui sert dans une vérification automatique. Un fichier ",[54,178,179],{},".prettierrc"," à la racine peut contenir des options, ou simplement ",[54,182,183],{},"{}"," pour garder les valeurs par défaut.",[10,186,188],{"id":187},"un-premier-test","Un premier test",[32,190,191,192,195],{},"Un ",[42,193,194],{},"test"," est du code qui vérifie qu'un autre code fait ce qu'il doit. Il te protège quand tu modifies quelque chose : si un test casse, tu le sais tout de suite.",[32,197,198,199,202],{},"Node.js inclut un lanceur de tests. Voici un test pour la fonction ",[54,200,201],{},"calculerDuree"," du site de recettes :",[47,204,209],{"className":205,"code":206,"filename":207,"language":208,"meta":52,"style":52},"language-js shiki shiki-themes github-light-default github-dark-default github-dark-default","import { test } from 'node:test'\nimport assert from 'node:assert'\nimport { calculerDuree } from '.\u002Fduree.js'\n\ntest('additionne préparation et cuisson', () => {\n  assert.strictEqual(calculerDuree({ preparation: 15, cuisson: 30 }), 45)\n})\n","duree.test.js","js",[54,210,211,227,239,251,258,279,313],{"__ignoreMap":52},[57,212,213,217,221,224],{"class":59,"line":60},[57,214,216],{"class":215},"sOnC1","import",[57,218,220],{"class":219},"scfrF"," { test } ",[57,222,223],{"class":215},"from",[57,225,226],{"class":67}," 'node:test'\n",[57,228,229,231,234,236],{"class":59,"line":97},[57,230,216],{"class":215},[57,232,233],{"class":219}," assert ",[57,235,223],{"class":215},[57,237,238],{"class":67}," 'node:assert'\n",[57,240,241,243,246,248],{"class":59,"line":157},[57,242,216],{"class":215},[57,244,245],{"class":219}," { calculerDuree } ",[57,247,223],{"class":215},[57,249,250],{"class":67}," '.\u002Fduree.js'\n",[57,252,254],{"class":59,"line":253},4,[57,255,257],{"emptyLinePlaceholder":256},true,"\n",[57,259,261,264,267,270,273,276],{"class":59,"line":260},5,[57,262,194],{"class":263},"syCW7",[57,265,266],{"class":219},"(",[57,268,269],{"class":67},"'additionne préparation et cuisson'",[57,271,272],{"class":219},", () ",[57,274,275],{"class":215},"=>",[57,277,278],{"class":219}," {\n",[57,280,282,285,288,290,292,295,298,301,304,307,310],{"class":59,"line":281},6,[57,283,284],{"class":219},"  assert.",[57,286,287],{"class":263},"strictEqual",[57,289,266],{"class":219},[57,291,201],{"class":263},[57,293,294],{"class":219},"({ preparation: ",[57,296,297],{"class":107},"15",[57,299,300],{"class":219},", cuisson: ",[57,302,303],{"class":107},"30",[57,305,306],{"class":219}," }), ",[57,308,309],{"class":107},"45",[57,311,312],{"class":219},")\n",[57,314,316],{"class":59,"line":315},7,[57,317,318],{"class":219},"})\n",[32,320,321],{},"Lance-le avec :",[47,323,325],{"className":49,"code":324,"language":51,"meta":52,"style":52},"node --test\n",[54,326,327],{"__ignoreMap":52},[57,328,329,332],{"class":59,"line":60},[57,330,331],{"class":63},"node",[57,333,334],{"class":107}," --test\n",[32,336,337,338,341,342,345,346,349],{},"Si tu préfères un outil plus complet, ",[42,339,340],{},"Vitest"," s'installe avec ",[54,343,344],{},"npm install -D vitest"," et se lance avec ",[54,347,348],{},"npx vitest",".",[10,351,353],{"id":352},"la-revue-de-code-et-les-pull-requests","La revue de code et les pull requests",[32,355,356,357,360],{},"Une ",[42,358,359],{},"pull request"," (« requête de tirage » dans la documentation GitHub) propose de fusionner une branche dans une autre. Avant la fusion, d'autres personnes relisent les changements, commentent et demandent des modifications.",[32,362,363],{},"Les bonnes pratiques :",[365,366,367,370,373,379,382],"ol",{},[18,368,369],{},"Garde la pull request petite : un sujet à la fois.",[18,371,372],{},"Décris ce qui change, pourquoi, et comment le tester.",[18,374,375,376,349],{},"Relie l'issue avec ",[54,377,378],{},"Closes #12",[18,380,381],{},"Relis ton propre diff avant de demander une relecture.",[18,383,384],{},"Reçois les remarques comme une aide pour le code, pas comme une critique de toi.",[32,386,387,388,391],{},"GitHub permet d'ajouter un ",[42,389,390],{},"modèle de pull request"," pour que chaque proposition suive la même trame. Même seul, ouvrir une pull request pour tes propres changements te force à relire avant de fusionner.",[10,393,395],{"id":394},"préparer-la-mise-en-ligne","Préparer la mise en ligne",[32,397,398],{},"Mettre en ligne, c'est transformer ton projet de développement en version optimisée pour le public. Avec Nuxt, la commande est :",[47,400,402],{"className":49,"code":401,"language":51,"meta":52,"style":52},"npm run build\n",[54,403,404],{"__ignoreMap":52},[57,405,406,408,411],{"class":59,"line":60},[57,407,64],{"class":63},[57,409,410],{"class":67}," run",[57,412,413],{"class":67}," build\n",[32,415,416,417,420],{},"Elle produit le dossier ",[54,418,419],{},".output",". Le résultat est ce que ton hébergeur exécute, pas ton code source.",[10,422,424],{"id":423},"les-variables-denvironnement-en-production","Les variables d'environnement en production",[32,426,427,428,431],{},"Le fichier ",[54,429,430],{},".env"," est lu par Nuxt en développement et au moment du build, mais pas par le serveur compilé en production. Tu dois définir les variables dans l'interface de ton hébergeur, avec les mêmes noms.",[32,433,434,435,438],{},"Dans Nuxt, la configuration d'exécution se déclare dans ",[54,436,437],{},"nuxt.config.ts"," :",[47,440,444],{"className":441,"code":442,"filename":437,"language":443,"meta":52,"style":52},"language-ts shiki shiki-themes github-light-default github-dark-default github-dark-default","export default defineNuxtConfig({\n  runtimeConfig: {\n    apiSecret: '',\n    public: { apiBase: '' }\n  }\n})\n","ts",[54,445,446,460,465,476,486,491],{"__ignoreMap":52},[57,447,448,451,454,457],{"class":59,"line":60},[57,449,450],{"class":215},"export",[57,452,453],{"class":215}," default",[57,455,456],{"class":263}," defineNuxtConfig",[57,458,459],{"class":63},"({\n",[57,461,462],{"class":59,"line":97},[57,463,464],{"class":219},"  runtimeConfig: {\n",[57,466,467,470,473],{"class":59,"line":157},[57,468,469],{"class":219},"    apiSecret: ",[57,471,472],{"class":67},"''",[57,474,475],{"class":219},",\n",[57,477,478,481,483],{"class":59,"line":253},[57,479,480],{"class":219},"    public: { apiBase: ",[57,482,472],{"class":67},[57,484,485],{"class":219}," }\n",[57,487,488],{"class":59,"line":260},[57,489,490],{"class":219},"  }\n",[57,492,493],{"class":59,"line":281},[57,494,318],{"class":63},[32,496,497,498,501,502,505,506,509,510,349],{},"Les variables ",[54,499,500],{},"NUXT_API_SECRET"," et ",[54,503,504],{},"NUXT_PUBLIC_API_BASE"," remplacent ces valeurs au démarrage. Tout ce qui est sous ",[54,507,508],{},"public"," est visible par les visiteurs : n'y mets jamais de secret. Lis les valeurs avec ",[54,511,512],{},"useRuntimeConfig()",[514,515,516],"warning",{},[32,517,518],{},"Utilise des clés différentes pour le développement et la production. Si une clé de test fuite, ton site réel n'est pas touché.",[10,520,522],{"id":521},"vérifier-avant-de-déployer","Vérifier avant de déployer",[32,524,525],{},"Une liste de contrôle à parcourir à chaque mise en ligne :",[527,528,529,542],"table",{},[530,531,532],"thead",{},[533,534,535,539],"tr",{},[536,537,538],"th",{},"Vérification",[536,540,541],{},"Comment",[543,544,545,560,574,585,593,603,611],"tbody",{},[533,546,547,551],{},[548,549,550],"td",{},"Le code est propre",[548,552,553,501,556,559],{},[54,554,555],{},"npx eslint .",[54,557,558],{},"npx prettier . --check"," sans erreur.",[533,561,562,565],{},[548,563,564],{},"Les tests passent",[548,566,567,570,571,349],{},[54,568,569],{},"node --test"," ou ",[54,572,573],{},"npx vitest run",[533,575,576,579],{},[548,577,578],{},"Les dépendances sont saines",[548,580,581,584],{},[54,582,583],{},"npm audit"," sans faille grave.",[533,586,587,590],{},[548,588,589],{},"Aucun secret dans le dépôt",[548,591,592],{},"Recherche dans l'historique et dans le code.",[533,594,595,598],{},[548,596,597],{},"Le build réussit",[548,599,600,559],{},[54,601,602],{},"npm run build",[533,604,605,608],{},[548,606,607],{},"Les variables de production existent",[548,609,610],{},"Contrôle dans l'interface de l'hébergeur.",[533,612,613,616],{},[548,614,615],{},"Le site est en HTTPS",[548,617,618,619,349],{},"L'adresse commence par ",[54,620,621],{},"https:\u002F\u002F",[32,623,624],{},"Après le déploiement, ouvre le site, vérifie la console du navigateur et teste le parcours principal. Garde sous la main le moyen de revenir à la version précédente.",[10,626,628],{"id":627},"à-retenir","À retenir",[15,630,631,638,647,653,656,664],{},[18,632,633,634,637],{},"ESLint repère les erreurs probables, ",[54,635,636],{},"npx eslint . --fix"," corrige ce qui est automatique.",[18,639,640,641,643,644,646],{},"Prettier uniformise le style, ",[54,642,175],{}," vérifie et ",[54,645,171],{}," réécrit.",[18,648,649,650,652],{},"Un test vérifie une fonction et se lance avec ",[54,651,569],{}," ou Vitest.",[18,654,655],{},"Une pull request petite, décrite et relue vaut mieux qu'un gros envoi sans explication.",[18,657,658,660,661,663],{},[54,659,602],{}," prépare le site, mais le ",[54,662,430],{}," n'est pas lu par le serveur en production.",[18,665,666],{},"Passe une liste de vérifications avant chaque déploiement, puis teste le site en ligne.",[668,669,670],"style",{},"html pre.shiki code .sIXEE, html code.shiki .sIXEE{--shiki-light:#953800;--shiki-default:#FFA657;--shiki-dark:#FFA657}html pre.shiki code .shWOn, html code.shiki .shWOn{--shiki-light:#0A3069;--shiki-default:#A5D6FF;--shiki-dark:#A5D6FF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}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);}html pre.shiki code .s5iOY, html code.shiki .s5iOY{--shiki-light:#0550AE;--shiki-default:#79C0FF;--shiki-dark:#79C0FF}html pre.shiki code .sOnC1, html code.shiki .sOnC1{--shiki-light:#CF222E;--shiki-default:#FF7B72;--shiki-dark:#FF7B72}html pre.shiki code .scfrF, html code.shiki .scfrF{--shiki-light:#1F2328;--shiki-default:#E6EDF3;--shiki-dark:#E6EDF3}html pre.shiki code .syCW7, html code.shiki .syCW7{--shiki-light:#8250DF;--shiki-default:#D2A8FF;--shiki-dark:#D2A8FF}",{"title":52,"searchDepth":97,"depth":157,"links":672},[673,674,675,676,677,678,679,680,681,682],{"id":12,"depth":97,"text":13},{"id":29,"depth":97,"text":30},{"id":37,"depth":97,"text":38},{"id":114,"depth":97,"text":115},{"id":187,"depth":97,"text":188},{"id":352,"depth":97,"text":353},{"id":394,"depth":97,"text":395},{"id":423,"depth":97,"text":424},{"id":521,"depth":97,"text":522},{"id":627,"depth":97,"text":628},"Garder un code propre avec ESLint, Prettier et des tests, passer par une revue de code, puis déployer avec les bonnes variables d'environnement.","md","pratiques",{},[44,120,194,340,359,688,689,690],"revue de code","build","variables d'environnement","avance","\u002Fpratiques\u002Fqualite-et-mise-en-ligne",[694],"\u002Fpratiques\u002Fsecurite-de-base",[696,700,703],{"nom":697,"url":698,"type":699},"GitHub Docs, Requêtes de tirage","https:\u002F\u002Fdocs.github.com\u002Ffr\u002Fpull-requests\u002Fcollaborating-with-pull-requests\u002Fproposing-changes-to-your-work-with-pull-requests\u002Fabout-pull-requests","doc",{"nom":701,"url":702,"type":699},"GitHub Docs, Création d'un modèle de pull request","https:\u002F\u002Fdocs.github.com\u002Ffr\u002Fcommunities\u002Fusing-templates-to-encourage-useful-issues-and-pull-requests\u002Fcreating-a-pull-request-template-for-your-repository",{"nom":704,"url":705,"type":699,"anglais":256},"Documentation d'ESLint","https:\u002F\u002Feslint.org\u002Fdocs\u002Flatest\u002Fuse\u002Fgetting-started",{"title":5,"description":683},[708,710,713,716],{"nom":709,"url":705},"Documentation d'ESLint (en anglais)",{"nom":711,"url":712},"Documentation de Prettier (en anglais)","https:\u002F\u002Fprettier.io\u002Fdocs\u002Finstall",{"nom":714,"url":715},"Documentation de Node.js, test runner (en anglais)","https:\u002F\u002Fnodejs.org\u002Fapi\u002Ftest.html",{"nom":717,"url":718},"Documentation de Nuxt, Runtime Config (en anglais)","https:\u002F\u002Fnuxt.com\u002Fdocs\u002F4.x\u002Fguide\u002Fgoing-further\u002Fruntime-config","pratiques\u002F06.qualite-et-mise-en-ligne","i7sMnu3rHEjD8SgHiFKmp5L1SHYM707JI0rkwfu1JJI",[722,726,730,734,738,741,742],{"path":723,"title":724,"stem":725},"\u002Fpratiques\u002Fnommer-et-organiser","Nommer et organiser son code","pratiques\u002F01.nommer-et-organiser",{"path":727,"title":728,"stem":729},"\u002Fpratiques\u002Flire-une-erreur","Lire une erreur","pratiques\u002F02.lire-une-erreur",{"path":731,"title":732,"stem":733},"\u002Fpratiques\u002Fdeboguer","Déboguer méthodiquement","pratiques\u002F03.deboguer",{"path":735,"title":736,"stem":737},"\u002Fpratiques\u002Fgerer-un-projet","Gérer un projet","pratiques\u002F04.gerer-un-projet",{"path":694,"title":739,"stem":740},"Sécurité de base","pratiques\u002F05.securite-de-base",{"path":692,"title":5,"stem":719},{"path":743,"title":744,"stem":745},"\u002Fpratiques","Bonnes pratiques","pratiques\u002Findex",[747,749],{"title":739,"path":694,"stem":740,"description":748,"children":-1},"Protéger les secrets avec .env, ne pas faire confiance aux entrées des utilisateurs, surveiller les dépendances et utiliser HTTPS.",null,[751],{"path":694,"title":739,"ligne":685},[753,755,756,757,759,760,761],{"path":723,"title":724,"niveau":754,"stem":725},"debutant",{"path":727,"title":728,"niveau":754,"stem":729},{"path":731,"title":732,"niveau":754,"stem":733},{"path":735,"title":736,"niveau":758,"stem":737},"intermediaire",{"path":694,"title":739,"niveau":758,"stem":740},{"path":692,"title":5,"niveau":691,"stem":719},{"path":743,"title":744,"niveau":762,"stem":745},"memo",1794583452682]