[{"data":1,"prerenderedAt":601},["ShallowReactive",2],{"article-\u002Fblog\u002Fcomprendre-architecture-nuxt-4":3},{"id":4,"title":5,"body":6,"brouillon":588,"date":589,"description":590,"extension":591,"image":592,"imageAlt":592,"meta":593,"navigation":264,"path":594,"seo":595,"stem":596,"tags":597,"__hash__":600},"blog\u002Fblog\u002Fcomprendre-architecture-nuxt-4.md","Comprendre l'architecture de Nuxt 4 : la carte du framework",{"type":7,"value":8,"toc":579},"minimark",[9,13,18,26,118,129,133,161,313,329,333,343,379,386,390,393,431,532,535,539,549,553,568,572,575],[10,11,12],"p",{},"Quand on arrive sur Nuxt en venant de Vue « nu », la première impression est\ndéroutante : beaucoup de choses semblent se produire toutes seules. Les\ncomposants s'importent sans qu'on les importe, une page apparaît dès qu'on\ncrée un fichier, une fonction serveur devient une URL. Ce n'est pas de la\nmagie, c'est une convention. Une fois la carte du framework en tête, Nuxt\ndevient très prévisible. Voici cette carte.",[14,15,17],"h2",{"id":16},"la-structure-de-dossiers","La structure de dossiers",[10,19,20,21,25],{},"En Nuxt 4, le code applicatif vit dans ",[22,23,24],"code",{},"app\u002F",", et le reste du projet\ns'organise autour. Chaque dossier a un rôle précis et une convention\nassociée :",[27,28,29,43,51,59,67,75,83,91,102,110],"ul",{},[30,31,32,38,39,42],"li",{},[33,34,35],"strong",{},[22,36,37],{},"app\u002Fpages\u002F"," : chaque fichier ",[22,40,41],{},".vue"," devient une route. C'est le\nrouting par fichiers (voir plus bas).",[30,44,45,50],{},[33,46,47],{},[22,48,49],{},"app\u002Fcomponents\u002F"," : les composants réutilisables, auto-importés dans\ntout le projet.",[30,52,53,58],{},[33,54,55],{},[22,56,57],{},"app\u002Fcomposables\u002F"," : la logique réactive réutilisable, elle aussi\nauto-importée.",[30,60,61,66],{},[33,62,63],{},[22,64,65],{},"app\u002Flayouts\u002F"," : les gabarits qui enveloppent les pages (en-tête,\npied de page, structure commune).",[30,68,69,74],{},[33,70,71],{},[22,72,73],{},"app\u002Fplugins\u002F"," : le code qui s'exécute à l'initialisation de\nl'application, côté client, serveur ou les deux.",[30,76,77,82],{},[33,78,79],{},[22,80,81],{},"app\u002Fmiddleware\u002F"," : les gardes de navigation, exécutés avant d'entrer\nsur une route (redirections, contrôle d'accès).",[30,84,85,90],{},[33,86,87],{},[22,88,89],{},"app\u002Fassets\u002F"," : les ressources traitées par le build (CSS, images\noptimisées, polices).",[30,92,93,98,99,101],{},[33,94,95],{},[22,96,97],{},"server\u002F"," : le code serveur, à la racine du projet et non dans\n",[22,100,24],{},", car il ne tourne jamais dans le navigateur.",[30,103,104,109],{},[33,105,106],{},[22,107,108],{},"public\u002F"," : les fichiers servis tels quels, sans transformation\n(favicon, robots.txt, images fixes).",[30,111,112,117],{},[33,113,114],{},[22,115,116],{},"nuxt.config.ts"," : le point de contrôle unique de toute la\nconfiguration.",[10,119,120,121,124,125,128],{},"La règle mentale est simple : ",[33,122,123],{},"le nom du dossier décrit son rôle, et le\nrôle impose la convention",". Vous ne choisissez pas où mettre un composable,\nvous le posez dans ",[22,126,127],{},"composables\u002F"," et Nuxt fait le reste.",[14,130,132],{"id":131},"les-auto-imports","Les auto-imports",[10,134,135,136,139,140,142,143,146,147,150,151,150,154,150,157,160],{},"C'est la fonctionnalité qui déroute le plus au début. Les composants de\n",[22,137,138],{},"components\u002F",", les fonctions de ",[22,141,127],{}," et ",[22,144,145],{},"utils\u002F",", ainsi que les\nutilitaires du framework (",[22,148,149],{},"ref",", ",[22,152,153],{},"computed",[22,155,156],{},"useRoute",[22,158,159],{},"useFetch",") sont\ndisponibles partout sans ligne d'import.",[162,163,168],"pre",{"className":164,"code":165,"language":166,"meta":167,"style":167},"language-vue shiki shiki-themes github-dark","\u003Cscript setup lang=\"ts\">\n\u002F\u002F Aucun import : ref, useRoute et MonComposant sont auto-importés\nconst route = useRoute()\nconst compteur = ref(0)\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003CMonComposant :id=\"route.params.id\" @clic=\"compteur++\" \u002F>\n\u003C\u002Ftemplate>\n","vue","",[22,169,170,200,207,227,249,259,266,276,304],{"__ignoreMap":167},[171,172,175,179,183,187,190,193,197],"span",{"class":173,"line":174},"line",1,[171,176,178],{"class":177},"s95oV","\u003C",[171,180,182],{"class":181},"s4JwU","script",[171,184,186],{"class":185},"svObZ"," setup",[171,188,189],{"class":185}," lang",[171,191,192],{"class":177},"=",[171,194,196],{"class":195},"sU2Wk","\"ts\"",[171,198,199],{"class":177},">\n",[171,201,203],{"class":173,"line":202},2,[171,204,206],{"class":205},"sAwPA","\u002F\u002F Aucun import : ref, useRoute et MonComposant sont auto-importés\n",[171,208,210,214,218,221,224],{"class":173,"line":209},3,[171,211,213],{"class":212},"snl16","const",[171,215,217],{"class":216},"sDLfK"," route",[171,219,220],{"class":212}," =",[171,222,223],{"class":185}," useRoute",[171,225,226],{"class":177},"()\n",[171,228,230,232,235,237,240,243,246],{"class":173,"line":229},4,[171,231,213],{"class":212},[171,233,234],{"class":216}," compteur",[171,236,220],{"class":212},[171,238,239],{"class":185}," ref",[171,241,242],{"class":177},"(",[171,244,245],{"class":216},"0",[171,247,248],{"class":177},")\n",[171,250,252,255,257],{"class":173,"line":251},5,[171,253,254],{"class":177},"\u003C\u002F",[171,256,182],{"class":181},[171,258,199],{"class":177},[171,260,262],{"class":173,"line":261},6,[171,263,265],{"emptyLinePlaceholder":264},true,"\n",[171,267,269,271,274],{"class":173,"line":268},7,[171,270,178],{"class":177},[171,272,273],{"class":181},"template",[171,275,199],{"class":177},[171,277,279,282,285,288,290,293,296,298,301],{"class":173,"line":278},8,[171,280,281],{"class":177},"  \u003C",[171,283,284],{"class":181},"MonComposant",[171,286,287],{"class":185}," :id",[171,289,192],{"class":177},[171,291,292],{"class":195},"\"route.params.id\"",[171,294,295],{"class":185}," @clic",[171,297,192],{"class":177},[171,299,300],{"class":195},"\"compteur++\"",[171,302,303],{"class":177}," \u002F>\n",[171,305,307,309,311],{"class":173,"line":306},9,[171,308,254],{"class":177},[171,310,273],{"class":181},[171,312,199],{"class":177},[10,314,315,316,319,320,150,322,324,325,328],{},"Ce n'est pas de la magie opaque : Nuxt génère des déclarations de types dans\n",[22,317,318],{},".nuxt\u002F"," pour que l'éditeur et TypeScript connaissent ces symboles. Le\nbénéfice est un code débarrassé de vingt lignes d'imports en haut de chaque\nfichier ; le prix est qu'il faut connaître la convention pour savoir d'où\nvient une fonction. La règle : si vous ne voyez pas l'import, cherchez dans\n",[22,321,127],{},[22,323,138],{}," ou la documentation des ",[22,326,327],{},"use*"," de Nuxt.",[14,330,332],{"id":331},"le-routing-par-fichiers","Le routing par fichiers",[10,334,335,336,338,339,342],{},"Il n'y a pas de fichier de routes à maintenir. L'arborescence de\n",[22,337,37],{}," ",[33,340,341],{},"est"," la table de routage :",[27,344,345,354,362,371],{},[30,346,347,350,351],{},[22,348,349],{},"pages\u002Findex.vue"," donne ",[22,352,353],{},"\u002F",[30,355,356,350,359],{},[22,357,358],{},"pages\u002Fblog\u002Findex.vue",[22,360,361],{},"\u002Fblog",[30,363,364,350,367,370],{},[22,365,366],{},"pages\u002Fblog\u002F[slug].vue",[22,368,369],{},"\u002Fblog\u002Fmon-article"," (segment dynamique)",[30,372,373,350,376],{},[22,374,375],{},"pages\u002Fprojets\u002F[slug].vue",[22,377,378],{},"\u002Fprojets\u002Fnom-du-projet",[10,380,381,382,385],{},"Le paramètre dynamique se lit avec ",[22,383,384],{},"useRoute().params.slug",". Ajouter une\npage, c'est ajouter un fichier ; supprimer une page, c'est supprimer un\nfichier. Le routeur suit toujours le disque.",[14,387,389],{"id":388},"les-modes-de-rendu","Les modes de rendu",[10,391,392],{},"C'est la décision d'architecture la plus structurante, et Nuxt la rend\nsouple. Le même code peut être servi de plusieurs façons :",[27,394,395,401,411,417],{},[30,396,397,400],{},[33,398,399],{},"SSR"," (rendu serveur) : le HTML est généré à la demande sur le serveur,\npuis hydraté côté client. Idéal pour du contenu dynamique et le SEO.",[30,402,403,406,407,410],{},[33,404,405],{},"SSG"," (génération statique, ",[22,408,409],{},"nuxi generate",") : tout le site est\npré-rendu en HTML au build, puis servi comme des fichiers. Idéal pour un\nsite vitrine ou un blog. C'est le mode de ce site.",[30,412,413,416],{},[33,414,415],{},"SPA"," : rendu uniquement côté client, pour une application derrière une\nauthentification où le SEO n'importe pas.",[30,418,419,422,423,426,427,430],{},[33,420,421],{},"Hybride"," : via ",[22,424,425],{},"routeRules"," dans ",[22,428,429],{},"nuxt.config",", on choisit le mode\nroute par route (une partie statique, une partie serveur, une partie en\ncache).",[162,432,436],{"className":433,"code":434,"language":435,"meta":167,"style":167},"language-typescript shiki shiki-themes github-dark","export default defineNuxtConfig({\n  routeRules: {\n    '\u002F': { prerender: true },          \u002F\u002F page d'accueil figée au build\n    '\u002Fblog\u002F**': { prerender: true },   \u002F\u002F articles statiques\n    '\u002Fapi\u002F**': { cors: true },         \u002F\u002F routes serveur dynamiques\n    '\u002Fadmin\u002F**': { ssr: false }        \u002F\u002F espace privé en SPA\n  }\n})\n","typescript",[22,437,438,452,457,474,489,505,522,527],{"__ignoreMap":167},[171,439,440,443,446,449],{"class":173,"line":174},[171,441,442],{"class":212},"export",[171,444,445],{"class":212}," default",[171,447,448],{"class":185}," defineNuxtConfig",[171,450,451],{"class":177},"({\n",[171,453,454],{"class":173,"line":202},[171,455,456],{"class":177},"  routeRules: {\n",[171,458,459,462,465,468,471],{"class":173,"line":209},[171,460,461],{"class":195},"    '\u002F'",[171,463,464],{"class":177},": { prerender: ",[171,466,467],{"class":216},"true",[171,469,470],{"class":177}," },          ",[171,472,473],{"class":205},"\u002F\u002F page d'accueil figée au build\n",[171,475,476,479,481,483,486],{"class":173,"line":229},[171,477,478],{"class":195},"    '\u002Fblog\u002F**'",[171,480,464],{"class":177},[171,482,467],{"class":216},[171,484,485],{"class":177}," },   ",[171,487,488],{"class":205},"\u002F\u002F articles statiques\n",[171,490,491,494,497,499,502],{"class":173,"line":251},[171,492,493],{"class":195},"    '\u002Fapi\u002F**'",[171,495,496],{"class":177},": { cors: ",[171,498,467],{"class":216},[171,500,501],{"class":177}," },         ",[171,503,504],{"class":205},"\u002F\u002F routes serveur dynamiques\n",[171,506,507,510,513,516,519],{"class":173,"line":261},[171,508,509],{"class":195},"    '\u002Fadmin\u002F**'",[171,511,512],{"class":177},": { ssr: ",[171,514,515],{"class":216},"false",[171,517,518],{"class":177}," }        ",[171,520,521],{"class":205},"\u002F\u002F espace privé en SPA\n",[171,523,524],{"class":173,"line":268},[171,525,526],{"class":177},"  }\n",[171,528,529],{"class":173,"line":278},[171,530,531],{"class":177},"})\n",[10,533,534],{},"Ne choisissez pas le mode par habitude : choisissez-le par besoin réel de\nchaque partie du site.",[14,536,538],{"id":537},"nitro-le-serveur-universel","Nitro : le serveur universel",[10,540,541,542,544,545,548],{},"Sous Nuxt, il y a Nitro, le moteur serveur. C'est lui qui exécute le SSR,\nqui sert le dossier ",[22,543,97],{},", et surtout qui permet de déployer le même\nprojet sur des cibles très différentes (Node, un hébergeur statique, un\nworker edge) sans changer le code. Quand vous écrivez une route dans\n",[22,546,547],{},"server\u002Fapi\u002F",", c'est Nitro qui la transforme en point d'accès HTTP. J'y\nreviens en détail dans l'article sur les applications fullstack.",[14,550,552],{"id":551},"les-modules","Les modules",[10,554,555,556,559,560,563,564,567],{},"Un module Nuxt est une extension qui s'installe et se configure en une\nligne, et qui apporte ses propres conventions. Ce site en utilise plusieurs :\n",[22,557,558],{},"@nuxt\u002Fcontent"," pour écrire les articles en Markdown, ",[22,561,562],{},"@nuxtjs\u002Fi18n"," pour le\nbilinguisme, ",[22,565,566],{},"@nuxtjs\u002Fseo"," pour les métadonnées et le sitemap. Un bon\nréflexe avant de coder une fonctionnalité transverse : vérifier s'il existe\ndéjà un module qui la fournit avec ses conventions éprouvées.",[14,569,571],{"id":570},"la-leçon","La leçon",[10,573,574],{},"Nuxt n'est pas Vue « avec des trucs en plus » : c'est un cadre de\nconventions qui répond à une seule question, « où va chaque chose ». Une\nfois la carte assimilée (un dossier par rôle, l'auto-import, le routing par\nfichiers, le mode de rendu choisi par besoin, Nitro derrière), le framework\ncesse de surprendre et devient un accélérateur. Le temps passé à comprendre\ncette structure au départ est remboursé sur chaque fonctionnalité ensuite.",[576,577,578],"style",{},"html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .s4JwU, html code.shiki .s4JwU{--shiki-default:#85E89D}html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}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);}",{"title":167,"searchDepth":202,"depth":202,"links":580},[581,582,583,584,585,586,587],{"id":16,"depth":202,"text":17},{"id":131,"depth":202,"text":132},{"id":331,"depth":202,"text":332},{"id":388,"depth":202,"text":389},{"id":537,"depth":202,"text":538},{"id":551,"depth":202,"text":552},{"id":570,"depth":202,"text":571},false,"2026-07-10","Dossiers, auto-imports, routing, modes de rendu, Nitro : une vue d'ensemble structurée de Nuxt 4 pour savoir où va chaque chose et pourquoi.","md",null,{},"\u002Fblog\u002Fcomprendre-architecture-nuxt-4",{"title":5,"description":590},"blog\u002Fcomprendre-architecture-nuxt-4",[598,599],"Nuxt","Architecture","PP9oRb5oRzRzA476-ltAOe3MAAh0PJXL6C4Ay2S4YhQ",1784652016702]