[{"data":1,"prerenderedAt":2019},["ShallowReactive",2],{"pt-BR-article-\u002Fblog\u002Fcomo-funciona-o-sistema-de-rotas-no-nuxt":3,"pt-BR-related-posts-\u002Fblog\u002Fcomo-funciona-o-sistema-de-rotas-no-nuxt":1859},{"id":4,"title":5,"articleCover":6,"articleCoverEmbed":7,"articleCoverEmbedUploadDate":7,"articleCoverHeight":8,"articleCoverWidth":9,"authorId":10,"body":11,"categoriesIds":1845,"description":1848,"enAlternateSlug":1849,"extension":1850,"meta":1851,"navigation":266,"path":1610,"ptBrAlternateSlug":195,"publishedAt":1852,"seo":1853,"sitemap":1854,"stem":1856,"updatedAt":1855,"wordCount":1857,"__hash__":1858},"blog\u002Fblog\u002Fcomo-funciona-o-sistema-de-rotas-no-nuxt.md","Rotas no Nuxt: dinâmicas, aninhadas e catch-all","\u002Fimages\u002Fblog\u002Fnuxt\u002Fsistema-de-rotas-no-nuxtjs-thumb.webp",null,720,1280,"thiago-nunes-batista",{"type":12,"value":13,"toc":1820},"minimark",[14,23,28,38,82,108,111,115,118,128,143,147,150,186,197,200,572,599,606,611,626,726,731,735,738,741,747,754,895,901,905,916,939,943,950,983,986,990,1003,1082,1085,1089,1099,1105,1128,1251,1354,1361,1365,1368,1446,1457,1461,1470,1662,1682,1686,1712,1716,1720,1733,1737,1746,1750,1763,1767,1779,1783,1802,1806,1816],[15,16,17,18,22],"p",{},"O Nuxt transforma os arquivos da pasta ",[19,20,21],"code",{},"pages"," em rotas. Este artigo mostra como esse mapeamento funciona no Nuxt 4, com slugs dinâmicos, rotas aninhadas, opcionais e catch-all, parâmetros de consulta e as escolhas de roteamento que afetam o SEO de um site real.",[24,25,27],"h2",{"id":26},"como-funciona-o-roteamento-baseado-em-arquivos-do-nuxt","Como funciona o roteamento baseado em arquivos do Nuxt",[15,29,30,31,34,35,37],{},"Todo arquivo ",[19,32,33],{},".vue"," dentro da pasta ",[19,36,21],{}," vira uma página, e a URL vem do caminho do arquivo:",[39,40,41,54],"table",{},[42,43,44],"thead",{},[45,46,47,51],"tr",{},[48,49,50],"th",{},"Arquivo",[48,52,53],{},"Rota",[55,56,57,66,74],"tbody",{},[45,58,59,63],{},[60,61,62],"td",{},"app\u002Fpages\u002Findex.vue",[60,64,65],{},"\u002F",[45,67,68,71],{},[60,69,70],{},"app\u002Fpages\u002Flinks.vue",[60,72,73],{},"\u002Flinks",[45,75,76,79],{},[60,77,78],{},"app\u002Fpages\u002Ftools\u002Fcpf-generator.vue",[60,80,81],{},"\u002Ftools\u002Fcpf-generator",[15,83,84,85,88,89,92,93,96,97,100,101,104,105,107],{},"No Nuxt 4, projetos novos guardam o código da aplicação dentro de um diretório ",[19,86,87],{},"app\u002F",". As páginas ficam em ",[19,90,91],{},"app\u002Fpages\u002F",", os layouts em ",[19,94,95],{},"app\u002Flayouts\u002F"," e os middlewares de rota em ",[19,98,99],{},"app\u002Fmiddleware\u002F",". Se você migrou do Nuxt 3 e ainda tem uma pasta ",[19,102,103],{},"pages\u002F"," na raiz, ela continua funcionando: o Nuxt detecta a estrutura antiga e não força a nova. Os exemplos abaixo usam os caminhos com ",[19,106,87],{},".",[15,109,110],{},"O sistema usa o Vue Router por baixo. O Nuxt gera a lista de rotas a partir dos seus arquivos, então raramente você precisa escrever uma configuração de roteador à mão.",[24,112,114],{"id":113},"rotas-estáticas","Rotas estáticas",[15,116,117],{},"Uma rota estática é uma página cuja URL nunca muda, como uma página institucional ou uma ferramenta:",[119,120,126],"pre",{"className":121,"code":123,"language":124,"meta":125},[122],"language-text","app\u002Fpages\u002F\n├── index.vue              -> \u002F\n├── about.vue              -> \u002Fabout\n├── privacy-policy.vue     -> \u002Fprivacy-policy\n└── tools\u002F\n    └── cpf-generator.vue  -> \u002Ftools\u002Fcpf-generator\n","text","",[19,127,123],{"__ignoreMap":125},[15,129,130,131,134,135,138,139,142],{},"Se a URL base for ",[19,132,133],{},"https:\u002F\u002Flojaonline.com",", o Nuxt serve ",[19,136,137],{},"https:\u002F\u002Flojaonline.com\u002Fabout"," e ",[19,140,141],{},"https:\u002F\u002Flojaonline.com\u002Fprivacy-policy"," a partir desses arquivos.",[24,144,146],{"id":145},"rotas-dinâmicas","Rotas dinâmicas",[15,148,149],{},"Quando muitas URLs usam o mesmo modelo de página, como os posts de um blog, você cria um único arquivo com o nome do parâmetro entre colchetes. As duas estruturas abaixo geram a mesma rota:",[39,151,152,163],{},[42,153,154],{},[45,155,156,159,161],{},[48,157,158],{},"Local do parâmetro",[48,160,50],{},[48,162,53],{},[55,164,165,176],{},[45,166,167,170,173],{},[60,168,169],{},"Nome do arquivo",[60,171,172],{},"app\u002Fpages\u002Fblog\u002F[slug].vue",[60,174,175],{},"\u002Fblog\u002Fmeu-post",[45,177,178,181,184],{},[60,179,180],{},"Nome do diretório",[60,182,183],{},"app\u002Fpages\u002Fblog\u002F[slug]\u002Findex.vue",[60,185,175],{},[15,187,188,189,192,193,196],{},"O nome entre colchetes é a chave que você lê em ",[19,190,191],{},"route.params",". O slug é a parte legível da URL que identifica um recurso, geralmente derivada do título, como ",[19,194,195],{},"como-funciona-o-sistema-de-rotas-no-nuxt",". Ele não é um id de banco de dados: nada garante que seja único nem que nunca mude, então quem decide como resolvê-lo é a sua aplicação.",[15,198,199],{},"Aqui está uma página de post que carrega o conteúdo do Nuxt Content usando o slug:",[119,201,205],{"className":202,"code":203,"language":204,"meta":125,"style":125},"language-vue shiki shiki-themes dracula","\u003Cscript setup lang=\"ts\">\nconst route = useRoute();\n\nconst slug = computed(() => String(route.params.slug));\n\nconst { data: post } = await useAsyncData(\n  () => `post-${slug.value}`,\n  () => queryCollection(\"blog\").path(`\u002Fblog\u002F${slug.value}`).first()\n);\n\nif (!post.value) {\n  throw createError({\n    status: 404,\n    statusText: \"Post não encontrado\",\n    fatal: true\n  });\n}\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Carticle v-if=\"post\">\n    \u003Ch1>{{ post.title }}\u003C\u002Fh1>\n  \u003C\u002Farticle>\n\u003C\u002Ftemplate>\n","vue",[19,206,207,243,261,268,293,298,323,349,396,402,407,422,434,448,466,477,483,489,499,504,514,537,553,563],{"__ignoreMap":125},[208,209,212,216,220,224,227,230,234,238,240],"span",{"class":210,"line":211},"line",1,[208,213,215],{"class":214},"sCdxs","\u003C",[208,217,219],{"class":218},"s0Tla","script",[208,221,223],{"class":222},"sY_PY"," setup",[208,225,226],{"class":222}," lang",[208,228,229],{"class":218},"=",[208,231,233],{"class":232},"seVfx","\"",[208,235,237],{"class":236},"s-mGx","ts",[208,239,233],{"class":232},[208,241,242],{"class":214},">\n",[208,244,246,249,252,254,258],{"class":210,"line":245},2,[208,247,248],{"class":218},"const",[208,250,251],{"class":214}," route ",[208,253,229],{"class":218},[208,255,257],{"class":256},"sAOxA"," useRoute",[208,259,260],{"class":214},"();\n",[208,262,264],{"class":210,"line":263},3,[208,265,267],{"emptyLinePlaceholder":266},true,"\n",[208,269,271,273,276,278,281,284,287,290],{"class":210,"line":270},4,[208,272,248],{"class":218},[208,274,275],{"class":214}," slug ",[208,277,229],{"class":218},[208,279,280],{"class":256}," computed",[208,282,283],{"class":214},"(() ",[208,285,286],{"class":218},"=>",[208,288,289],{"class":256}," String",[208,291,292],{"class":214},"(route.params.slug));\n",[208,294,296],{"class":210,"line":295},5,[208,297,267],{"emptyLinePlaceholder":266},[208,299,301,303,306,309,312,314,317,320],{"class":210,"line":300},6,[208,302,248],{"class":218},[208,304,305],{"class":214}," { data",[208,307,308],{"class":218},":",[208,310,311],{"class":214}," post } ",[208,313,229],{"class":218},[208,315,316],{"class":218}," await",[208,318,319],{"class":256}," useAsyncData",[208,321,322],{"class":214},"(\n",[208,324,326,329,331,334,337,340,343,346],{"class":210,"line":325},7,[208,327,328],{"class":214},"  () ",[208,330,286],{"class":218},[208,332,333],{"class":236}," `post-",[208,335,336],{"class":218},"${",[208,338,339],{"class":214},"slug.value",[208,341,342],{"class":218},"}",[208,344,345],{"class":236},"`",[208,347,348],{"class":214},",\n",[208,350,352,354,356,359,362,364,367,369,372,375,377,380,382,384,386,388,390,393],{"class":210,"line":351},8,[208,353,328],{"class":214},[208,355,286],{"class":218},[208,357,358],{"class":256}," queryCollection",[208,360,361],{"class":214},"(",[208,363,233],{"class":232},[208,365,366],{"class":236},"blog",[208,368,233],{"class":232},[208,370,371],{"class":214},").",[208,373,374],{"class":256},"path",[208,376,361],{"class":214},[208,378,379],{"class":236},"`\u002Fblog\u002F",[208,381,336],{"class":218},[208,383,339],{"class":214},[208,385,342],{"class":218},[208,387,345],{"class":236},[208,389,371],{"class":214},[208,391,392],{"class":256},"first",[208,394,395],{"class":214},"()\n",[208,397,399],{"class":210,"line":398},9,[208,400,401],{"class":214},");\n",[208,403,405],{"class":210,"line":404},10,[208,406,267],{"emptyLinePlaceholder":266},[208,408,410,413,416,419],{"class":210,"line":409},11,[208,411,412],{"class":218},"if",[208,414,415],{"class":214}," (",[208,417,418],{"class":218},"!",[208,420,421],{"class":214},"post.value) {\n",[208,423,425,428,431],{"class":210,"line":424},12,[208,426,427],{"class":218},"  throw",[208,429,430],{"class":256}," createError",[208,432,433],{"class":214},"({\n",[208,435,437,440,442,446],{"class":210,"line":436},13,[208,438,439],{"class":214},"    status",[208,441,308],{"class":218},[208,443,445],{"class":444},"sIQBb"," 404",[208,447,348],{"class":214},[208,449,451,454,456,459,462,464],{"class":210,"line":450},14,[208,452,453],{"class":214},"    statusText",[208,455,308],{"class":218},[208,457,458],{"class":232}," \"",[208,460,461],{"class":236},"Post não encontrado",[208,463,233],{"class":232},[208,465,348],{"class":214},[208,467,469,472,474],{"class":210,"line":468},15,[208,470,471],{"class":214},"    fatal",[208,473,308],{"class":218},[208,475,476],{"class":444}," true\n",[208,478,480],{"class":210,"line":479},16,[208,481,482],{"class":214},"  });\n",[208,484,486],{"class":210,"line":485},17,[208,487,488],{"class":214},"}\n",[208,490,492,495,497],{"class":210,"line":491},18,[208,493,494],{"class":214},"\u003C\u002F",[208,496,219],{"class":218},[208,498,242],{"class":214},[208,500,502],{"class":210,"line":501},19,[208,503,267],{"emptyLinePlaceholder":266},[208,505,507,509,512],{"class":210,"line":506},20,[208,508,215],{"class":214},[208,510,511],{"class":218},"template",[208,513,242],{"class":214},[208,515,517,520,523,526,528,530,533,535],{"class":210,"line":516},21,[208,518,519],{"class":214},"  \u003C",[208,521,522],{"class":218},"article",[208,524,525],{"class":222}," v-if",[208,527,229],{"class":218},[208,529,233],{"class":232},[208,531,532],{"class":236},"post",[208,534,233],{"class":232},[208,536,242],{"class":214},[208,538,540,543,546,549,551],{"class":210,"line":539},22,[208,541,542],{"class":214},"    \u003C",[208,544,545],{"class":218},"h1",[208,547,548],{"class":214},">{{ post.title }}\u003C\u002F",[208,550,545],{"class":218},[208,552,242],{"class":214},[208,554,556,559,561],{"class":210,"line":555},23,[208,557,558],{"class":214},"  \u003C\u002F",[208,560,522],{"class":218},[208,562,242],{"class":214},[208,564,566,568,570],{"class":210,"line":565},24,[208,567,494],{"class":214},[208,569,511],{"class":218},[208,571,242],{"class":214},[15,573,574,575,578,579,582,583,586,587,590,591,594,595,598],{},"O slug é um ",[19,576,577],{},"computed",", e a chave do ",[19,580,581],{},"useAsyncData"," é uma função que depende dele. Quando o usuário vai de ",[19,584,585],{},"\u002Fblog\u002Fa"," para ",[19,588,589],{},"\u002Fblog\u002Fb",", o Vue Router pode manter o mesmo componente de página montado, então o código do ",[19,592,593],{},"\u003Cscript setup>"," não necessariamente roda de novo. Com uma chave reativa, o Nuxt busca o novo post quando o slug muda. Se você ler ",[19,596,597],{},"route.params.slug"," uma vez e guardar em uma variável comum, a URL muda, mas a página continua mostrando o post anterior.",[15,600,601,602,605],{},"Um slug que não existe também precisa de um 404. Sem a verificação com ",[19,603,604],{},"createError",", ele renderiza uma página vazia com status 200, e os buscadores enxergam uma URL válida, porém vazia.",[607,608,610],"h3",{"id":609},"validando-o-parâmetro-antes-de-renderizar","Validando o parâmetro antes de renderizar",[15,612,613,614,617,618,621,622,625],{},"O ",[19,615,616],{},"definePageMeta"," aceita uma função ",[19,619,620],{},"validate"," que decide se a rota pode ser renderizada por aquela página. Se ela retornar ",[19,623,624],{},"false"," e nenhuma outra rota combinar, o Nuxt responde com 404:",[119,627,629],{"className":202,"code":628,"language":204,"meta":125,"style":125},"\u003Cscript setup lang=\"ts\">\ndefinePageMeta({\n  validate: (route) => \u002F^[a-z0-9-]+$\u002F.test(String(route.params.slug))\n});\n\u003C\u002Fscript>\n",[19,630,631,651,657,713,718],{"__ignoreMap":125},[208,632,633,635,637,639,641,643,645,647,649],{"class":210,"line":211},[208,634,215],{"class":214},[208,636,219],{"class":218},[208,638,223],{"class":222},[208,640,226],{"class":222},[208,642,229],{"class":218},[208,644,233],{"class":232},[208,646,237],{"class":236},[208,648,233],{"class":232},[208,650,242],{"class":214},[208,652,653,655],{"class":210,"line":245},[208,654,616],{"class":256},[208,656,433],{"class":214},[208,658,659,662,664,666,670,673,675,679,682,686,689,692,695,698,700,702,705,707,710],{"class":210,"line":263},[208,660,661],{"class":256},"  validate",[208,663,308],{"class":218},[208,665,415],{"class":214},[208,667,669],{"class":668},"sGEwX","route",[208,671,672],{"class":214},") ",[208,674,286],{"class":218},[208,676,678],{"class":677},"s-doY"," \u002F",[208,680,681],{"class":218},"^",[208,683,685],{"class":684},"sLL85","[",[208,687,688],{"class":444},"a-z0-9",[208,690,691],{"class":236},"-",[208,693,694],{"class":684},"]",[208,696,697],{"class":218},"+$",[208,699,65],{"class":677},[208,701,107],{"class":214},[208,703,704],{"class":256},"test",[208,706,361],{"class":214},[208,708,709],{"class":256},"String",[208,711,712],{"class":214},"(route.params.slug))\n",[208,714,715],{"class":210,"line":270},[208,716,717],{"class":214},"});\n",[208,719,720,722,724],{"class":210,"line":295},[208,721,494],{"class":214},[208,723,219],{"class":218},[208,725,242],{"class":214},[15,727,613,728,730],{},[19,729,620],{}," só confere o formato do parâmetro. Saber se o post existe continua exigindo a consulta aos dados mostrada acima.",[24,732,734],{"id":733},"rotas-aninhadas","Rotas aninhadas",[15,736,737],{},"Rotas aninhadas servem para seções de uma interface em que uma área pai permanece na tela enquanto o conteúdo filho muda. Um painel administrativo com Pedidos, Produtos e Configurações é o caso típico.",[15,739,740],{},"Para criar uma, você precisa de um arquivo de página pai e de uma pasta com o mesmo nome que guarda os filhos:",[119,742,745],{"className":743,"code":744,"language":124,"meta":125},[122],"app\u002Fpages\u002F\n├── admin.vue\n└── admin\u002F\n    ├── index.vue      -> \u002Fadmin\n    ├── orders.vue     -> \u002Fadmin\u002Forders\n    ├── products.vue   -> \u002Fadmin\u002Fproducts\n    └── settings.vue   -> \u002Fadmin\u002Fsettings\n",[19,746,744],{"__ignoreMap":125},[15,748,749,750,753],{},"O arquivo pai renderiza a interface compartilhada e usa ",[19,751,752],{},"\u003CNuxtPage \u002F>"," onde a página filha deve aparecer:",[119,755,757],{"className":202,"code":756,"language":204,"meta":125,"style":125},"\u003Ctemplate>\n  \u003Cdiv>\n    \u003Cnav>\n      \u003CNuxtLink to=\"\u002Fadmin\u002Forders\">Pedidos\u003C\u002FNuxtLink>\n      \u003CNuxtLink to=\"\u002Fadmin\u002Fproducts\">Produtos\u003C\u002FNuxtLink>\n      \u003CNuxtLink to=\"\u002Fadmin\u002Fsettings\">Configurações\u003C\u002FNuxtLink>\n    \u003C\u002Fnav>\n    \u003CNuxtPage \u002F>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n",[19,758,759,767,776,785,812,836,860,869,879,887],{"__ignoreMap":125},[208,760,761,763,765],{"class":210,"line":211},[208,762,215],{"class":214},[208,764,511],{"class":218},[208,766,242],{"class":214},[208,768,769,771,774],{"class":210,"line":245},[208,770,519],{"class":214},[208,772,773],{"class":218},"div",[208,775,242],{"class":214},[208,777,778,780,783],{"class":210,"line":263},[208,779,542],{"class":214},[208,781,782],{"class":218},"nav",[208,784,242],{"class":214},[208,786,787,790,793,796,798,800,803,805,808,810],{"class":210,"line":270},[208,788,789],{"class":214},"      \u003C",[208,791,792],{"class":218},"NuxtLink",[208,794,795],{"class":222}," to",[208,797,229],{"class":218},[208,799,233],{"class":232},[208,801,802],{"class":236},"\u002Fadmin\u002Forders",[208,804,233],{"class":232},[208,806,807],{"class":214},">Pedidos\u003C\u002F",[208,809,792],{"class":218},[208,811,242],{"class":214},[208,813,814,816,818,820,822,824,827,829,832,834],{"class":210,"line":295},[208,815,789],{"class":214},[208,817,792],{"class":218},[208,819,795],{"class":222},[208,821,229],{"class":218},[208,823,233],{"class":232},[208,825,826],{"class":236},"\u002Fadmin\u002Fproducts",[208,828,233],{"class":232},[208,830,831],{"class":214},">Produtos\u003C\u002F",[208,833,792],{"class":218},[208,835,242],{"class":214},[208,837,838,840,842,844,846,848,851,853,856,858],{"class":210,"line":300},[208,839,789],{"class":214},[208,841,792],{"class":218},[208,843,795],{"class":222},[208,845,229],{"class":218},[208,847,233],{"class":232},[208,849,850],{"class":236},"\u002Fadmin\u002Fsettings",[208,852,233],{"class":232},[208,854,855],{"class":214},">Configurações\u003C\u002F",[208,857,792],{"class":218},[208,859,242],{"class":214},[208,861,862,865,867],{"class":210,"line":325},[208,863,864],{"class":214},"    \u003C\u002F",[208,866,782],{"class":218},[208,868,242],{"class":214},[208,870,871,873,876],{"class":210,"line":351},[208,872,542],{"class":214},[208,874,875],{"class":218},"NuxtPage",[208,877,878],{"class":214}," \u002F>\n",[208,880,881,883,885],{"class":210,"line":398},[208,882,558],{"class":214},[208,884,773],{"class":218},[208,886,242],{"class":214},[208,888,889,891,893],{"class":210,"line":404},[208,890,494],{"class":214},[208,892,511],{"class":218},[208,894,242],{"class":214},[15,896,897,898,900],{},"Ao navegar entre os filhos, só o conteúdo renderizado pelo ",[19,899,752],{}," troca, e o menu continua no lugar.",[607,902,904],{"id":903},"rotas-aninhadas-não-são-layouts","Rotas aninhadas não são layouts",[15,906,907,908,911,912,915],{},"O Nuxt não tem um arquivo ",[19,909,910],{},"layout.vue"," dentro de ",[19,913,914],{},"pages\u002Fadmin",". Página pai e layout são recursos separados:",[917,918,919,929],"ul",{},[920,921,922,923,926,927,107],"li",{},"Uma página pai aninhada (",[19,924,925],{},"admin.vue",") faz parte da árvore de rotas. Ela renderiza as rotas filhas por meio do ",[19,928,752],{},[920,930,931,932,934,935,938],{},"Um layout fica em ",[19,933,95],{}," e é uma estrutura reutilizável, como um cabeçalho com rodapé. A página escolhe um com ",[19,936,937],{},"definePageMeta({ layout: \"dashboard\" })",", e o layout renderiza a página pelo slot.",[24,940,942],{"id":941},"rotas-opcionais-e-catch-all","Rotas opcionais e catch-all",[15,944,945,946,949],{},"Dois padrões com colchetes cobrem casos que um ",[19,947,948],{},"[slug]"," simples não resolve:",[39,951,952,961],{},[42,953,954],{},[45,955,956,958],{},[48,957,50],{},[48,959,960],{},"Casa com",[55,962,963,975],{},[45,964,965,968],{},[60,966,967],{},"app\u002Fpages\u002F[[slug]].vue",[60,969,970,138,972],{},[19,971,65],{},[19,973,974],{},"\u002Fqualquer-coisa",[45,976,977,980],{},[60,978,979],{},"app\u002Fpages\u002F[...slug].vue",[60,981,982],{},"qualquer caminho, inclusive com vários trechos",[15,984,985],{},"Colchetes duplos tornam o trecho opcional. Os três pontos criam um catch-all que recebe o restante do caminho. Rotas catch-all servem para URLs de profundidade variável, como em documentações, e para tratar URLs antigas que você precisa redirecionar.",[24,987,989],{"id":988},"caminhos-personalizados-e-aliases","Caminhos personalizados e aliases",[15,991,992,993,995,996,998,999,1002],{},"Às vezes a URL pública não deve seguir a estrutura de arquivos. O ",[19,994,616],{}," permite definir um ",[19,997,374],{}," personalizado ou adicionar um ",[19,1000,1001],{},"alias"," para uma página:",[119,1004,1006],{"className":202,"code":1005,"language":204,"meta":125,"style":125},"\u003Cscript setup lang=\"ts\">\ndefinePageMeta({\n  path: \"\u002Fshirts\u002F:slug\",\n  alias: [\"\u002Ft-shirts\u002F:slug\"]\n});\n\u003C\u002Fscript>\n",[19,1007,1008,1028,1034,1050,1070,1074],{"__ignoreMap":125},[208,1009,1010,1012,1014,1016,1018,1020,1022,1024,1026],{"class":210,"line":211},[208,1011,215],{"class":214},[208,1013,219],{"class":218},[208,1015,223],{"class":222},[208,1017,226],{"class":222},[208,1019,229],{"class":218},[208,1021,233],{"class":232},[208,1023,237],{"class":236},[208,1025,233],{"class":232},[208,1027,242],{"class":214},[208,1029,1030,1032],{"class":210,"line":245},[208,1031,616],{"class":256},[208,1033,433],{"class":214},[208,1035,1036,1039,1041,1043,1046,1048],{"class":210,"line":263},[208,1037,1038],{"class":214},"  path",[208,1040,308],{"class":218},[208,1042,458],{"class":232},[208,1044,1045],{"class":236},"\u002Fshirts\u002F:slug",[208,1047,233],{"class":232},[208,1049,348],{"class":214},[208,1051,1052,1055,1057,1060,1062,1065,1067],{"class":210,"line":270},[208,1053,1054],{"class":214},"  alias",[208,1056,308],{"class":218},[208,1058,1059],{"class":214}," [",[208,1061,233],{"class":232},[208,1063,1064],{"class":236},"\u002Ft-shirts\u002F:slug",[208,1066,233],{"class":232},[208,1068,1069],{"class":214},"]\n",[208,1071,1072],{"class":210,"line":295},[208,1073,717],{"class":214},[208,1075,1076,1078,1080],{"class":210,"line":300},[208,1077,494],{"class":214},[208,1079,219],{"class":218},[208,1081,242],{"class":214},[15,1083,1084],{},"O alias faz a mesma página responder em mais de uma URL. Isso cria URLs duplicadas, então use só quando precisar das duas e aponte o canonical para a que você quer nos resultados de busca.",[24,1086,1088],{"id":1087},"parâmetros-de-consulta-query","Parâmetros de consulta (query)",[15,1090,1091,1092,1095,1096,308],{},"Os parâmetros de consulta carregam um estado opcional que não muda qual recurso a página representa: um filtro, a página atual de uma lista ou um termo de busca. O formato é ",[19,1093,1094],{},"?nome=valor",", e parâmetros extras são unidos com ",[19,1097,1098],{},"&",[119,1100,1103],{"className":1101,"code":1102,"language":124,"meta":125},[122],"https:\u002F\u002Flojaonline.com\u002Fcamisetas?cor=azul&tamanho=m&page=2\n",[19,1104,1102],{"__ignoreMap":125},[15,1106,1107,1108,1111,1112,1115,1116,1119,1120,1123,1124,1127],{},"Você os lê com ",[19,1109,1110],{},"useRoute().query",". O valor de um parâmetro nem sempre é uma única string. Pode ser uma string, ",[19,1113,1114],{},"null"," (para ",[19,1117,1118],{},"?cor"," sem valor), um array (para ",[19,1121,1122],{},"?tag=seo&tag=nuxt",") ou ",[19,1125,1126],{},"undefined"," quando o parâmetro não existe. Um helper pequeno evita bugs quando o valor é usado em um filtro ou em uma chamada de API:",[119,1129,1132],{"className":1130,"code":1131,"language":237,"meta":125,"style":125},"language-ts shiki shiki-themes dracula","\u002F\u002F app\u002Futils\u002Fquery.ts\nexport function firstQueryValue(\n  value: string | null | (string | null)[] | undefined\n) {\n  const first = Array.isArray(value) ? value[0] : value;\n  return first ?? undefined;\n}\n",[19,1133,1134,1140,1153,1190,1195,1231,1247],{"__ignoreMap":125},[208,1135,1136],{"class":210,"line":211},[208,1137,1139],{"class":1138},"shSDL","\u002F\u002F app\u002Futils\u002Fquery.ts\n",[208,1141,1142,1145,1148,1151],{"class":210,"line":245},[208,1143,1144],{"class":218},"export",[208,1146,1147],{"class":218}," function",[208,1149,1150],{"class":256}," firstQueryValue",[208,1152,322],{"class":214},[208,1154,1155,1158,1160,1164,1167,1170,1172,1174,1177,1179,1181,1184,1187],{"class":210,"line":263},[208,1156,1157],{"class":668},"  value",[208,1159,308],{"class":218},[208,1161,1163],{"class":1162},"sCp4m"," string",[208,1165,1166],{"class":218}," |",[208,1168,1169],{"class":1162}," null",[208,1171,1166],{"class":218},[208,1173,415],{"class":214},[208,1175,1176],{"class":1162},"string",[208,1178,1166],{"class":218},[208,1180,1169],{"class":1162},[208,1182,1183],{"class":214},")[] ",[208,1185,1186],{"class":218},"|",[208,1188,1189],{"class":1162}," undefined\n",[208,1191,1192],{"class":210,"line":270},[208,1193,1194],{"class":214},") {\n",[208,1196,1197,1200,1203,1205,1208,1211,1214,1217,1220,1223,1226,1228],{"class":210,"line":295},[208,1198,1199],{"class":218},"  const",[208,1201,1202],{"class":214}," first ",[208,1204,229],{"class":218},[208,1206,1207],{"class":214}," Array.",[208,1209,1210],{"class":256},"isArray",[208,1212,1213],{"class":214},"(value) ",[208,1215,1216],{"class":218},"?",[208,1218,1219],{"class":214}," value[",[208,1221,1222],{"class":444},"0",[208,1224,1225],{"class":214},"] ",[208,1227,308],{"class":218},[208,1229,1230],{"class":214}," value;\n",[208,1232,1233,1236,1238,1241,1244],{"class":210,"line":300},[208,1234,1235],{"class":218},"  return",[208,1237,1202],{"class":214},[208,1239,1240],{"class":218},"??",[208,1242,1243],{"class":444}," undefined",[208,1245,1246],{"class":214},";\n",[208,1248,1249],{"class":210,"line":325},[208,1250,488],{"class":214},[119,1252,1254],{"className":202,"code":1253,"language":204,"meta":125,"style":125},"\u003Cscript setup lang=\"ts\">\nconst route = useRoute();\n\nconst page = computed(() => Number(firstQueryValue(route.query.page)) || 1);\nconst cor = computed(() => firstQueryValue(route.query.cor));\n\u003C\u002Fscript>\n",[19,1255,1256,1276,1288,1292,1326,1346],{"__ignoreMap":125},[208,1257,1258,1260,1262,1264,1266,1268,1270,1272,1274],{"class":210,"line":211},[208,1259,215],{"class":214},[208,1261,219],{"class":218},[208,1263,223],{"class":222},[208,1265,226],{"class":222},[208,1267,229],{"class":218},[208,1269,233],{"class":232},[208,1271,237],{"class":236},[208,1273,233],{"class":232},[208,1275,242],{"class":214},[208,1277,1278,1280,1282,1284,1286],{"class":210,"line":245},[208,1279,248],{"class":218},[208,1281,251],{"class":214},[208,1283,229],{"class":218},[208,1285,257],{"class":256},[208,1287,260],{"class":214},[208,1289,1290],{"class":210,"line":263},[208,1291,267],{"emptyLinePlaceholder":266},[208,1293,1294,1296,1299,1301,1303,1305,1307,1310,1312,1315,1318,1321,1324],{"class":210,"line":270},[208,1295,248],{"class":218},[208,1297,1298],{"class":214}," page ",[208,1300,229],{"class":218},[208,1302,280],{"class":256},[208,1304,283],{"class":214},[208,1306,286],{"class":218},[208,1308,1309],{"class":256}," Number",[208,1311,361],{"class":214},[208,1313,1314],{"class":256},"firstQueryValue",[208,1316,1317],{"class":214},"(route.query.page)) ",[208,1319,1320],{"class":218},"||",[208,1322,1323],{"class":444}," 1",[208,1325,401],{"class":214},[208,1327,1328,1330,1333,1335,1337,1339,1341,1343],{"class":210,"line":295},[208,1329,248],{"class":218},[208,1331,1332],{"class":214}," cor ",[208,1334,229],{"class":218},[208,1336,280],{"class":256},[208,1338,283],{"class":214},[208,1340,286],{"class":218},[208,1342,1150],{"class":256},[208,1344,1345],{"class":214},"(route.query.cor));\n",[208,1347,1348,1350,1352],{"class":210,"line":300},[208,1349,494],{"class":214},[208,1351,219],{"class":218},[208,1353,242],{"class":214},[15,1355,1356,1357,1360],{},"O Nuxt importa o helper de ",[19,1358,1359],{},"app\u002Futils"," automaticamente, e os dois valores se atualizam quando a query muda.",[607,1362,1364],{"id":1363},"query-strings-e-seo","Query strings e SEO",[15,1366,1367],{},"Cada combinação de filtros cria uma URL diferente, e uma listagem com poucos filtros pode gerar uma quantidade enorme delas. Para URLs que só ordenam ou restringem a mesma lista, defina um canonical apontando para a listagem sem filtro:",[119,1369,1371],{"className":202,"code":1370,"language":204,"meta":125,"style":125},"\u003Cscript setup lang=\"ts\">\nuseHead({\n  link: [{ rel: \"canonical\", href: \"https:\u002F\u002Flojaonline.com\u002Fcamisetas\" }]\n});\n\u003C\u002Fscript>\n",[19,1372,1373,1393,1400,1434,1438],{"__ignoreMap":125},[208,1374,1375,1377,1379,1381,1383,1385,1387,1389,1391],{"class":210,"line":211},[208,1376,215],{"class":214},[208,1378,219],{"class":218},[208,1380,223],{"class":222},[208,1382,226],{"class":222},[208,1384,229],{"class":218},[208,1386,233],{"class":232},[208,1388,237],{"class":236},[208,1390,233],{"class":232},[208,1392,242],{"class":214},[208,1394,1395,1398],{"class":210,"line":245},[208,1396,1397],{"class":256},"useHead",[208,1399,433],{"class":214},[208,1401,1402,1405,1407,1410,1412,1414,1417,1419,1422,1424,1426,1429,1431],{"class":210,"line":263},[208,1403,1404],{"class":214},"  link",[208,1406,308],{"class":218},[208,1408,1409],{"class":214}," [{ rel",[208,1411,308],{"class":218},[208,1413,458],{"class":232},[208,1415,1416],{"class":236},"canonical",[208,1418,233],{"class":232},[208,1420,1421],{"class":214},", href",[208,1423,308],{"class":218},[208,1425,458],{"class":232},[208,1427,1428],{"class":236},"https:\u002F\u002Flojaonline.com\u002Fcamisetas",[208,1430,233],{"class":232},[208,1432,1433],{"class":214}," }]\n",[208,1435,1436],{"class":210,"line":270},[208,1437,717],{"class":214},[208,1439,1440,1442,1444],{"class":210,"line":295},[208,1441,494],{"class":214},[208,1443,219],{"class":218},[208,1445,242],{"class":214},[15,1447,1448,1449,1452,1453,1456],{},"Páginas de paginação são outro caso: cada página da lista tem conteúdo próprio, então ",[19,1450,1451],{},"?page=2"," mantém um canonical apontando para ela mesma, não para a página 1. Um conteúdo que deve ranquear sozinho, como uma categoria, funciona melhor como caminho (",[19,1454,1455],{},"\u002Fcamisetas\u002Fazul",") do que como query string.",[24,1458,1460],{"id":1459},"navegando-entre-rotas","Navegando entre rotas",[15,1462,1463,1464,1466,1467,308],{},"Use o ",[19,1465,792],{}," nos links que o usuário vê. Ele renderiza um elemento âncora normal e navega no cliente, sem recarregar a página. Para redirecionamentos e navegação disparada por código, use o ",[19,1468,1469],{},"navigateTo",[119,1471,1473],{"className":202,"code":1472,"language":204,"meta":125,"style":125},"\u003Cscript setup lang=\"ts\">\nasync function aplicarFiltro() {\n  await navigateTo({\n    path: \"\u002Fcamisetas\",\n    query: { cor: \"azul\", tamanho: \"m\" }\n  });\n}\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003CNuxtLink to=\"\u002Fblog\u002Fcomo-funciona-o-sistema-de-rotas-no-nuxt\">\n    Ler o post\n  \u003C\u002FNuxtLink>\n  \u003Cbutton @click=\"aplicarFiltro\">Azul, tamanho M\u003C\u002Fbutton>\n\u003C\u002Ftemplate>\n",[19,1474,1475,1495,1508,1518,1534,1568,1572,1576,1584,1588,1596,1615,1620,1628,1654],{"__ignoreMap":125},[208,1476,1477,1479,1481,1483,1485,1487,1489,1491,1493],{"class":210,"line":211},[208,1478,215],{"class":214},[208,1480,219],{"class":218},[208,1482,223],{"class":222},[208,1484,226],{"class":222},[208,1486,229],{"class":218},[208,1488,233],{"class":232},[208,1490,237],{"class":236},[208,1492,233],{"class":232},[208,1494,242],{"class":214},[208,1496,1497,1500,1502,1505],{"class":210,"line":245},[208,1498,1499],{"class":218},"async",[208,1501,1147],{"class":218},[208,1503,1504],{"class":256}," aplicarFiltro",[208,1506,1507],{"class":214},"() {\n",[208,1509,1510,1513,1516],{"class":210,"line":263},[208,1511,1512],{"class":218},"  await",[208,1514,1515],{"class":256}," navigateTo",[208,1517,433],{"class":214},[208,1519,1520,1523,1525,1527,1530,1532],{"class":210,"line":270},[208,1521,1522],{"class":214},"    path",[208,1524,308],{"class":218},[208,1526,458],{"class":232},[208,1528,1529],{"class":236},"\u002Fcamisetas",[208,1531,233],{"class":232},[208,1533,348],{"class":214},[208,1535,1536,1539,1541,1544,1546,1548,1551,1553,1556,1558,1560,1563,1565],{"class":210,"line":295},[208,1537,1538],{"class":214},"    query",[208,1540,308],{"class":218},[208,1542,1543],{"class":214}," { cor",[208,1545,308],{"class":218},[208,1547,458],{"class":232},[208,1549,1550],{"class":236},"azul",[208,1552,233],{"class":232},[208,1554,1555],{"class":214},", tamanho",[208,1557,308],{"class":218},[208,1559,458],{"class":232},[208,1561,1562],{"class":236},"m",[208,1564,233],{"class":232},[208,1566,1567],{"class":214}," }\n",[208,1569,1570],{"class":210,"line":300},[208,1571,482],{"class":214},[208,1573,1574],{"class":210,"line":325},[208,1575,488],{"class":214},[208,1577,1578,1580,1582],{"class":210,"line":351},[208,1579,494],{"class":214},[208,1581,219],{"class":218},[208,1583,242],{"class":214},[208,1585,1586],{"class":210,"line":398},[208,1587,267],{"emptyLinePlaceholder":266},[208,1589,1590,1592,1594],{"class":210,"line":404},[208,1591,215],{"class":214},[208,1593,511],{"class":218},[208,1595,242],{"class":214},[208,1597,1598,1600,1602,1604,1606,1608,1611,1613],{"class":210,"line":409},[208,1599,519],{"class":214},[208,1601,792],{"class":218},[208,1603,795],{"class":222},[208,1605,229],{"class":218},[208,1607,233],{"class":232},[208,1609,1610],{"class":236},"\u002Fblog\u002Fcomo-funciona-o-sistema-de-rotas-no-nuxt",[208,1612,233],{"class":232},[208,1614,242],{"class":214},[208,1616,1617],{"class":210,"line":424},[208,1618,1619],{"class":214},"    Ler o post\n",[208,1621,1622,1624,1626],{"class":210,"line":436},[208,1623,558],{"class":214},[208,1625,792],{"class":218},[208,1627,242],{"class":214},[208,1629,1630,1632,1635,1638,1640,1642,1645,1647,1650,1652],{"class":210,"line":450},[208,1631,519],{"class":214},[208,1633,1634],{"class":218},"button",[208,1636,1637],{"class":222}," @click",[208,1639,229],{"class":218},[208,1641,233],{"class":232},[208,1643,1644],{"class":236},"aplicarFiltro",[208,1646,233],{"class":232},[208,1648,1649],{"class":214},">Azul, tamanho M\u003C\u002F",[208,1651,1634],{"class":218},[208,1653,242],{"class":214},[208,1655,1656,1658,1660],{"class":210,"line":468},[208,1657,494],{"class":214},[208,1659,511],{"class":218},[208,1661,242],{"class":214},[15,1663,1664,1665,1667,1668,138,1671,1674,1675,1678,1679,1681],{},"Quando uma regra vale para muitas rotas, como exigir login, use um middleware de rota em ",[19,1666,99],{},". Dentro do middleware, leia os argumentos ",[19,1669,1670],{},"to",[19,1672,1673],{},"from"," em vez de chamar ",[19,1676,1677],{},"useRoute()",". A documentação do Nuxt desaconselha o ",[19,1680,1677],{}," ali, porque o middleware ainda não tem uma rota atual.",[24,1683,1685],{"id":1684},"erros-comuns-de-roteamento","Erros comuns de roteamento",[917,1687,1688,1693,1699,1706,1709],{},[920,1689,1690,1691,107],{},"Usar um layout como pai de rotas aninhadas, em vez de uma página pai com ",[19,1692,752],{},[920,1694,1695,1696,1698],{},"Ler ",[19,1697,191],{}," uma vez em vez de derivar os dados dele de forma reativa.",[920,1700,1701,1702,1705],{},"Tratar os valores de ",[19,1703,1704],{},"route.query"," como strings simples.",[920,1707,1708],{},"Devolver uma página vazia com status 200 para um slug que não existe.",[920,1710,1711],{},"Criar URLs de filtro sem decidir qual versão os buscadores devem indexar.",[24,1713,1715],{"id":1714},"perguntas-frequentes","Perguntas frequentes",[607,1717,1719],{"id":1718},"o-que-é-roteamento-baseado-em-arquivos-no-nuxt","O que é roteamento baseado em arquivos no Nuxt?",[15,1721,1722,1723,1725,1726,1729,1730,107],{},"O Nuxt cria as rotas a partir dos arquivos e pastas dentro do diretório ",[19,1724,21],{},". Por exemplo, ",[19,1727,1728],{},"app\u002Fpages\u002Fabout.vue"," vira ",[19,1731,1732],{},"\u002Fabout",[607,1734,1736],{"id":1735},"onde-ficam-as-páginas-no-nuxt-4","Onde ficam as páginas no Nuxt 4?",[15,1738,1739,1740,1742,1743,1745],{},"Projetos novos do Nuxt 4 usam ",[19,1741,91],{},". Projetos que ainda têm uma pasta ",[19,1744,103],{}," na raiz continuam funcionando, porque o Nuxt detecta a estrutura antiga.",[607,1747,1749],{"id":1748},"como-criar-uma-rota-dinâmica-no-nuxt","Como criar uma rota dinâmica no Nuxt?",[15,1751,1752,1753,1755,1756,1759,1760,1762],{},"Nomeie o arquivo com um parâmetro entre colchetes, como ",[19,1754,172],{},", e leia o valor com ",[19,1757,1758],{},"useRoute().params.slug",". Derive tudo que depende dele de um ",[19,1761,577],{},", para atualizar quando o slug mudar.",[607,1764,1766],{"id":1765},"qual-é-a-diferença-entre-rotas-aninhadas-e-layouts","Qual é a diferença entre rotas aninhadas e layouts?",[15,1768,1769,1770,1772,1773,1775,1776,107],{},"Uma rota aninhada usa uma página pai com ",[19,1771,752],{}," para renderizar as rotas filhas. Um layout fica em ",[19,1774,95],{}," e envolve as páginas com uma estrutura reutilizável, escolhida com ",[19,1777,1778],{},"definePageMeta({ layout })",[607,1780,1782],{"id":1781},"como-mostrar-um-404-para-um-slug-inválido","Como mostrar um 404 para um slug inválido?",[15,1784,1785,1786,1788,1789,1792,1793,1795,1796,1798,1799,1801],{},"Lance um ",[19,1787,604],{}," com ",[19,1790,1791],{},"status: 404"," quando os dados não existirem, ou retorne ",[19,1794,624],{}," no ",[19,1797,620],{}," do ",[19,1800,616],{}," quando o parâmetro tiver um formato inválido.",[24,1803,1805],{"id":1804},"conclusão","Conclusão",[15,1807,1808,1809,107],{},"Antes de criar os arquivos, liste as suas URLs públicas: quais páginas são estáticas, quais precisam de slug e qual estado pertence à query string. Depois decida quais URLs filtradas devem ser indexadas. Para a lista completa de opções, consulte a ",[1810,1811,1815],"a",{"href":1812,"rel":1813},"https:\u002F\u002Fnuxt.com\u002Fdocs\u002F4.x\u002Fgetting-started\u002Frouting",[1814],"nofollow","documentação de roteamento do Nuxt",[1817,1818,1819],"style",{},"html pre.shiki code .sCdxs, html code.shiki .sCdxs{--shiki-default:#F8F8F2}html pre.shiki code .s0Tla, html code.shiki .s0Tla{--shiki-default:#FF79C6}html pre.shiki code .sY_PY, html code.shiki .sY_PY{--shiki-default:#50FA7B;--shiki-default-font-style:italic}html pre.shiki code .seVfx, html code.shiki .seVfx{--shiki-default:#E9F284}html pre.shiki code .s-mGx, html code.shiki .s-mGx{--shiki-default:#F1FA8C}html pre.shiki code .sAOxA, html code.shiki .sAOxA{--shiki-default:#50FA7B}html pre.shiki code .sIQBb, html code.shiki .sIQBb{--shiki-default:#BD93F9}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 pre.shiki code .sGEwX, html code.shiki .sGEwX{--shiki-default:#FFB86C;--shiki-default-font-style:italic}html pre.shiki code .s-doY, html code.shiki .s-doY{--shiki-default:#FF5555}html pre.shiki code .sLL85, html code.shiki .sLL85{--shiki-default:#8BE9FD}html pre.shiki code .shSDL, html code.shiki .shSDL{--shiki-default:#6272A4}html pre.shiki code .sCp4m, html code.shiki .sCp4m{--shiki-default:#8BE9FD;--shiki-default-font-style:italic}",{"title":125,"searchDepth":245,"depth":245,"links":1821},[1822,1823,1824,1827,1830,1831,1832,1835,1836,1837,1844],{"id":26,"depth":245,"text":27},{"id":113,"depth":245,"text":114},{"id":145,"depth":245,"text":146,"children":1825},[1826],{"id":609,"depth":263,"text":610},{"id":733,"depth":245,"text":734,"children":1828},[1829],{"id":903,"depth":263,"text":904},{"id":941,"depth":245,"text":942},{"id":988,"depth":245,"text":989},{"id":1087,"depth":245,"text":1088,"children":1833},[1834],{"id":1363,"depth":263,"text":1364},{"id":1459,"depth":245,"text":1460},{"id":1684,"depth":245,"text":1685},{"id":1714,"depth":245,"text":1715,"children":1838},[1839,1840,1841,1842,1843],{"id":1718,"depth":263,"text":1719},{"id":1735,"depth":263,"text":1736},{"id":1748,"depth":263,"text":1749},{"id":1765,"depth":263,"text":1766},{"id":1781,"depth":263,"text":1782},{"id":1804,"depth":245,"text":1805},[1846,1847],"nuxt","vuejs","Como funciona o roteamento por arquivos do Nuxt: rotas dinâmicas, aninhadas e catch-all, query params, erro 404 e URLs canônicas, com exemplos do Nuxt 4.","how-the-routing-system-works-in-nuxt","md",{},"2025-03-12",{"title":5,"description":1848},{"loc":1610,"lastmod":1855},"2026-10-03","blog\u002Fcomo-funciona-o-sistema-de-rotas-no-nuxt",1446,"SlAfr9lxbNq9z6lwz58-9qTTGytpbmIu6idqDw5Wkzc",[1860,1868,1875,1882,1890,1898,1906,1908,1916,1924,1931,1939,1945,1954,1961,1968,1975,1982,1989,1997,2004,2011],{"id":1861,"path":1862,"title":1863,"articleCover":1864,"categoriesIds":1865,"publishedAt":1867},"blog\u002Fblog\u002Fa-maneira-correta-de-utilizar-a-nomenclatura-bem.md","\u002Fblog\u002Fa-maneira-correta-de-utilizar-a-nomenclatura-bem","A maneira correta de utilizar a nomenclatura BEM","\u002Fimages\u002Fblog\u002Fa-maneira-correta-de-utilizar-a-nomenclatura-bem.webp",[1866],"css","2024-05-05",{"id":1869,"path":1870,"title":1871,"articleCover":1872,"categoriesIds":1873,"publishedAt":1874},"blog\u002Fblog\u002Fcomo-adicionar-caracteres-especiais-no-i18n.md","\u002Fblog\u002Fcomo-adicionar-caracteres-especiais-no-i18n","Como Adicionar Caracteres Especiais em Traduções do i18N","\u002Fimages\u002Fblog\u002Fi18n\u002Fi18n-caracteres-especiais-no-nuxtjs-thumb.webp",[1846,1847],"2025-01-29",{"id":1876,"path":1877,"title":1878,"articleCover":1879,"categoriesIds":1880,"publishedAt":1881},"blog\u002Fblog\u002Fcomo-adicionar-o-google-tag-manager-no-seu-website-com-nuxt-3.md","\u002Fblog\u002Fcomo-adicionar-o-google-tag-manager-no-seu-website-com-nuxt-3","Como adicionar o Google Tag Manager no seu website com Nuxt 3","\u002Fimages\u002Fblog\u002Fcomo-adicionar-google-tag-manager-em-projeto-com-nuxt-3.webp",[1846,1847],"2024-08-15",{"id":1883,"path":1884,"title":1885,"articleCover":1886,"categoriesIds":1887,"publishedAt":1889},"blog\u002Fblog\u002Fcomo-configurar-chave-ssh-no-git-para-usar-no-github.md","\u002Fblog\u002Fcomo-configurar-chave-ssh-no-git-para-usar-no-github","Chave SSH no Git: Como Configurar chave SSH para usar no GitHub","\u002Fimages\u002Fblog\u002Fgit\u002Fcomo-criar-e-configurar-chave-ssh-no-github-thumb.webp",[1888],"git","2025-02-04",{"id":1891,"path":1892,"title":1893,"articleCover":1894,"categoriesIds":1895,"publishedAt":1897},"blog\u002Fblog\u002Fcomo-consumir-uma-api-no-javascript-com-a-fetch-api.md","\u002Fblog\u002Fcomo-consumir-uma-api-no-javascript-com-a-fetch-api","Como consumir uma API no JavaScript com a Fetch API","\u002Fimages\u002Fblog\u002Fcomo-consumir-uma-api-no-javascript-com-a-fetch-api.webp",[1896],"javascript","2024-09-05",{"id":1899,"path":1900,"title":1901,"articleCover":1902,"categoriesIds":1903,"publishedAt":1905},"blog\u002Fblog\u002Fcomo-criar-dados-estruturados-com-nuxtjs.md","\u002Fblog\u002Fcomo-criar-dados-estruturados-com-nuxtjs","Como Adicionar Dados Estruturados no Nuxt.JS","\u002Fimages\u002Fblog\u002Fseo\u002Fstructured-data\u002Fstructured-data-thumb-1.webp",[1846,1847,1904],"seo","2025-01-22",{"id":4,"path":1610,"title":5,"articleCover":6,"categoriesIds":1907,"publishedAt":1852},[1846,1847],{"id":1909,"path":1910,"title":1911,"articleCover":1912,"categoriesIds":1913,"publishedAt":1915},"blog\u002Fblog\u002Fcomo-lidar-com-inveja-de-outros-programadores.md","\u002Fblog\u002Fcomo-lidar-com-inveja-de-outros-programadores","Como Lidar com Inveja de Outros Programadores","\u002Fimages\u002Fblog\u002Fcarreira\u002Finveja-de-programadores-com-quem-se-destaca.webp",[1914],"career","2025-08-29",{"id":1917,"path":1918,"title":1919,"articleCover":1920,"categoriesIds":1921,"publishedAt":1923},"blog\u002Fblog\u002Fcomo-recuperar-arquivos-perdidos-no-git-pelo-vscode.md","\u002Fblog\u002Fcomo-recuperar-arquivos-perdidos-no-git-pelo-vscode","Perdeu arquivos no Git sem commit? Veja como recuperar pelo VS Code","\u002Fimages\u002Fblog\u002Fcomo-recuperar-arquivos-perdido-no-git-pelo-vscode.webp",[1888,1922],"vscode","2024-05-15",{"id":1925,"path":1926,"title":1927,"articleCover":1928,"categoriesIds":1929,"publishedAt":1930},"blog\u002Fblog\u002Fcomo-usar-middlewares-no-nuxtjs.md","\u002Fblog\u002Fcomo-usar-middlewares-no-nuxtjs","Middlewares: O que são e como utilizar no Nuxt.JS","\u002Fimages\u002Fblog\u002Fnuxt\u002Fmiddlewares-no-front-end.webp",[1846,1847],"2025-01-14",{"id":1932,"path":1933,"title":1934,"articleCover":1935,"categoriesIds":1936,"publishedAt":1938},"blog\u002Fblog\u002Fcomo-validar-cartao-de-credito-com-javascript.md","\u002Fblog\u002Fcomo-validar-cartao-de-credito-com-javascript","Como validar um cartão de crédito com JavaScript (algoritmo de Luhn)","\u002Fimages\u002Fblog\u002Fjavascript\u002Fcomo-validar-cartao-de-credito-com-javascript.webp",[1896,1937],"tools","2026-09-17",{"id":1940,"path":1941,"title":1942,"articleCover":1943,"categoriesIds":1944,"publishedAt":1938},"blog\u002Fblog\u002Fcomo-validar-cpf-com-javascript.md","\u002Fblog\u002Fcomo-validar-cpf-com-javascript","Como validar um CPF com JavaScript","\u002Fimages\u002Fblog\u002Fjavascript\u002Fcomo-validar-cpf-com-javascript.webp",[1896,1937],{"id":1946,"path":1947,"title":1948,"articleCover":1949,"categoriesIds":1950,"publishedAt":1953},"blog\u002Fblog\u002Fcomponentes-do-figma-um-guia-para-te-ajudar-a-comecar.md","\u002Fblog\u002Fcomponentes-do-figma-um-guia-para-te-ajudar-a-comecar","Guia de Componentes no Figma para Iniciantes","\u002Fimages\u002Fblog\u002Ffigma\u002Fcomponentes-do-figma-um-guia-para-te-ajudar-a-comecar.png",[1951,1952],"figma","ux","2024-10-15",{"id":1955,"path":1956,"title":1957,"articleCover":1958,"categoriesIds":1959,"publishedAt":1960},"blog\u002Fblog\u002Fhub-de-ferramentas-gratuitas-para-desenvolvedores.md","\u002Fblog\u002Fhub-de-ferramentas-gratuitas-para-desenvolvedores","Criei um Hub de Ferramentas Web Gratuitas para Devs","\u002Fimages\u002Fblog\u002Fferramentas\u002Fhub-ferramentas-gratuitas-para-desenvolvedores.webp",[1937],"2026-01-06",{"id":1962,"path":1963,"title":1964,"articleCover":1965,"categoriesIds":1966,"publishedAt":1967},"blog\u002Fblog\u002Fo-que-sao-diretivas-no-vue-e-como-implementa-las.md","\u002Fblog\u002Fo-que-sao-diretivas-no-vue-e-como-implementa-las","Diretivas no Vue 3: nativas e personalizadas","\u002Fimages\u002Fblog\u002Fvue\u002Fo-que-sao-diretivas-no-vue-e-como-implementa-las.webp",[1847],"2025-03-21",{"id":1969,"path":1970,"title":1971,"articleCover":1972,"categoriesIds":1973,"publishedAt":1974},"blog\u002Fblog\u002Fog-tags-o-que-sao-e-como-adicionar-no-seu-site.md","\u002Fblog\u002Fog-tags-o-que-sao-e-como-adicionar-no-seu-site","OG Tags: O que São e Como Adicioná-las ao Seu Site","\u002Fimages\u002Fblog\u002Fseo\u002Fo-que-e-como-utilizar-as-og-tags.webp",[1904],"2024-10-05",{"id":1976,"path":1977,"title":1978,"articleCover":1979,"categoriesIds":1980,"publishedAt":1981},"blog\u002Fblog\u002Fos-principais-erros-de-programadores-em-entrevistas-de-emprego.md","\u002Fblog\u002Fos-principais-erros-de-programadores-em-entrevistas-de-emprego","Os principais erros de programadores em entrevistas de emprego","\u002Fimages\u002Fblog\u002Fnao-cometa-esses-erros-na-sua-entrevista.webp",[1914],"2024-09-15",{"id":1983,"path":1984,"title":1985,"articleCover":1986,"categoriesIds":1987,"publishedAt":1988},"blog\u002Fblog\u002Fqual-a-diferenca-entre-a-composition-api-e-options-api-no-vuejs.md","\u002Fblog\u002Fqual-a-diferenca-entre-a-composition-api-e-options-api-no-vuejs","Qual a diferença entre a Composition API e Options API no VueJS","\u002Fimages\u002Fblog\u002Fvue\u002Fqual-a-diferenca-entre-a-composition-api-e-options-api-no-vuejs.webp",[1847],"2025-02-20",{"id":1990,"path":1991,"title":1992,"articleCover":1993,"categoriesIds":1994,"publishedAt":1996},"blog\u002Fblog\u002Fscroll-infinito-como-adicionar-ao-seu-site-e-suas-vantagens.md","\u002Fblog\u002Fscroll-infinito-como-adicionar-ao-seu-site-e-suas-vantagens","Scroll Infinito no React-Native: Guia Prático","\u002Fimages\u002Fblog\u002Freact-native\u002Fscroll-infinito-como-adicionar-ao-seu-site-e-suas-vantagens.webp",[1995],"react-native","2024-12-15",{"id":1998,"path":1999,"title":2000,"articleCover":2001,"categoriesIds":2002,"publishedAt":2003},"blog\u002Fblog\u002Fvercel-compra-nuxt-labs.md","\u002Fblog\u002Fvercel-compra-nuxt-labs","Vercel comprou a Nuxt Labs! E agora, o que muda para o Nuxt?","\u002Fimages\u002Fblog\u002Fnuxt\u002Fvercel-compra-nuxt-labs.webp",[1846],"2025-07-17",{"id":2005,"path":2006,"title":2007,"articleCover":2008,"categoriesIds":2009,"publishedAt":2010},"blog\u002Fblog\u002Fvue-vapor-mode-como-funciona-e-como-usar.md","\u002Fblog\u002Fvue-vapor-mode-como-funciona-e-como-usar","Vue Vapor Mode: o que é e o que muda no Vue 3.6","\u002Fimages\u002Fblog\u002Fvue\u002Fvue-vapor-mode-como-funciona-e-como-usar.webp",[1847,1846],"2026-10-06",{"id":2012,"path":2013,"title":2014,"articleCover":2015,"categoriesIds":2016,"publishedAt":2018},"blog\u002Fblog\u002Fweb-vitals-como-a-experiencia-do-usuario-vai-afetar-o-seo-do-seu-site.md","\u002Fblog\u002Fweb-vitals-como-a-experiencia-do-usuario-vai-afetar-o-seo-do-seu-site","Web Vitals e SEO: como a experiência do usuário afeta o seu site","\u002Fimages\u002Fblog\u002Fseo\u002Fweb-vitals\u002Fweb-vitals-como-a-experiencia-do-usuario-vai-afetar-o-seo-do-seu-site.webp",[1904,2017],"web-vitals","2024-10-25",1791682332479]