[{"data":1,"prerenderedAt":840},["ShallowReactive",2],{"page-\u002Fsupabase\u002Fbrancher-a-nuxt":3,"pieces-supabase":797,"autour-\u002Fsupabase\u002Fbrancher-a-nuxt":822,"prerequis-\u002Fsupabase\u002Fbrancher-a-nuxt":827,"plan-supabase":829},{"id":4,"title":5,"body":6,"description":767,"extension":768,"ligne":769,"meta":770,"motsCles":771,"navigation":352,"niveau":776,"path":777,"prerequis":778,"ressources":780,"seo":788,"sources":789,"stem":795,"__hash__":796},"docs\u002Fsupabase\u002F02.brancher-a-nuxt.md","Brancher Supabase à Nuxt",{"type":7,"value":8,"toc":757},"minimark",[9,14,36,40,44,75,82,124,132,136,142,165,183,194,198,208,217,223,227,230,278,285,288,292,298,541,550,553,557,568,676,683,690,700,704,753],[10,11,13],"h2",{"id":12},"ce-que-tu-vas-apprendre","Ce que tu vas apprendre",[15,16,17,26,33],"ul",{},[18,19,20,21,25],"li",{},"Installer et déclarer le module ",[22,23,24],"code",{},"@nuxtjs\u002Fsupabase",".",[18,27,28,29,32],{},"Renseigner l'adresse du projet et les clés dans un fichier ",[22,30,31],{},".env"," qui ne part jamais dans Git.",[18,34,35],{},"Savoir ce qui se passe côté navigateur et ce qui reste côté serveur.",[10,37,39],{"id":38},"installer-le-module","Installer le module",[41,42,43],"p",{},"Dans ton projet Nuxt, une commande installe le module et l'ajoute à la configuration :",[45,46,51],"pre",{"className":47,"code":48,"language":49,"meta":50,"style":50},"language-bash shiki shiki-themes github-light-default github-dark-default github-dark-default","npx nuxi@latest module add supabase\n","bash","",[22,52,53],{"__ignoreMap":50},[54,55,58,62,66,69,72],"span",{"class":56,"line":57},"line",1,[54,59,61],{"class":60},"sIXEE","npx",[54,63,65],{"class":64},"shWOn"," nuxi@latest",[54,67,68],{"class":64}," module",[54,70,71],{"class":64}," add",[54,73,74],{"class":64}," supabase\n",[41,76,77,78,81],{},"Vérifie ensuite que ",[22,79,80],{},"nuxt.config.ts"," le déclare :",[45,83,87],{"className":84,"code":85,"filename":80,"language":86,"meta":50,"style":50},"language-ts shiki shiki-themes github-light-default github-dark-default github-dark-default","export default defineNuxtConfig({\n  modules: ['@nuxtjs\u002Fsupabase']\n})\n","ts",[22,88,89,105,118],{"__ignoreMap":50},[54,90,91,95,98,102],{"class":56,"line":57},[54,92,94],{"class":93},"sOnC1","export",[54,96,97],{"class":93}," default",[54,99,101],{"class":100},"syCW7"," defineNuxtConfig",[54,103,104],{"class":60},"({\n",[54,106,108,112,115],{"class":56,"line":107},2,[54,109,111],{"class":110},"scfrF","  modules: [",[54,113,114],{"class":64},"'@nuxtjs\u002Fsupabase'",[54,116,117],{"class":110},"]\n",[54,119,121],{"class":56,"line":120},3,[54,122,123],{"class":60},"})\n",[41,125,126,127,131],{},"Un ",[128,129,130],"strong",{},"module"," Nuxt est une extension qui ajoute des fonctions prêtes à l'emploi à ton projet. Celui-ci apporte le client Supabase, la gestion de la session et des fonctions pour le serveur.",[10,133,135],{"id":134},"les-variables-denvironnement","Les variables d'environnement",[41,137,138,139,141],{},"Crée un fichier ",[22,140,31],{}," à la racine du projet :",[45,143,147],{"className":144,"code":145,"filename":31,"language":146,"meta":50,"style":50},"language-ini shiki shiki-themes github-light-default github-dark-default github-dark-default","NUXT_PUBLIC_SUPABASE_URL=https:\u002F\u002Fxxxx.supabase.co\nNUXT_PUBLIC_SUPABASE_KEY=sb_publishable_...\n","ini",[22,148,149,157],{"__ignoreMap":50},[54,150,151,154],{"class":56,"line":57},[54,152,153],{"class":93},"NUXT_PUBLIC_SUPABASE_URL",[54,155,156],{"class":110},"=https:\u002F\u002Fxxxx.supabase.co\n",[54,158,159,162],{"class":56,"line":107},[54,160,161],{"class":93},"NUXT_PUBLIC_SUPABASE_KEY",[54,163,164],{"class":110},"=sb_publishable_...\n",[41,166,167,168,171,172,175,176,179,180,25],{},"Une ",[128,169,170],{},"variable d'environnement"," est un réglage stocké hors du code, propre à chaque machine. L'adresse vient du dialogue ",[128,173,174],{},"Connect"," du tableau de bord, la clé de ",[128,177,178],{},"Settings",", ",[128,181,182],{},"API Keys",[41,184,185,186,189,190,193],{},"Le module lit ces noms. Les anciens ",[22,187,188],{},"SUPABASE_URL"," et ",[22,191,192],{},"SUPABASE_KEY"," fonctionnent encore comme solution de repli.",[10,195,197],{"id":196},"protéger-le-fichier-env","Protéger le fichier .env",[41,199,200,201,203,204,207],{},"Le fichier ",[22,202,31],{}," doit être ignoré par Git. Vérifie que ton ",[22,205,206],{},".gitignore"," contient la ligne :",[45,209,211],{"className":144,"code":210,"filename":206,"language":146,"meta":50,"style":50},".env\n",[22,212,213],{"__ignoreMap":50},[54,214,215],{"class":56,"line":57},[54,216,210],{"class":110},[218,219,220],"warning",{},[41,221,222],{},"Un secret commité reste dans l'historique de Git, même après suppression. Si une clé secrète est partie sur GitHub, révoque-la dans le tableau de bord et crée-en une nouvelle.",[10,224,226],{"id":225},"quelle-clé-pour-quoi","Quelle clé pour quoi ?",[41,228,229],{},"Le module connaît deux clés :",[231,232,233,249],"table",{},[234,235,236],"thead",{},[237,238,239,243,246],"tr",{},[240,241,242],"th",{},"Variable",[240,244,245],{},"Contenu",[240,247,248],{},"Où elle vit",[250,251,252,265],"tbody",{},[237,253,254,259,262],{},[255,256,257],"td",{},[22,258,161],{},[255,260,261],{},"Clé publishable",[255,263,264],{},"Navigateur et serveur",[237,266,267,272,275],{},[255,268,269],{},[22,270,271],{},"NUXT_SUPABASE_SECRET_KEY",[255,273,274],{},"Clé secrète",[255,276,277],{},"Serveur uniquement",[41,279,280,281,284],{},"Les variables qui commencent par ",[22,282,283],{},"NUXT_PUBLIC_"," sont envoyées au navigateur. C'est voulu pour la clé publishable.",[41,286,287],{},"La clé secrète n'a pas ce préfixe. Elle ne sert qu'à un code que tu exécutes sur ton serveur, et tu n'en as pas besoin pour ce cours. Ne l'ajoute que le jour où un cas précis l'exige.",[10,289,291],{"id":290},"tester-la-connexion-côté-page","Tester la connexion côté page",[41,293,294,297],{},[22,295,296],{},"useSupabaseClient()"," est disponible dans toutes tes pages, sans import :",[45,299,304],{"className":300,"code":301,"filename":302,"language":303,"meta":50,"style":50},"language-vue shiki shiki-themes github-light-default github-dark-default github-dark-default","\u003Cscript setup lang=\"ts\">\nconst supabase = useSupabaseClient()\n\nconst { data: recettes } = await useAsyncData('recettes', async () => {\n  const { data } = await supabase.from('recettes').select('id, titre')\n  return data\n})\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cul>\n    \u003Cli v-for=\"r in recettes\" :key=\"r.id\">{{ r.titre }}\u003C\u002Fli>\n  \u003C\u002Ful>\n\u003C\u002Ftemplate>\n","app\u002Fpages\u002Frecettes.vue","vue",[22,305,306,331,348,354,402,442,451,456,466,471,481,491,522,532],{"__ignoreMap":50},[54,307,308,311,315,319,322,325,328],{"class":56,"line":57},[54,309,310],{"class":110},"\u003C",[54,312,314],{"class":313},"s5JFL","script",[54,316,318],{"class":317},"s5iOY"," setup",[54,320,321],{"class":317}," lang",[54,323,324],{"class":110},"=",[54,326,327],{"class":64},"\"ts\"",[54,329,330],{"class":110},">\n",[54,332,333,336,339,342,345],{"class":56,"line":107},[54,334,335],{"class":93},"const",[54,337,338],{"class":317}," supabase",[54,340,341],{"class":93}," =",[54,343,344],{"class":100}," useSupabaseClient",[54,346,347],{"class":110},"()\n",[54,349,350],{"class":56,"line":120},[54,351,353],{"emptyLinePlaceholder":352},true,"\n",[54,355,357,359,362,365,368,371,374,376,379,382,385,388,390,393,396,399],{"class":56,"line":356},4,[54,358,335],{"class":93},[54,360,361],{"class":110}," { ",[54,363,364],{"class":60},"data",[54,366,367],{"class":110},": ",[54,369,370],{"class":317},"recettes",[54,372,373],{"class":110}," } ",[54,375,324],{"class":93},[54,377,378],{"class":93}," await",[54,380,381],{"class":100}," useAsyncData",[54,383,384],{"class":110},"(",[54,386,387],{"class":64},"'recettes'",[54,389,179],{"class":110},[54,391,392],{"class":93},"async",[54,394,395],{"class":110}," () ",[54,397,398],{"class":93},"=>",[54,400,401],{"class":110}," {\n",[54,403,405,408,410,412,414,416,418,421,424,426,428,431,434,436,439],{"class":56,"line":404},5,[54,406,407],{"class":93},"  const",[54,409,361],{"class":110},[54,411,364],{"class":317},[54,413,373],{"class":110},[54,415,324],{"class":93},[54,417,378],{"class":93},[54,419,420],{"class":110}," supabase.",[54,422,423],{"class":100},"from",[54,425,384],{"class":110},[54,427,387],{"class":64},[54,429,430],{"class":110},").",[54,432,433],{"class":100},"select",[54,435,384],{"class":110},[54,437,438],{"class":64},"'id, titre'",[54,440,441],{"class":110},")\n",[54,443,445,448],{"class":56,"line":444},6,[54,446,447],{"class":93},"  return",[54,449,450],{"class":110}," data\n",[54,452,454],{"class":56,"line":453},7,[54,455,123],{"class":110},[54,457,459,462,464],{"class":56,"line":458},8,[54,460,461],{"class":110},"\u003C\u002F",[54,463,314],{"class":313},[54,465,330],{"class":110},[54,467,469],{"class":56,"line":468},9,[54,470,353],{"emptyLinePlaceholder":352},[54,472,474,476,479],{"class":56,"line":473},10,[54,475,310],{"class":110},[54,477,478],{"class":313},"template",[54,480,330],{"class":110},[54,482,484,487,489],{"class":56,"line":483},11,[54,485,486],{"class":110},"  \u003C",[54,488,15],{"class":313},[54,490,330],{"class":110},[54,492,494,497,499,502,504,507,510,512,515,518,520],{"class":56,"line":493},12,[54,495,496],{"class":110},"    \u003C",[54,498,18],{"class":313},[54,500,501],{"class":317}," v-for",[54,503,324],{"class":110},[54,505,506],{"class":64},"\"r in recettes\"",[54,508,509],{"class":317}," :key",[54,511,324],{"class":110},[54,513,514],{"class":64},"\"r.id\"",[54,516,517],{"class":110},">{{ r.titre }}\u003C\u002F",[54,519,18],{"class":313},[54,521,330],{"class":110},[54,523,525,528,530],{"class":56,"line":524},13,[54,526,527],{"class":110},"  \u003C\u002F",[54,529,15],{"class":313},[54,531,330],{"class":110},[54,533,535,537,539],{"class":56,"line":534},14,[54,536,461],{"class":110},[54,538,478],{"class":313},[54,540,330],{"class":110},[41,542,543,546,547,25],{},[22,544,545],{},"useAsyncData"," charge les données avant l'affichage de la page. Si ta table contient des recettes, elles apparaissent sur ",[22,548,549],{},"\u002Frecettes",[41,551,552],{},"Si la liste reste vide alors que la table contient des lignes, c'est probablement la RLS qui bloque la lecture. Le cours 05 explique comment l'autoriser.",[10,554,556],{"id":555},"utiliser-supabase-dans-une-route-serveur","Utiliser Supabase dans une route serveur",[41,558,559,560,563,564,567],{},"Le code d'un dossier ",[22,561,562],{},"server\u002F"," s'exécute sur le serveur. Le module fournit ",[22,565,566],{},"serverSupabaseClient"," pour y créer un client :",[45,569,572],{"className":84,"code":570,"filename":571,"language":86,"meta":50,"style":50},"import { serverSupabaseClient } from '#supabase\u002Fserver'\n\nexport default eventHandler(async (event) => {\n  const client = await serverSupabaseClient(event)\n  const { data } = await client.from('recettes').select('*')\n  return { recettes: data }\n})\n","server\u002Fapi\u002Frecettes.get.ts",[22,573,574,587,591,611,628,662,669],{"__ignoreMap":50},[54,575,576,579,582,584],{"class":56,"line":57},[54,577,578],{"class":93},"import",[54,580,581],{"class":110}," { serverSupabaseClient } ",[54,583,423],{"class":93},[54,585,586],{"class":64}," '#supabase\u002Fserver'\n",[54,588,589],{"class":56,"line":107},[54,590,353],{"emptyLinePlaceholder":352},[54,592,593,595,597,600,602,604,607,609],{"class":56,"line":120},[54,594,94],{"class":93},[54,596,97],{"class":93},[54,598,599],{"class":100}," eventHandler",[54,601,384],{"class":60},[54,603,392],{"class":93},[54,605,606],{"class":60}," (event) ",[54,608,398],{"class":93},[54,610,401],{"class":110},[54,612,613,615,618,620,622,625],{"class":56,"line":356},[54,614,407],{"class":93},[54,616,617],{"class":317}," client",[54,619,341],{"class":93},[54,621,378],{"class":93},[54,623,624],{"class":100}," serverSupabaseClient",[54,626,627],{"class":110},"(event)\n",[54,629,630,632,634,636,638,640,642,645,647,649,651,653,655,657,660],{"class":56,"line":404},[54,631,407],{"class":93},[54,633,361],{"class":110},[54,635,364],{"class":317},[54,637,373],{"class":110},[54,639,324],{"class":93},[54,641,378],{"class":93},[54,643,644],{"class":110}," client.",[54,646,423],{"class":100},[54,648,384],{"class":110},[54,650,387],{"class":64},[54,652,430],{"class":110},[54,654,433],{"class":100},[54,656,384],{"class":110},[54,658,659],{"class":64},"'*'",[54,661,441],{"class":110},[54,663,664,666],{"class":56,"line":444},[54,665,447],{"class":93},[54,667,668],{"class":110}," { recettes: data }\n",[54,670,671,674],{"class":56,"line":453},[54,672,673],{"class":110},"}",[54,675,441],{"class":60},[41,677,678,679,682],{},"La fonction est asynchrone : il faut l'attendre avec ",[22,680,681],{},"await",". Elle reçoit l'événement de la requête pour retrouver la session de l'utilisateur.",[41,684,685,686,689],{},"Ce client utilise la clé publishable et reste soumis à la RLS. Pour contourner la RLS, le module propose une autre fonction, ",[22,687,688],{},"serverSupabaseServiceRole",", à réserver à des tâches d'administration.",[691,692,693],"note",{},[41,694,695,696,699],{},"Le module cherche aussi un fichier de types ",[22,697,698],{},"~\u002Ftypes\u002Fdatabase.types.ts"," pour typer les requêtes. C'est optionnel, tu peux l'ignorer au début.",[10,701,703],{"id":702},"à-retenir","À retenir",[15,705,706,714,724,732,742],{},[18,707,708,711,712,25],{},[22,709,710],{},"npx nuxi@latest module add supabase"," installe ",[22,713,24],{},[18,715,716,717,719,720,189,722,25],{},"L'adresse et la clé publishable vont dans ",[22,718,31],{},", sous ",[22,721,153],{},[22,723,161],{},[18,725,726,728,729,731],{},[22,727,31],{}," est dans ",[22,730,206],{},", toujours.",[18,733,734,735,737,738,741],{},"La clé secrète (",[22,736,271],{},") n'a pas de préfixe ",[22,739,740],{},"PUBLIC"," et ne sert que côté serveur.",[18,743,744,746,747,750,751,25],{},[22,745,296],{}," dans les pages, ",[22,748,749],{},"serverSupabaseClient(event)"," dans les routes de ",[22,752,562],{},[754,755,756],"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 .sOnC1, html code.shiki .sOnC1{--shiki-light:#CF222E;--shiki-default:#FF7B72;--shiki-dark:#FF7B72}html pre.shiki code .syCW7, html code.shiki .syCW7{--shiki-light:#8250DF;--shiki-default:#D2A8FF;--shiki-dark:#D2A8FF}html pre.shiki code .scfrF, html code.shiki .scfrF{--shiki-light:#1F2328;--shiki-default:#E6EDF3;--shiki-dark:#E6EDF3}html pre.shiki code .s5JFL, html code.shiki .s5JFL{--shiki-light:#116329;--shiki-default:#7EE787;--shiki-dark:#7EE787}html pre.shiki code .s5iOY, html code.shiki .s5iOY{--shiki-light:#0550AE;--shiki-default:#79C0FF;--shiki-dark:#79C0FF}",{"title":50,"searchDepth":107,"depth":120,"links":758},[759,760,761,762,763,764,765,766],{"id":12,"depth":107,"text":13},{"id":38,"depth":107,"text":39},{"id":134,"depth":107,"text":135},{"id":196,"depth":107,"text":197},{"id":225,"depth":107,"text":226},{"id":290,"depth":107,"text":291},{"id":555,"depth":107,"text":556},{"id":702,"depth":107,"text":703},"Installer le module @nuxtjs\u002Fsupabase, renseigner les variables d'environnement et savoir quelle clé va où.","md","supabase",{},[24,80,772,31,773,566,774,775],"variables d'environnement","useSupabaseClient","clé publishable","runtimeConfig","debutant","\u002Fsupabase\u002Fbrancher-a-nuxt",[779],"\u002Fsupabase\u002Fdecouvrir-supabase",[781,785],{"nom":782,"url":783,"type":784,"anglais":352},"Module Nuxt Supabase, documentation (en anglais)","https:\u002F\u002Fsupabase.nuxtjs.org\u002F","doc",{"nom":786,"url":787,"type":784,"anglais":352},"Supabase, démarrage rapide avec Nuxt (en anglais)","https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Fgetting-started\u002Fquickstarts\u002Fnuxtjs",{"title":5,"description":767},[790,792],{"nom":791,"url":783},"Module Nuxt Supabase (en anglais)",{"nom":793,"url":794},"Supabase, clés d'API (en anglais)","https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Fapi\u002Fapi-keys","supabase\u002F02.brancher-a-nuxt","6oCIWgl4mdOfnVnsltleojM8wwIEEls4XjsU_RXSSww",[798,801,802,806,810,814,818],{"path":779,"title":799,"stem":800},"Découvrir Supabase","supabase\u002F01.decouvrir-supabase",{"path":777,"title":5,"stem":795},{"path":803,"title":804,"stem":805},"\u002Fsupabase\u002Flire-et-ecrire","Lire et écrire des données","supabase\u002F03.lire-et-ecrire",{"path":807,"title":808,"stem":809},"\u002Fsupabase\u002Fauthentification","Authentification","supabase\u002F04.authentification",{"path":811,"title":812,"stem":813},"\u002Fsupabase\u002Frow-level-security","Row Level Security","supabase\u002F05.row-level-security",{"path":815,"title":816,"stem":817},"\u002Fsupabase\u002Fstockage-et-temps-reel","Stockage et temps réel","supabase\u002F06.stockage-et-temps-reel",{"path":819,"title":820,"stem":821},"\u002Fsupabase","Supabase","supabase\u002Findex",[823,825],{"title":799,"path":779,"stem":800,"description":824,"children":-1},"Ce qu'est Supabase, comment créer un projet et une première table de recettes, et quelle clé peut être publique.",{"title":804,"path":803,"stem":805,"description":826,"children":-1},"Lire, ajouter, modifier et supprimer des lignes avec le client Supabase, en gérant les erreurs.",[828],{"path":779,"title":799,"ligne":769},[830,831,832,833,835,836,838],{"path":779,"title":799,"niveau":776,"stem":800},{"path":777,"title":5,"niveau":776,"stem":795},{"path":803,"title":804,"niveau":776,"stem":805},{"path":807,"title":808,"niveau":834,"stem":809},"intermediaire",{"path":811,"title":812,"niveau":834,"stem":813},{"path":815,"title":816,"niveau":837,"stem":817},"avance",{"path":819,"title":820,"niveau":839,"stem":821},"memo",1794583460441]