[{"data":1,"prerenderedAt":2265},["ShallowReactive",2],{"blog-seo-geo-aeo-nuxt":3},{"id":4,"title":5,"about":6,"author":7,"body":8,"date":2233,"description":2234,"extension":1535,"faq":2235,"image":2248,"mentions":6,"meta":2249,"navigation":154,"path":2250,"seo":2251,"seoDescription":2252,"seoTitle":2253,"stem":2254,"tags":2255,"updated":6,"__hash__":2264},"blog\u002Fblog\u002Fseo-geo-aeo-nuxt.md","SEO, GEO e AEO na prática: preparando um site Nuxt para o Google e para as IAs",null,"Larissa Santos",{"type":9,"value":10,"toc":2222},"minimark",[11,15,18,26,29,34,41,48,59,335,346,356,446,449,451,455,458,472,490,620,627,634,641,655,666,668,672,675,700,844,851,858,1074,1083,1090,1243,1246,1248,1252,1262,1268,1422,1429,1431,1435,1442,1455,1511,1517,1528,1531,1740,1743,1745,1749,1759,1769,1806,1816,1980,1987,1996,2108,2110,2114,2126,2132,2135,2137,2141,2144,2189,2191,2195,2218],[12,13,14],"p",{},"Um site hoje não é lido por um público só. A mesma página é rastreada pelo buscador do Google, lida pelo mecanismo que monta a resposta direta no topo da busca, e visitada pela IA generativa que vai decidir se cita aquele conteúdo como fonte. Cada um lê de um jeito, e otimizar para um não garante os outros.",[12,16,17],{},"É daí que saem as três siglas. SEO é a otimização clássica, indexar e ranquear no buscador. AEO (Answer Engine Optimization) prepara o conteúdo para virar resposta direta, aquele bloco que aparece no topo da busca ou no AI Overview. E GEO (Generative Engine Optimization) é a visibilidade dentro das respostas de IAs como ChatGPT e Perplexity. As três se cruzam, mas cada uma resolve um tipo de leitura diferente da mesma URL.",[12,19,20,21,25],{},"A boa notícia é que num projeto Nuxt, com o módulo ",[22,23,24],"code",{},"@nuxtjs\u002Fseo",", dá para cobrir as três frentes com ferramenta nativa. Neste artigo vamos ver como, começando pela base e passando por og:image dinâmica, Schema.org, robots.txt, llms.txt e sitemap.",[27,28],"hr",{},[30,31,33],"h2",{"id":32},"a-base-ssr-e-meta-tags-por-página","A base: SSR e meta tags por página",[12,35,36,37,40],{},"Antes de qualquer og:image ou schema, existe uma condição que sustenta tudo: o conteúdo precisa estar no HTML que sai do servidor. Se a página só se monta depois do JavaScript rodar no navegador, boa parte dos crawlers recebe um HTML quase vazio, com o ",[22,38,39],{},"\u003Cdiv id=\"app\">"," e pouco mais que isso. Isso vale para o Google, que hoje até executa JavaScript mas com atraso e limites, e vale ainda mais para os crawlers de IA, que muitas vezes leem só o HTML cru.",[12,42,43,44,47],{},"É aqui que o Nuxt entra na frente de uma SPA tradicional. Com SSR ativo, os dados já vêm renderizados dentro do HTML da resposta, junto com as meta tags e o dado estruturado. O crawler não depende de executar nada para enxergar o conteúdo. Para páginas que não mudam a cada request, dá ainda para pré-renderizar em build com o ",[22,45,46],{},"prerender",", entregando HTML estático e rápido.",[12,49,50,51,54,55,58],{},"Com a renderização resolvida, o próximo passo é o básico do SEO técnico: title, description e as meta tags de cada página. O ",[22,52,53],{},"useSeoMeta",", chamado dentro do ",[22,56,57],{},"\u003Cscript setup>"," da página, cuida disso de forma tipada, alimentado pelos dados reais da rota:",[60,61,66],"pre",{"className":62,"code":63,"language":64,"meta":65,"style":65},"language-ts shiki shiki-themes material-theme-lighter github-dark github-dark","const seoTitle = post.value.seoTitle ?? post.value.title\nconst seoDescription = post.value.seoDescription ?? post.value.description\n\nuseSeoMeta({\n  title: seoTitle,\n  description: seoDescription,\n  ogTitle: seoTitle,\n  ogDescription: seoDescription,\n  ogUrl: `https:\u002F\u002Fwww.larisantos.com.br\u002Fblog\u002F${route.params.slug}`,\n  ogImage: toAbsoluteUrl(post.value.image),\n  ogImageAlt: post.value.title,\n  twitterTitle: seoTitle,\n  twitterDescription: seoDescription,\n})\n","ts","",[22,67,68,115,149,156,168,183,195,207,219,256,281,302,314,326],{"__ignoreMap":65},[69,70,73,77,81,85,89,93,96,98,101,104,106,108,110,112],"span",{"class":71,"line":72},"line",1,[69,74,76],{"class":75},"sFsEu","const",[69,78,80],{"class":79},"sVPC0"," seoTitle",[69,82,84],{"class":83},"sFfmW"," =",[69,86,88],{"class":87},"sMo7A"," post",[69,90,92],{"class":91},"sG-J9",".",[69,94,95],{"class":87},"value",[69,97,92],{"class":91},[69,99,100],{"class":87},"seoTitle ",[69,102,103],{"class":83},"??",[69,105,88],{"class":87},[69,107,92],{"class":91},[69,109,95],{"class":87},[69,111,92],{"class":91},[69,113,114],{"class":87},"title\n",[69,116,118,120,123,125,127,129,131,133,136,138,140,142,144,146],{"class":71,"line":117},2,[69,119,76],{"class":75},[69,121,122],{"class":79}," seoDescription",[69,124,84],{"class":83},[69,126,88],{"class":87},[69,128,92],{"class":91},[69,130,95],{"class":87},[69,132,92],{"class":91},[69,134,135],{"class":87},"seoDescription ",[69,137,103],{"class":83},[69,139,88],{"class":87},[69,141,92],{"class":91},[69,143,95],{"class":87},[69,145,92],{"class":91},[69,147,148],{"class":87},"description\n",[69,150,152],{"class":71,"line":151},3,[69,153,155],{"emptyLinePlaceholder":154},true,"\n",[69,157,159,162,165],{"class":71,"line":158},4,[69,160,53],{"class":161},"sK_r7",[69,163,164],{"class":87},"(",[69,166,167],{"class":91},"{\n",[69,169,171,175,178,180],{"class":71,"line":170},5,[69,172,174],{"class":173},"sdv8B","  title",[69,176,177],{"class":91},":",[69,179,80],{"class":87},[69,181,182],{"class":91},",\n",[69,184,186,189,191,193],{"class":71,"line":185},6,[69,187,188],{"class":173},"  description",[69,190,177],{"class":91},[69,192,122],{"class":87},[69,194,182],{"class":91},[69,196,198,201,203,205],{"class":71,"line":197},7,[69,199,200],{"class":173},"  ogTitle",[69,202,177],{"class":91},[69,204,80],{"class":87},[69,206,182],{"class":91},[69,208,210,213,215,217],{"class":71,"line":209},8,[69,211,212],{"class":173},"  ogDescription",[69,214,177],{"class":91},[69,216,122],{"class":87},[69,218,182],{"class":91},[69,220,222,225,227,231,235,238,241,243,246,248,251,254],{"class":71,"line":221},9,[69,223,224],{"class":173},"  ogUrl",[69,226,177],{"class":91},[69,228,230],{"class":229},"sF_wb"," `",[69,232,234],{"class":233},"s0vBq","https:\u002F\u002Fwww.larisantos.com.br\u002Fblog\u002F",[69,236,237],{"class":229},"${",[69,239,240],{"class":87},"route",[69,242,92],{"class":229},[69,244,245],{"class":87},"params",[69,247,92],{"class":229},[69,249,250],{"class":87},"slug",[69,252,253],{"class":229},"}`",[69,255,182],{"class":91},[69,257,259,262,264,267,270,272,274,276,279],{"class":71,"line":258},10,[69,260,261],{"class":173},"  ogImage",[69,263,177],{"class":91},[69,265,266],{"class":161}," toAbsoluteUrl",[69,268,269],{"class":87},"(post",[69,271,92],{"class":91},[69,273,95],{"class":87},[69,275,92],{"class":91},[69,277,278],{"class":87},"image)",[69,280,182],{"class":91},[69,282,284,287,289,291,293,295,297,300],{"class":71,"line":283},11,[69,285,286],{"class":173},"  ogImageAlt",[69,288,177],{"class":91},[69,290,88],{"class":87},[69,292,92],{"class":91},[69,294,95],{"class":87},[69,296,92],{"class":91},[69,298,299],{"class":87},"title",[69,301,182],{"class":91},[69,303,305,308,310,312],{"class":71,"line":304},12,[69,306,307],{"class":173},"  twitterTitle",[69,309,177],{"class":91},[69,311,80],{"class":87},[69,313,182],{"class":91},[69,315,317,320,322,324],{"class":71,"line":316},13,[69,318,319],{"class":173},"  twitterDescription",[69,321,177],{"class":91},[69,323,122],{"class":87},[69,325,182],{"class":91},[69,327,329,332],{"class":71,"line":328},14,[69,330,331],{"class":91},"}",[69,333,334],{"class":87},")\n",[12,336,337,338,341,342,345],{},"Repare que ",[22,339,340],{},"ogTitle"," e ",[22,343,344],{},"twitterTitle"," recebem o mesmo valor do title. É comum esquecer esses campos e acabar com o Twitter Card mostrando o texto da home em todas as páginas, um bug silencioso que só aparece quando o link é compartilhado.",[12,347,348,349,352,353,177],{},"Falta um detalhe que evita conteúdo duplicado: o ",[22,350,351],{},"canonical",". Ele declara qual é a URL oficial daquela página, para o buscador não tratar variações como páginas diferentes. Ainda na mesma página, ele vai pelo ",[22,354,355],{},"useHead",[60,357,359],{"className":62,"code":358,"language":64,"meta":65,"style":65},"useHead({\n  link: [\n    {\n      rel: \"canonical\",\n      href: `https:\u002F\u002Fwww.larisantos.com.br\u002Fblog\u002F${route.params.slug}`,\n    },\n  ],\n})\n",[22,360,361,369,379,384,401,428,433,440],{"__ignoreMap":65},[69,362,363,365,367],{"class":71,"line":72},[69,364,355],{"class":161},[69,366,164],{"class":87},[69,368,167],{"class":91},[69,370,371,374,376],{"class":71,"line":117},[69,372,373],{"class":173},"  link",[69,375,177],{"class":91},[69,377,378],{"class":87}," [\n",[69,380,381],{"class":71,"line":151},[69,382,383],{"class":91},"    {\n",[69,385,386,389,391,394,396,399],{"class":71,"line":158},[69,387,388],{"class":173},"      rel",[69,390,177],{"class":91},[69,392,393],{"class":229}," \"",[69,395,351],{"class":233},[69,397,398],{"class":229},"\"",[69,400,182],{"class":91},[69,402,403,406,408,410,412,414,416,418,420,422,424,426],{"class":71,"line":170},[69,404,405],{"class":173},"      href",[69,407,177],{"class":91},[69,409,230],{"class":229},[69,411,234],{"class":233},[69,413,237],{"class":229},[69,415,240],{"class":87},[69,417,92],{"class":229},[69,419,245],{"class":87},[69,421,92],{"class":229},[69,423,250],{"class":87},[69,425,253],{"class":229},[69,427,182],{"class":91},[69,429,430],{"class":71,"line":185},[69,431,432],{"class":91},"    },\n",[69,434,435,438],{"class":71,"line":197},[69,436,437],{"class":87},"  ]",[69,439,182],{"class":91},[69,441,442,444],{"class":71,"line":209},[69,443,331],{"class":91},[69,445,334],{"class":87},[12,447,448],{},"Sem o canonical apontando para si mesma, uma página de listagem pode acabar canonizada para a home, e o Google deixa de indexá-la como página própria. É um erro sutil e comum, que vale conferir em cada rota.",[27,450],{},[30,452,454],{"id":453},"ogimage-dinâmica-um-preview-por-página","og:image dinâmica: um preview por página",[12,456,457],{},"A og:image é a imagem exibida quando um link é compartilhado no WhatsApp, no LinkedIn ou no Twitter. Por muito tempo era uma imagem fixa, a mesma para o site inteiro. Isso já resolve para uma landing page única, mas cai por terra assim que o site tem mais de uma página relevante: cada URL compartilhada exibe o mesmo cartão genérico, sem título e sem contexto do que está por trás daquele link. Num blog fica evidente: cada post merece um preview próprio. Mas o problema vale para qualquer conjunto de páginas dinâmicas.",[12,459,460,461,463,464,467,468,471],{},"O módulo ",[22,462,24],{}," resolve isso gerando a imagem no servidor a partir de um componente Vue. A convenção é o ponto elegante da abordagem: qualquer componente criado em ",[22,465,466],{},"components\u002FOgImage\u002F"," vira automaticamente um template disponível. O nome do arquivo é o primeiro argumento do ",[22,469,470],{},"defineOgImageComponent",", e as props do componente são os dados passados no segundo argumento.",[12,473,474,475,478,479,482,483,486,487,489],{},"As dimensões e o renderer padrão ficam globais no ",[22,476,477],{},"nuxt.config.ts",", sob ",[22,480,481],{},"ogImage.defaults"," (1200x630, renderer ",[22,484,485],{},"satori","), já que valem para todo o site. O que muda por rota é a chamada, feita no ",[22,488,57],{}," de cada página:",[60,491,493],{"className":62,"code":492,"language":64,"meta":65,"style":65},"defineOgImageComponent(\"OgImageOgBlogPost\", {\n  title: post.value.title,\n  description: post.value.description,\n  date: formatDate(post.value.date),\n  image: post.value.image,\n  tags: post.value.tags,\n})\n",[22,494,495,514,532,551,574,594,614],{"__ignoreMap":65},[69,496,497,499,501,503,506,508,511],{"class":71,"line":72},[69,498,470],{"class":161},[69,500,164],{"class":87},[69,502,398],{"class":229},[69,504,505],{"class":233},"OgImageOgBlogPost",[69,507,398],{"class":229},[69,509,510],{"class":91},",",[69,512,513],{"class":91}," {\n",[69,515,516,518,520,522,524,526,528,530],{"class":71,"line":117},[69,517,174],{"class":173},[69,519,177],{"class":91},[69,521,88],{"class":87},[69,523,92],{"class":91},[69,525,95],{"class":87},[69,527,92],{"class":91},[69,529,299],{"class":87},[69,531,182],{"class":91},[69,533,534,536,538,540,542,544,546,549],{"class":71,"line":151},[69,535,188],{"class":173},[69,537,177],{"class":91},[69,539,88],{"class":87},[69,541,92],{"class":91},[69,543,95],{"class":87},[69,545,92],{"class":91},[69,547,548],{"class":87},"description",[69,550,182],{"class":91},[69,552,553,556,558,561,563,565,567,569,572],{"class":71,"line":158},[69,554,555],{"class":173},"  date",[69,557,177],{"class":91},[69,559,560],{"class":161}," formatDate",[69,562,269],{"class":87},[69,564,92],{"class":91},[69,566,95],{"class":87},[69,568,92],{"class":91},[69,570,571],{"class":87},"date)",[69,573,182],{"class":91},[69,575,576,579,581,583,585,587,589,592],{"class":71,"line":170},[69,577,578],{"class":173},"  image",[69,580,177],{"class":91},[69,582,88],{"class":87},[69,584,92],{"class":91},[69,586,95],{"class":87},[69,588,92],{"class":91},[69,590,591],{"class":87},"image",[69,593,182],{"class":91},[69,595,596,599,601,603,605,607,609,612],{"class":71,"line":185},[69,597,598],{"class":173},"  tags",[69,600,177],{"class":91},[69,602,88],{"class":87},[69,604,92],{"class":91},[69,606,95],{"class":87},[69,608,92],{"class":91},[69,610,611],{"class":87},"tags",[69,613,182],{"class":91},[69,615,616,618],{"class":71,"line":197},[69,617,331],{"class":91},[69,619,334],{"class":87},[12,621,622,623,626],{},"Cada post passa seus próprios dados, e o componente ",[22,624,625],{},"OgBlogPost.vue"," monta a imagem 1200x630 com o título, a descrição e as tags daquele post. Nos bastidores, o Satori pega esse componente e renderiza como imagem no servidor. Todo link compartilhado passa a refletir o conteúdo real da página, sem geração manual de imagem.",[12,628,629],{},[630,631],"img",{"alt":632,"src":633},"Exemplo de og:image gerada dinamicamente pelo Satori, com título, descrição e tags de um post preenchidos a partir dos dados reais da página","\u002Fimages\u002Fblog\u002Fseo\u002Fog-image-exemplo.png",[12,635,636,637,640],{},"O componente é um Vue normal, mas com uma restrição importante: o Satori só entende um subconjunto de CSS, e não roda JavaScript. Isso exclui classes utilitárias que dependam de runtime e qualquer layout que precise de cálculo no navegador. Tudo é estilo inline e flexbox direto: gradiente de fundo, título com ",[22,638,639],{},"line-clamp"," para não estourar, tags como pílulas e a marca do site num canto.",[12,642,643,644,646,647,650,651,654],{},"Um detalhe passa batido e não dá erro nenhum: o segundo argumento do ",[22,645,470],{}," é um objeto, não um array. Se ele for passado como ",[22,648,649],{},"[]"," em vez de ",[22,652,653],{},"{}",", a og:image simplesmente não é gerada, e o console fica em silêncio. Quando o preview não sair, o tipo desse argumento é o primeiro lugar para olhar.",[12,656,657,658,665],{},"Para validar antes de publicar, o ",[659,660,664],"a",{"href":661,"rel":662},"https:\u002F\u002Fmetatags.io",[663],"nofollow","metatags.io"," simula como o link vai aparecer em cada rede.",[27,667],{},[30,669,671],{"id":670},"schemaorg-dado-estruturado-que-a-ia-entende","Schema.org: dado estruturado que a IA entende",[12,673,674],{},"Se a og:image fala com a pessoa que vê o link, o Schema.org fala com a máquina que lê a página. É um vocabulário de dados estruturados injetado no HTML em formato JSON-LD, descrevendo o que aquele conteúdo é: um artigo, uma pessoa, uma organização, uma trilha de navegação. O buscador usa isso para montar rich snippets, e as IAs usam para entender a entidade por trás do site com menos ambiguidade.",[12,676,677,678,681,682,684,685,688,689,692,693,695,696,699],{},"No Nuxt, o ",[22,679,680],{},"useSchemaOrg"," do ",[22,683,24],{}," traz funções prontas para os tipos mais comuns. O primeiro cuidado é escolher o tipo raiz certo. Um portfólio pessoal se descreve como ",[22,686,687],{},"Person",", não como ",[22,690,691],{},"Organization",", porque é ",[22,694,687],{}," que habilita o snippet com nome, cargo e foto. Como esse dado descreve a autora do site inteiro, ele é declarado uma vez só no ",[22,697,698],{},"app.vue",", não em cada página:",[60,701,703],{"className":62,"code":702,"language":64,"meta":65,"style":65},"useSchemaOrg([\n  definePerson({\n    \"@id\": \"https:\u002F\u002Fwww.larisantos.com.br\u002F#larissa\",\n    name: \"Larissa Santos\",\n    jobTitle: \"Desenvolvedora Frontend\",\n    image: \"https:\u002F\u002Fwww.larisantos.com.br\u002Fimages\u002Flarissa.png\",\n    sameAs: [\n      \"https:\u002F\u002Fgithub.com\u002FLariMoro20\",\n      \"https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Flari-moro-ss\",\n    ],\n  }),\n])\n",[22,704,705,712,721,743,758,774,790,799,811,822,829,839],{"__ignoreMap":65},[69,706,707,709],{"class":71,"line":72},[69,708,680],{"class":161},[69,710,711],{"class":87},"([\n",[69,713,714,717,719],{"class":71,"line":117},[69,715,716],{"class":161},"  definePerson",[69,718,164],{"class":87},[69,720,167],{"class":91},[69,722,723,726,730,732,734,736,739,741],{"class":71,"line":151},[69,724,725],{"class":229},"    \"",[69,727,729],{"class":728},"swHuM","@id",[69,731,398],{"class":229},[69,733,177],{"class":91},[69,735,393],{"class":229},[69,737,738],{"class":233},"https:\u002F\u002Fwww.larisantos.com.br\u002F#larissa",[69,740,398],{"class":229},[69,742,182],{"class":91},[69,744,745,748,750,752,754,756],{"class":71,"line":158},[69,746,747],{"class":173},"    name",[69,749,177],{"class":91},[69,751,393],{"class":229},[69,753,7],{"class":233},[69,755,398],{"class":229},[69,757,182],{"class":91},[69,759,760,763,765,767,770,772],{"class":71,"line":170},[69,761,762],{"class":173},"    jobTitle",[69,764,177],{"class":91},[69,766,393],{"class":229},[69,768,769],{"class":233},"Desenvolvedora Frontend",[69,771,398],{"class":229},[69,773,182],{"class":91},[69,775,776,779,781,783,786,788],{"class":71,"line":185},[69,777,778],{"class":173},"    image",[69,780,177],{"class":91},[69,782,393],{"class":229},[69,784,785],{"class":233},"https:\u002F\u002Fwww.larisantos.com.br\u002Fimages\u002Flarissa.png",[69,787,398],{"class":229},[69,789,182],{"class":91},[69,791,792,795,797],{"class":71,"line":197},[69,793,794],{"class":173},"    sameAs",[69,796,177],{"class":91},[69,798,378],{"class":87},[69,800,801,804,807,809],{"class":71,"line":209},[69,802,803],{"class":229},"      \"",[69,805,806],{"class":233},"https:\u002F\u002Fgithub.com\u002FLariMoro20",[69,808,398],{"class":229},[69,810,182],{"class":91},[69,812,813,815,818,820],{"class":71,"line":221},[69,814,803],{"class":229},[69,816,817],{"class":233},"https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Flari-moro-ss",[69,819,398],{"class":229},[69,821,182],{"class":91},[69,823,824,827],{"class":71,"line":258},[69,825,826],{"class":87},"    ]",[69,828,182],{"class":91},[69,830,831,834,837],{"class":71,"line":283},[69,832,833],{"class":91},"  }",[69,835,836],{"class":87},")",[69,838,182],{"class":91},[69,840,841],{"class":71,"line":304},[69,842,843],{"class":87},"])\n",[12,845,846,847,850],{},"O ",[22,848,849],{},"sameAs"," é o campo que conecta os perfis. Ele informa ao buscador e às IAs que a pessoa deste site é a mesma do GitHub e do LinkedIn. É isso que consolida o reconhecimento de entidade, quando várias fontes apontam para a mesma pessoa com dados consistentes.",[12,852,853,854,857],{},"Já dentro da página de cada post, o tipo certo é ",[22,855,856],{},"BlogPosting",", com título, datas de publicação e modificação, autor e palavras-chave:",[60,859,861],{"className":62,"code":860,"language":64,"meta":65,"style":65},"defineArticle({\n  \"@type\": \"BlogPosting\",\n  headline: post.value.title,\n  description: post.value.description,\n  image: toAbsoluteUrl(post.value.image),\n  datePublished: post.value.date,\n  dateModified: post.value.updated ?? post.value.date,\n  author: {\n    \"@id\": \"https:\u002F\u002Fwww.larisantos.com.br\u002F#larissa\",\n  },\n  keywords: post.value.tags,\n  inLanguage: \"pt-BR\",\n})\n",[22,862,863,872,892,911,929,949,969,1001,1010,1028,1033,1052,1068],{"__ignoreMap":65},[69,864,865,868,870],{"class":71,"line":72},[69,866,867],{"class":161},"defineArticle",[69,869,164],{"class":87},[69,871,167],{"class":91},[69,873,874,877,880,882,884,886,888,890],{"class":71,"line":117},[69,875,876],{"class":229},"  \"",[69,878,879],{"class":728},"@type",[69,881,398],{"class":229},[69,883,177],{"class":91},[69,885,393],{"class":229},[69,887,856],{"class":233},[69,889,398],{"class":229},[69,891,182],{"class":91},[69,893,894,897,899,901,903,905,907,909],{"class":71,"line":151},[69,895,896],{"class":173},"  headline",[69,898,177],{"class":91},[69,900,88],{"class":87},[69,902,92],{"class":91},[69,904,95],{"class":87},[69,906,92],{"class":91},[69,908,299],{"class":87},[69,910,182],{"class":91},[69,912,913,915,917,919,921,923,925,927],{"class":71,"line":158},[69,914,188],{"class":173},[69,916,177],{"class":91},[69,918,88],{"class":87},[69,920,92],{"class":91},[69,922,95],{"class":87},[69,924,92],{"class":91},[69,926,548],{"class":87},[69,928,182],{"class":91},[69,930,931,933,935,937,939,941,943,945,947],{"class":71,"line":170},[69,932,578],{"class":173},[69,934,177],{"class":91},[69,936,266],{"class":161},[69,938,269],{"class":87},[69,940,92],{"class":91},[69,942,95],{"class":87},[69,944,92],{"class":91},[69,946,278],{"class":87},[69,948,182],{"class":91},[69,950,951,954,956,958,960,962,964,967],{"class":71,"line":185},[69,952,953],{"class":173},"  datePublished",[69,955,177],{"class":91},[69,957,88],{"class":87},[69,959,92],{"class":91},[69,961,95],{"class":87},[69,963,92],{"class":91},[69,965,966],{"class":87},"date",[69,968,182],{"class":91},[69,970,971,974,976,978,980,982,984,987,989,991,993,995,997,999],{"class":71,"line":197},[69,972,973],{"class":173},"  dateModified",[69,975,177],{"class":91},[69,977,88],{"class":87},[69,979,92],{"class":91},[69,981,95],{"class":87},[69,983,92],{"class":91},[69,985,986],{"class":87},"updated ",[69,988,103],{"class":83},[69,990,88],{"class":87},[69,992,92],{"class":91},[69,994,95],{"class":87},[69,996,92],{"class":91},[69,998,966],{"class":87},[69,1000,182],{"class":91},[69,1002,1003,1006,1008],{"class":71,"line":209},[69,1004,1005],{"class":173},"  author",[69,1007,177],{"class":91},[69,1009,513],{"class":91},[69,1011,1012,1014,1016,1018,1020,1022,1024,1026],{"class":71,"line":221},[69,1013,725],{"class":229},[69,1015,729],{"class":728},[69,1017,398],{"class":229},[69,1019,177],{"class":91},[69,1021,393],{"class":229},[69,1023,738],{"class":233},[69,1025,398],{"class":229},[69,1027,182],{"class":91},[69,1029,1030],{"class":71,"line":258},[69,1031,1032],{"class":91},"  },\n",[69,1034,1035,1038,1040,1042,1044,1046,1048,1050],{"class":71,"line":283},[69,1036,1037],{"class":173},"  keywords",[69,1039,177],{"class":91},[69,1041,88],{"class":87},[69,1043,92],{"class":91},[69,1045,95],{"class":87},[69,1047,92],{"class":91},[69,1049,611],{"class":87},[69,1051,182],{"class":91},[69,1053,1054,1057,1059,1061,1064,1066],{"class":71,"line":304},[69,1055,1056],{"class":173},"  inLanguage",[69,1058,177],{"class":91},[69,1060,393],{"class":229},[69,1062,1063],{"class":233},"pt-BR",[69,1065,398],{"class":229},[69,1067,182],{"class":91},[69,1069,1070,1072],{"class":71,"line":316},[69,1071,331],{"class":91},[69,1073,334],{"class":87},[12,1075,846,1076,1079,1080,1082],{},[22,1077,1078],{},"author"," aponta por ",[22,1081,729],{}," para a mesma pessoa definida na raiz. Em vez de repetir os dados do autor dentro do artigo, só o identificador é referenciado. Assim o grafo de dados fica coerente: existe uma única entidade, e cada post é escrito por ela.",[12,1084,1085,1086,1089],{},"Junto do artigo vai um ",[22,1087,1088],{},"BreadcrumbList",", que é a trilha Home > Blog > Título do Post:",[60,1091,1093],{"className":62,"code":1092,"language":64,"meta":65,"style":65},"defineBreadcrumb({\n  itemListElement: [\n    { name: \"Home\", item: \"https:\u002F\u002Fwww.larisantos.com.br\" },\n    { name: \"Blog\", item: \"https:\u002F\u002Fwww.larisantos.com.br\u002Fblog\" },\n    {\n      name: post.value.title,\n      item: `https:\u002F\u002Fwww.larisantos.com.br\u002Fblog\u002F${route.params.slug}`,\n    },\n  ],\n})\n",[22,1094,1095,1104,1113,1147,1177,1181,1200,1227,1231,1237],{"__ignoreMap":65},[69,1096,1097,1100,1102],{"class":71,"line":72},[69,1098,1099],{"class":161},"defineBreadcrumb",[69,1101,164],{"class":87},[69,1103,167],{"class":91},[69,1105,1106,1109,1111],{"class":71,"line":117},[69,1107,1108],{"class":173},"  itemListElement",[69,1110,177],{"class":91},[69,1112,378],{"class":87},[69,1114,1115,1118,1121,1123,1125,1128,1130,1132,1135,1137,1139,1142,1144],{"class":71,"line":151},[69,1116,1117],{"class":91},"    {",[69,1119,1120],{"class":173}," name",[69,1122,177],{"class":91},[69,1124,393],{"class":229},[69,1126,1127],{"class":233},"Home",[69,1129,398],{"class":229},[69,1131,510],{"class":91},[69,1133,1134],{"class":173}," item",[69,1136,177],{"class":91},[69,1138,393],{"class":229},[69,1140,1141],{"class":233},"https:\u002F\u002Fwww.larisantos.com.br",[69,1143,398],{"class":229},[69,1145,1146],{"class":91}," },\n",[69,1148,1149,1151,1153,1155,1157,1160,1162,1164,1166,1168,1170,1173,1175],{"class":71,"line":158},[69,1150,1117],{"class":91},[69,1152,1120],{"class":173},[69,1154,177],{"class":91},[69,1156,393],{"class":229},[69,1158,1159],{"class":233},"Blog",[69,1161,398],{"class":229},[69,1163,510],{"class":91},[69,1165,1134],{"class":173},[69,1167,177],{"class":91},[69,1169,393],{"class":229},[69,1171,1172],{"class":233},"https:\u002F\u002Fwww.larisantos.com.br\u002Fblog",[69,1174,398],{"class":229},[69,1176,1146],{"class":91},[69,1178,1179],{"class":71,"line":170},[69,1180,383],{"class":91},[69,1182,1183,1186,1188,1190,1192,1194,1196,1198],{"class":71,"line":185},[69,1184,1185],{"class":173},"      name",[69,1187,177],{"class":91},[69,1189,88],{"class":87},[69,1191,92],{"class":91},[69,1193,95],{"class":87},[69,1195,92],{"class":91},[69,1197,299],{"class":87},[69,1199,182],{"class":91},[69,1201,1202,1205,1207,1209,1211,1213,1215,1217,1219,1221,1223,1225],{"class":71,"line":197},[69,1203,1204],{"class":173},"      item",[69,1206,177],{"class":91},[69,1208,230],{"class":229},[69,1210,234],{"class":233},[69,1212,237],{"class":229},[69,1214,240],{"class":87},[69,1216,92],{"class":229},[69,1218,245],{"class":87},[69,1220,92],{"class":229},[69,1222,250],{"class":87},[69,1224,253],{"class":229},[69,1226,182],{"class":91},[69,1228,1229],{"class":71,"line":209},[69,1230,432],{"class":91},[69,1232,1233,1235],{"class":71,"line":221},[69,1234,437],{"class":87},[69,1236,182],{"class":91},[69,1238,1239,1241],{"class":71,"line":258},[69,1240,331],{"class":91},[69,1242,334],{"class":87},[12,1244,1245],{},"Ele aparece nos resultados de busca como o caminho de navegação em vez da URL crua, e ajuda tanto o Google quanto a IA a entenderem onde a página se encaixa na estrutura do site.",[27,1247],{},[30,1249,1251],{"id":1250},"aeo-transformar-o-conteúdo-em-resposta","AEO: transformar o conteúdo em resposta",[12,1253,1254,1255,1257,1258,1261],{},"Enquanto o ",[22,1256,856],{}," diz o que a página é, o ",[22,1259,1260],{},"FAQPage"," diz o que ela responde. Essa é a ponte para o AEO. Quando um post tem uma seção de perguntas e respostas, dá para expor isso como dado estruturado, e o Google pode usar direto como resposta destacada.",[12,1263,1264,1265,1267],{},"A estrutura do ",[22,1266,1260],{}," é uma lista de perguntas, cada uma com sua resposta aceita:",[60,1269,1271],{"className":62,"code":1270,"language":64,"meta":65,"style":65},"useSchemaOrg([\n  {\n    \"@type\": \"FAQPage\",\n    mainEntity: [\n      {\n        \"@type\": \"Question\",\n        name: \"Como gerar uma og:image dinâmica no Nuxt?\",\n        acceptedAnswer: {\n          \"@type\": \"Answer\",\n          text: \"Com o módulo @nuxtjs\u002Fseo. Cada componente em components\u002FOgImage\u002F vira um template, e o defineOgImageComponent passa os dados da página.\",\n        },\n      },\n    ],\n  },\n])\n",[22,1272,1273,1279,1284,1302,1311,1316,1336,1352,1361,1381,1397,1402,1407,1413,1417],{"__ignoreMap":65},[69,1274,1275,1277],{"class":71,"line":72},[69,1276,680],{"class":161},[69,1278,711],{"class":87},[69,1280,1281],{"class":71,"line":117},[69,1282,1283],{"class":91},"  {\n",[69,1285,1286,1288,1290,1292,1294,1296,1298,1300],{"class":71,"line":151},[69,1287,725],{"class":229},[69,1289,879],{"class":728},[69,1291,398],{"class":229},[69,1293,177],{"class":91},[69,1295,393],{"class":229},[69,1297,1260],{"class":233},[69,1299,398],{"class":229},[69,1301,182],{"class":91},[69,1303,1304,1307,1309],{"class":71,"line":158},[69,1305,1306],{"class":173},"    mainEntity",[69,1308,177],{"class":91},[69,1310,378],{"class":87},[69,1312,1313],{"class":71,"line":170},[69,1314,1315],{"class":91},"      {\n",[69,1317,1318,1321,1323,1325,1327,1329,1332,1334],{"class":71,"line":185},[69,1319,1320],{"class":229},"        \"",[69,1322,879],{"class":728},[69,1324,398],{"class":229},[69,1326,177],{"class":91},[69,1328,393],{"class":229},[69,1330,1331],{"class":233},"Question",[69,1333,398],{"class":229},[69,1335,182],{"class":91},[69,1337,1338,1341,1343,1345,1348,1350],{"class":71,"line":197},[69,1339,1340],{"class":173},"        name",[69,1342,177],{"class":91},[69,1344,393],{"class":229},[69,1346,1347],{"class":233},"Como gerar uma og:image dinâmica no Nuxt?",[69,1349,398],{"class":229},[69,1351,182],{"class":91},[69,1353,1354,1357,1359],{"class":71,"line":209},[69,1355,1356],{"class":173},"        acceptedAnswer",[69,1358,177],{"class":91},[69,1360,513],{"class":91},[69,1362,1363,1366,1368,1370,1372,1374,1377,1379],{"class":71,"line":221},[69,1364,1365],{"class":229},"          \"",[69,1367,879],{"class":728},[69,1369,398],{"class":229},[69,1371,177],{"class":91},[69,1373,393],{"class":229},[69,1375,1376],{"class":233},"Answer",[69,1378,398],{"class":229},[69,1380,182],{"class":91},[69,1382,1383,1386,1388,1390,1393,1395],{"class":71,"line":258},[69,1384,1385],{"class":173},"          text",[69,1387,177],{"class":91},[69,1389,393],{"class":229},[69,1391,1392],{"class":233},"Com o módulo @nuxtjs\u002Fseo. Cada componente em components\u002FOgImage\u002F vira um template, e o defineOgImageComponent passa os dados da página.",[69,1394,398],{"class":229},[69,1396,182],{"class":91},[69,1398,1399],{"class":71,"line":283},[69,1400,1401],{"class":91},"        },\n",[69,1403,1404],{"class":71,"line":304},[69,1405,1406],{"class":91},"      },\n",[69,1408,1409,1411],{"class":71,"line":316},[69,1410,826],{"class":87},[69,1412,182],{"class":91},[69,1414,1415],{"class":71,"line":328},[69,1416,1032],{"class":91},[69,1418,1420],{"class":71,"line":1419},15,[69,1421,843],{"class":87},[12,1423,1424,1425,1428],{},"Uma forma prática é manter essas perguntas no próprio frontmatter do post, num campo ",[22,1426,1427],{},"faq",", e só montar o schema quando o post tiver perguntas, para não marcar página com dado estruturado vazio. O que mais pesa aqui é a redação da resposta. Ela precisa funcionar fora de contexto, responder a pergunta em uma ou duas frases sem depender do resto do texto, porque é assim que vai ser extraída e mostrada como resposta destacada.",[27,1430],{},[30,1432,1434],{"id":1433},"geo-falar-com-os-bots-de-ia","GEO: falar com os bots de IA",[12,1436,1437,1438,1441],{},"A última frente é a que mais mudou nos últimos tempos. As IAs generativas rastreiam a web com crawlers próprios, cada um com seu user-agent, e boa parte deles respeita o ",[22,1439,1440],{},"robots.txt"," para decidir se lê o conteúdo do site. Para aparecer nas respostas dessas IAs, é preciso liberar esses agentes de forma explícita.",[12,1443,1444,1445,1447,1448,1451,1452,1454],{},"No Nuxt, em vez de escrever o arquivo na mão, os grupos são declarados no ",[22,1446,477],{}," sob ",[22,1449,1450],{},"robots",", e o módulo gera o ",[22,1453,1440],{},". O arquivo resultante lista os bots que interessam:",[60,1456,1460],{"className":1457,"code":1458,"language":1459,"meta":65,"style":65},"language-txt shiki shiki-themes material-theme-lighter github-dark github-dark","User-agent: GPTBot\nAllow: \u002F\n\nUser-agent: ClaudeBot\nAllow: \u002F\n\nUser-agent: PerplexityBot\nAllow: \u002F\n\nUser-agent: Google-Extended\nAllow: \u002F\n","txt",[22,1461,1462,1467,1472,1476,1481,1485,1489,1494,1498,1502,1507],{"__ignoreMap":65},[69,1463,1464],{"class":71,"line":72},[69,1465,1466],{},"User-agent: GPTBot\n",[69,1468,1469],{"class":71,"line":117},[69,1470,1471],{},"Allow: \u002F\n",[69,1473,1474],{"class":71,"line":151},[69,1475,155],{"emptyLinePlaceholder":154},[69,1477,1478],{"class":71,"line":158},[69,1479,1480],{},"User-agent: ClaudeBot\n",[69,1482,1483],{"class":71,"line":170},[69,1484,1471],{},[69,1486,1487],{"class":71,"line":185},[69,1488,155],{"emptyLinePlaceholder":154},[69,1490,1491],{"class":71,"line":197},[69,1492,1493],{},"User-agent: PerplexityBot\n",[69,1495,1496],{"class":71,"line":209},[69,1497,1471],{},[69,1499,1500],{"class":71,"line":221},[69,1501,155],{"emptyLinePlaceholder":154},[69,1503,1504],{"class":71,"line":258},[69,1505,1506],{},"User-agent: Google-Extended\n",[69,1508,1509],{"class":71,"line":283},[69,1510,1471],{},[12,1512,846,1513,1516],{},[22,1514,1515],{},"Google-Extended"," é o que controla o uso do conteúdo pelas funcionalidades de IA do Google, separado do crawler de busca tradicional. Com ele dá para bloquear a IA e continuar aparecendo na busca normal, ou o contrário, e essa separação deixa a escolha nas mãos de quem mantém o site.",[12,1518,1519,1520,1523,1524,1527],{},"A segunda parte do GEO é o ",[22,1521,1522],{},"llms.txt",", um arquivo na raiz do site, em ",[22,1525,1526],{},"\u002Fllms.txt",", que descreve em linguagem natural o que o site é, quem o mantém e como o conteúdo está organizado. É um resumo curado, feito para modelo de linguagem ler. Não é um padrão consolidado ainda, mas é barato de manter e serve como um contexto direto sobre a entidade, sem a IA ter que inferir tudo só do HTML.",[12,1529,1530],{},"O formato é Markdown simples: um título com o nome, um resumo em blockquote e seções com os dados e os links principais.",[60,1532,1536],{"className":1533,"code":1534,"language":1535,"meta":65,"style":65},"language-md shiki shiki-themes material-theme-lighter github-dark github-dark","# Larissa Santos, Desenvolvedora Frontend\n\n> Portfólio e blog de Larissa Santos, desenvolvedora Frontend\n> especialista em Vue.js, Nuxt e Quasar, com background fullstack em PHP.\n\n## Sobre\n- **Cargo:** Desenvolvedora Frontend\n- **Especialidades:** Vue.js 3, Nuxt, TypeScript, Pinia, Tailwind CSS\n- **Site:** https:\u002F\u002Fwww.larisantos.com.br\n\n## Links\n- [Portfólio](https:\u002F\u002Fwww.larisantos.com.br)\n- [Blog](https:\u002F\u002Fwww.larisantos.com.br\u002Fblog)\n- [GitHub](https:\u002F\u002Fgithub.com\u002FLariMoro20)\n\n## Blog\nArtigos técnicos em português sobre frontend, JavaScript, Vue.js e arquitetura.\n- [Vuex vs Pinia: guia completo de gerenciamento de estado](https:\u002F\u002Fwww.larisantos.com.br\u002Fblog\u002Fvuex-vs-pinia)\n- [Virtual DOM por baixo dos panos: um mini-framework do zero](https:\u002F\u002Fwww.larisantos.com.br\u002Fblog\u002Fvirtual-dom-mini-framework-do-zero)\n","md",[22,1537,1538,1548,1552,1562,1569,1573,1581,1601,1615,1629,1633,1640,1659,1673,1688,1692,1700,1706,1723],{"__ignoreMap":65},[69,1539,1540,1544],{"class":71,"line":72},[69,1541,1543],{"class":1542},"sSElE","# ",[69,1545,1547],{"class":1546},"s4BmV","Larissa Santos, Desenvolvedora Frontend\n",[69,1549,1550],{"class":71,"line":117},[69,1551,155],{"emptyLinePlaceholder":154},[69,1553,1554,1558],{"class":71,"line":151},[69,1555,1557],{"class":1556},"s63Gb",">",[69,1559,1561],{"class":1560},"sJeIW"," Portfólio e blog de Larissa Santos, desenvolvedora Frontend\n",[69,1563,1564,1566],{"class":71,"line":158},[69,1565,1557],{"class":1556},[69,1567,1568],{"class":1560}," especialista em Vue.js, Nuxt e Quasar, com background fullstack em PHP.\n",[69,1570,1571],{"class":71,"line":170},[69,1572,155],{"emptyLinePlaceholder":154},[69,1574,1575,1578],{"class":71,"line":185},[69,1576,1577],{"class":1542},"## ",[69,1579,1580],{"class":1546},"Sobre\n",[69,1582,1583,1587,1591,1595,1598],{"class":71,"line":197},[69,1584,1586],{"class":1585},"sUVGp","-",[69,1588,1590],{"class":1589},"shnMK"," **",[69,1592,1594],{"class":1593},"smV4n","Cargo:",[69,1596,1597],{"class":1589},"**",[69,1599,1600],{"class":87}," Desenvolvedora Frontend\n",[69,1602,1603,1605,1607,1610,1612],{"class":71,"line":209},[69,1604,1586],{"class":1585},[69,1606,1590],{"class":1589},[69,1608,1609],{"class":1593},"Especialidades:",[69,1611,1597],{"class":1589},[69,1613,1614],{"class":87}," Vue.js 3, Nuxt, TypeScript, Pinia, Tailwind CSS\n",[69,1616,1617,1619,1621,1624,1626],{"class":71,"line":221},[69,1618,1586],{"class":1585},[69,1620,1590],{"class":1589},[69,1622,1623],{"class":1593},"Site:",[69,1625,1597],{"class":1589},[69,1627,1628],{"class":87}," https:\u002F\u002Fwww.larisantos.com.br\n",[69,1630,1631],{"class":71,"line":258},[69,1632,155],{"emptyLinePlaceholder":154},[69,1634,1635,1637],{"class":71,"line":283},[69,1636,1577],{"class":1542},[69,1638,1639],{"class":1546},"Links\n",[69,1641,1642,1644,1647,1651,1654,1657],{"class":71,"line":304},[69,1643,1586],{"class":1585},[69,1645,1646],{"class":91}," [",[69,1648,1650],{"class":1649},"sM8Rc","Portfólio",[69,1652,1653],{"class":91},"](",[69,1655,1141],{"class":1656},"sH2AH",[69,1658,334],{"class":91},[69,1660,1661,1663,1665,1667,1669,1671],{"class":71,"line":316},[69,1662,1586],{"class":1585},[69,1664,1646],{"class":91},[69,1666,1159],{"class":1649},[69,1668,1653],{"class":91},[69,1670,1172],{"class":1656},[69,1672,334],{"class":91},[69,1674,1675,1677,1679,1682,1684,1686],{"class":71,"line":328},[69,1676,1586],{"class":1585},[69,1678,1646],{"class":91},[69,1680,1681],{"class":1649},"GitHub",[69,1683,1653],{"class":91},[69,1685,806],{"class":1656},[69,1687,334],{"class":91},[69,1689,1690],{"class":71,"line":1419},[69,1691,155],{"emptyLinePlaceholder":154},[69,1693,1695,1697],{"class":71,"line":1694},16,[69,1696,1577],{"class":1542},[69,1698,1699],{"class":1546},"Blog\n",[69,1701,1703],{"class":71,"line":1702},17,[69,1704,1705],{"class":87},"Artigos técnicos em português sobre frontend, JavaScript, Vue.js e arquitetura.\n",[69,1707,1709,1711,1713,1716,1718,1721],{"class":71,"line":1708},18,[69,1710,1586],{"class":1585},[69,1712,1646],{"class":91},[69,1714,1715],{"class":1649},"Vuex vs Pinia: guia completo de gerenciamento de estado",[69,1717,1653],{"class":91},[69,1719,1720],{"class":1656},"https:\u002F\u002Fwww.larisantos.com.br\u002Fblog\u002Fvuex-vs-pinia",[69,1722,334],{"class":91},[69,1724,1726,1728,1730,1733,1735,1738],{"class":71,"line":1725},19,[69,1727,1586],{"class":1585},[69,1729,1646],{"class":91},[69,1731,1732],{"class":1649},"Virtual DOM por baixo dos panos: um mini-framework do zero",[69,1734,1653],{"class":91},[69,1736,1737],{"class":1656},"https:\u002F\u002Fwww.larisantos.com.br\u002Fblog\u002Fvirtual-dom-mini-framework-do-zero",[69,1739,334],{"class":91},[12,1741,1742],{},"O conteúdo é enxuto e factual: nome, o que o site é, o posicionamento, a lista de seções e uma linha sobre cada área. Nada de invenção, só a mesma informação que já está no site, organizada de forma que uma IA consuma rápido.",[27,1744],{},[30,1746,1748],{"id":1747},"sitemapxml-o-mapa-para-os-crawlers","sitemap.xml: o mapa para os crawlers",[12,1750,1751,1752,1754,1755,1758],{},"Se o ",[22,1753,1440],{}," diz quem pode entrar, o ",[22,1756,1757],{},"sitemap.xml"," diz o que existe para ser rastreado. É a lista de todas as URLs do site, que o buscador usa para descobrir páginas sem depender só de seguir links. Para um blog que cresce, é o que garante que cada post novo seja encontrado.",[12,1760,1761,1762,1764,1765,1768],{},"No Nuxt, o módulo ",[22,1763,24],{}," já traz o ",[22,1766,1767],{},"@nuxtjs\u002Fsitemap",", e no caso mais simples a configuração é literalmente vazia:",[60,1770,1772],{"className":62,"code":1771,"language":64,"meta":65,"style":65},"export default defineNuxtConfig({\n  sitemap: {},\n})\n",[22,1773,1774,1790,1800],{"__ignoreMap":65},[69,1775,1776,1780,1783,1786,1788],{"class":71,"line":72},[69,1777,1779],{"class":1778},"s3Er8","export",[69,1781,1782],{"class":1778}," default",[69,1784,1785],{"class":161}," defineNuxtConfig",[69,1787,164],{"class":87},[69,1789,167],{"class":91},[69,1791,1792,1795,1797],{"class":71,"line":117},[69,1793,1794],{"class":173},"  sitemap",[69,1796,177],{"class":91},[69,1798,1799],{"class":91}," {},\n",[69,1801,1802,1804],{"class":71,"line":151},[69,1803,331],{"class":91},[69,1805,334],{"class":87},[12,1807,1808,1809,1811,1812,1815],{},"Com isso, as rotas estáticas e as que estão no ",[22,1810,46],{}," já entram no sitemap automaticamente. O ponto de atenção são as rotas dinâmicas, como ",[22,1813,1814],{},"\u002Fblog\u002F[slug]",", que não existem como arquivo e por isso não são descobertas sozinhas. A solução é fornecer essas URLs por um endpoint que o sitemap consome:",[60,1817,1819],{"className":62,"code":1818,"language":64,"meta":65,"style":65},"\u002F\u002F server\u002Fapi\u002F__sitemap__\u002Furls.ts\nexport default defineSitemapEventHandler(async () => {\n  const posts = await queryCollection('blog').all()\n\n  return posts.map((post) => ({\n    loc: `\u002Fblog\u002F${post.slug}`,\n    lastmod: post.updated ?? post.date,\n  }))\n})\n",[22,1820,1821,1827,1849,1885,1889,1918,1942,1967,1974],{"__ignoreMap":65},[69,1822,1823],{"class":71,"line":72},[69,1824,1826],{"class":1825},"sutJx","\u002F\u002F server\u002Fapi\u002F__sitemap__\u002Furls.ts\n",[69,1828,1829,1831,1833,1836,1838,1841,1844,1847],{"class":71,"line":117},[69,1830,1779],{"class":1778},[69,1832,1782],{"class":1778},[69,1834,1835],{"class":161}," defineSitemapEventHandler",[69,1837,164],{"class":87},[69,1839,1840],{"class":75},"async",[69,1842,1843],{"class":91}," ()",[69,1845,1846],{"class":75}," =>",[69,1848,513],{"class":91},[69,1850,1851,1854,1857,1859,1862,1865,1867,1870,1873,1875,1877,1879,1882],{"class":71,"line":151},[69,1852,1853],{"class":75},"  const",[69,1855,1856],{"class":79}," posts",[69,1858,84],{"class":83},[69,1860,1861],{"class":1778}," await",[69,1863,1864],{"class":161}," queryCollection",[69,1866,164],{"class":173},[69,1868,1869],{"class":229},"'",[69,1871,1872],{"class":233},"blog",[69,1874,1869],{"class":229},[69,1876,836],{"class":173},[69,1878,92],{"class":91},[69,1880,1881],{"class":161},"all",[69,1883,1884],{"class":173},"()\n",[69,1886,1887],{"class":71,"line":158},[69,1888,155],{"emptyLinePlaceholder":154},[69,1890,1891,1894,1896,1898,1901,1903,1905,1909,1911,1913,1916],{"class":71,"line":170},[69,1892,1893],{"class":1778},"  return",[69,1895,1856],{"class":87},[69,1897,92],{"class":91},[69,1899,1900],{"class":161},"map",[69,1902,164],{"class":173},[69,1904,164],{"class":91},[69,1906,1908],{"class":1907},"sk1zL","post",[69,1910,836],{"class":91},[69,1912,1846],{"class":75},[69,1914,1915],{"class":173}," (",[69,1917,167],{"class":91},[69,1919,1920,1923,1925,1927,1930,1932,1934,1936,1938,1940],{"class":71,"line":185},[69,1921,1922],{"class":173},"    loc",[69,1924,177],{"class":91},[69,1926,230],{"class":229},[69,1928,1929],{"class":233},"\u002Fblog\u002F",[69,1931,237],{"class":229},[69,1933,1908],{"class":87},[69,1935,92],{"class":229},[69,1937,250],{"class":87},[69,1939,253],{"class":229},[69,1941,182],{"class":91},[69,1943,1944,1947,1949,1951,1953,1956,1959,1961,1963,1965],{"class":71,"line":197},[69,1945,1946],{"class":173},"    lastmod",[69,1948,177],{"class":91},[69,1950,88],{"class":87},[69,1952,92],{"class":91},[69,1954,1955],{"class":87},"updated",[69,1957,1958],{"class":83}," ??",[69,1960,88],{"class":87},[69,1962,92],{"class":91},[69,1964,966],{"class":87},[69,1966,182],{"class":91},[69,1968,1969,1971],{"class":71,"line":209},[69,1970,833],{"class":91},[69,1972,1973],{"class":173},"))\n",[69,1975,1976,1978],{"class":71,"line":221},[69,1977,331],{"class":91},[69,1979,334],{"class":87},[12,1981,1982,1983,1986],{},"O endpoint busca os posts na mesma fonte que alimenta o blog, seja o ",[22,1984,1985],{},"@nuxt\u002Fcontent",", um CMS headless ou uma API, e devolve as URLs com a data de última modificação. Assim o sitemap fica sempre em dia com o conteúdo real, sem lista manual para manter.",[12,1988,1989,1990,1992,1993,1995],{},"Juntando tudo, a regra de onde cada coisa mora é: o que vale para o site inteiro fica no ",[22,1991,477],{}," ou no ",[22,1994,698],{},", e o que muda de página para página fica na página.",[1997,1998,1999,2012],"table",{},[2000,2001,2002],"thead",{},[2003,2004,2005,2009],"tr",{},[2006,2007,2008],"th",{},"Configuração",[2006,2010,2011],{},"Onde mora",[2013,2014,2015,2028,2042,2053,2065,2077,2085,2098],"tbody",{},[2003,2016,2017,2024],{},[2018,2019,2020,2023],"td",{},[22,2021,2022],{},"site"," (url, name, description, locale)",[2018,2025,2026],{},[22,2027,477],{},[2003,2029,2030,2038],{},[2018,2031,2032,2034,2035],{},[22,2033,1450],{}," (bots de IA) + ",[22,2036,2037],{},"sitemap",[2018,2039,2040],{},[22,2041,477],{},[2003,2043,2044,2049],{},[2018,2045,2046,2048],{},[22,2047,481],{}," (1200x630, satori)",[2018,2050,2051],{},[22,2052,477],{},[2003,2054,2055,2061],{},[2018,2056,2057,2058,2060],{},"Schema ",[22,2059,687],{}," do autor",[2018,2062,2063],{},[22,2064,698],{},[2003,2066,2067,2074],{},[2018,2068,2069,2071,2072],{},[22,2070,53],{}," + ",[22,2073,351],{},[2018,2075,2076],{},"página",[2003,2078,2079,2083],{},[2018,2080,2081],{},[22,2082,470],{},[2018,2084,2076],{},[2003,2086,2087,2096],{},[2018,2088,2089,2091,2092,2091,2094],{},[22,2090,856],{}," \u002F ",[22,2093,1088],{},[22,2095,1260],{},[2018,2097,2076],{},[2003,2099,2100,2103],{},[2018,2101,2102],{},"Endpoint do sitemap dinâmico",[2018,2104,2105],{},[22,2106,2107],{},"server\u002Fapi\u002F__sitemap__\u002Furls.ts",[27,2109],{},[30,2111,2113],{"id":2112},"seo-hoje-é-escrever-para-três-leitores","SEO hoje é escrever para três leitores",[12,2115,2116,2117,2119,2120,2122,2123,2125],{},"A página não tem mais um público só. A mesma URL é lida pelo crawler do Google, pelo mecanismo que monta a resposta direta e pela IA que vai citá-la. A og:image cuida da pessoa que vê o link, o Schema.org cuida da máquina que interpreta o conteúdo, o ",[22,2118,1260],{}," transforma parte do texto em resposta pronta e o ",[22,2121,1440],{}," mais o ",[22,2124,1522],{}," decidem o que as IAs enxergam.",[12,2127,2128,2129,2131],{},"Algumas frentes valem como próximo passo. Domínio próprio pesa no E-E-A-T e no reconhecimento de entidade, um site em subdomínio de plataforma nunca soa tão sólido quanto um domínio dedicado. E o ",[22,2130,1260],{}," pode ir além dos posts, cobrindo dúvidas de serviço e de produto em qualquer página.",[12,2133,2134],{},"Nenhuma dessas três frentes é complicada isoladamente. O que muda é a mentalidade: parar de otimizar a página para um leitor e escrever para todos eles ao mesmo tempo, sabendo que cada um lê de um jeito.",[27,2136],{},[30,2138,2140],{"id":2139},"onde-testar","Onde testar",[12,2142,2143],{},"Nada disso vale sem validação, e dá para conferir tudo com ferramenta gratuita:",[2145,2146,2147,2159,2169,2179],"ul",{},[2148,2149,2150,2158],"li",{},[2151,2152,2153],"strong",{},[659,2154,2157],{"href":2155,"rel":2156},"https:\u002F\u002Fwww.opengraph.xyz\u002F",[663],"opengraph.xyz"," simula como a og:image e as meta tags aparecem no Facebook, LinkedIn, Twitter e outros, antes de compartilhar o link de verdade.",[2148,2160,2161,2168],{},[2151,2162,2163],{},[659,2164,2167],{"href":2165,"rel":2166},"https:\u002F\u002Fpagespeed.web.dev\u002F",[663],"PageSpeed Insights"," analisa performance, Core Web Vitals e SEO técnico, com um relatório separado para mobile e desktop, e já traz também uma verificação de GEO.",[2148,2170,2171,2178],{},[2151,2172,2173],{},[659,2174,2177],{"href":2175,"rel":2176},"https:\u002F\u002Fsearch.google.com\u002Fsearch-console\u002F",[663],"Google Search Console"," mostra como o Google enxerga o site: indexação, cobertura, erros de rastreamento e validação dos dados estruturados que aparecem como rich results.",[2148,2180,2181,2188],{},[2151,2182,2183],{},[659,2184,2187],{"href":2185,"rel":2186},"https:\u002F\u002Fautomarticles.com\u002Fferramentas\u002Fdiagnostico-de-seo-e-geo",[663],"Diagnóstico de SEO e GEO da Automarticles"," faz uma varredura das duas frentes juntas, incluindo os pontos de GEO que a maioria das ferramentas clássicas de SEO ainda não cobre.",[27,2190],{},[30,2192,2194],{"id":2193},"leituras-relacionadas","Leituras relacionadas",[2145,2196,2197,2204,2211],{},[2148,2198,2199],{},[659,2200,2203],{"href":2201,"rel":2202},"https:\u002F\u002Fwww.larisantos.com.br\u002Fblog\u002Fnuxt-wordpress-headless-nuxt",[663],"WordPress Headless com Nuxt: quando faz sentido e como estruturar",[2148,2205,2206],{},[659,2207,2210],{"href":2208,"rel":2209},"https:\u002F\u002Fwww.larisantos.com.br\u002Fblog\u002Fnuxt-saas-multitenant",[663],"Como estruturei a arquitetura inicial de um SaaS multitenant com Nuxt 3 e Supabase",[2148,2212,2213],{},[659,2214,2217],{"href":2215,"rel":2216},"https:\u002F\u002Fwww.larisantos.com.br\u002Fblog\u002Fprincipio-solid",[663],"SOLID: 5 Princípios para Escrever Código Limpo e Escalável",[2219,2220,2221],"style",{},"html pre.shiki code .sFsEu, html code.shiki .sFsEu{--shiki-light:#9C3EDA;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .sVPC0, html code.shiki .sVPC0{--shiki-light:#90A4AE;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .sFfmW, html code.shiki .sFfmW{--shiki-light:#39ADB5;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .sMo7A, html code.shiki .sMo7A{--shiki-light:#90A4AE;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .sG-J9, html code.shiki .sG-J9{--shiki-light:#39ADB5;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .sK_r7, html code.shiki .sK_r7{--shiki-light:#6182B8;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .sdv8B, html code.shiki .sdv8B{--shiki-light:#E53935;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .sF_wb, html code.shiki .sF_wb{--shiki-light:#39ADB5;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html pre.shiki code .s0vBq, html code.shiki .s0vBq{--shiki-light:#91B859;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}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 .swHuM, html code.shiki .swHuM{--shiki-light:#E53935;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html pre.shiki code .sSElE, html code.shiki .sSElE{--shiki-light:#39ADB5;--shiki-light-font-weight:inherit;--shiki-default:#79B8FF;--shiki-default-font-weight:bold;--shiki-dark:#79B8FF;--shiki-dark-font-weight:bold}html pre.shiki code .s4BmV, html code.shiki .s4BmV{--shiki-light:#E2931D;--shiki-light-font-weight:inherit;--shiki-default:#79B8FF;--shiki-default-font-weight:bold;--shiki-dark:#79B8FF;--shiki-dark-font-weight:bold}html pre.shiki code .s63Gb, html code.shiki .s63Gb{--shiki-light:#FF5370;--shiki-light-font-style:italic;--shiki-default:#85E89D;--shiki-default-font-style:inherit;--shiki-dark:#85E89D;--shiki-dark-font-style:inherit}html pre.shiki code .sJeIW, html code.shiki .sJeIW{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#85E89D;--shiki-default-font-style:inherit;--shiki-dark:#85E89D;--shiki-dark-font-style:inherit}html pre.shiki code .sUVGp, html code.shiki .sUVGp{--shiki-light:#39ADB5;--shiki-default:#FFAB70;--shiki-dark:#FFAB70}html pre.shiki code .shnMK, html code.shiki .shnMK{--shiki-light:#39ADB5;--shiki-light-font-weight:bold;--shiki-default:#E1E4E8;--shiki-default-font-weight:bold;--shiki-dark:#E1E4E8;--shiki-dark-font-weight:bold}html pre.shiki code .smV4n, html code.shiki .smV4n{--shiki-light:#E53935;--shiki-light-font-weight:bold;--shiki-default:#E1E4E8;--shiki-default-font-weight:bold;--shiki-dark:#E1E4E8;--shiki-dark-font-weight:bold}html pre.shiki code .sM8Rc, html code.shiki .sM8Rc{--shiki-light:#91B859;--shiki-light-text-decoration:inherit;--shiki-default:#DBEDFF;--shiki-default-text-decoration:underline;--shiki-dark:#DBEDFF;--shiki-dark-text-decoration:underline}html pre.shiki code .sH2AH, html code.shiki .sH2AH{--shiki-light:#E53935;--shiki-light-text-decoration:underline;--shiki-default:#E1E4E8;--shiki-default-text-decoration:underline;--shiki-dark:#E1E4E8;--shiki-dark-text-decoration:underline}html pre.shiki code .s3Er8, html code.shiki .s3Er8{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#F97583;--shiki-default-font-style:inherit;--shiki-dark:#F97583;--shiki-dark-font-style:inherit}html pre.shiki code .sutJx, html code.shiki .sutJx{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#6A737D;--shiki-default-font-style:inherit;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit}html pre.shiki code .sk1zL, html code.shiki .sk1zL{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#FFAB70;--shiki-default-font-style:inherit;--shiki-dark:#FFAB70;--shiki-dark-font-style:inherit}",{"title":65,"searchDepth":117,"depth":117,"links":2223},[2224,2225,2226,2227,2228,2229,2230,2231,2232],{"id":32,"depth":117,"text":33},{"id":453,"depth":117,"text":454},{"id":670,"depth":117,"text":671},{"id":1250,"depth":117,"text":1251},{"id":1433,"depth":117,"text":1434},{"id":1747,"depth":117,"text":1748},{"id":2112,"depth":117,"text":2113},{"id":2139,"depth":117,"text":2140},{"id":2193,"depth":117,"text":2194},"2026-07-08T18:12:00-03:00","Um guia prático de como estruturar o SEO de um site Nuxt para três leitores diferentes: og:image dinâmica com Satori, Schema.org com useSchemaOrg, e GEO com robots.txt e llms.txt para os bots de IA.",[2236,2239,2242,2245],{"question":2237,"answer":2238},"Qual a diferença entre SEO, GEO e AEO?","SEO é a otimização clássica para buscadores como o Google indexarem e ranquearem a página. AEO (Answer Engine Optimization) prepara o conteúdo para virar resposta direta, aquele bloco que aparece no topo da busca ou no AI Overview. GEO (Generative Engine Optimization) é a visibilidade dentro de respostas de IAs generativas como ChatGPT e Perplexity, que citam fontes ao responder. As três frentes se sobrepõem, mas cada uma resolve um tipo de leitura diferente da mesma página.",{"question":2240,"answer":2241},"Como gerar uma og:image dinâmica por página no Nuxt?","Com o módulo @nuxtjs\u002Fseo. Qualquer componente Vue criado em components\u002FOgImage\u002F vira um template disponível, e o defineOgImageComponent na página escolhe o template e passa os dados. O Satori renderiza esse componente como imagem 1200x630 no servidor, então cada post gera um preview próprio com título, descrição e tags reais sem configuração manual.",{"question":2243,"answer":2244},"O robots.txt precisa liberar os bots de IA separadamente?","Sim. Crawlers de IA usam user-agents próprios, como GPTBot, ClaudeBot, PerplexityBot e Google-Extended, e alguns respeitam o robots.txt para decidir se leem seu conteúdo. Se você quer aparecer em respostas de IA, precisa liberar esses agentes explicitamente, porque bloquear ou omitir pode deixar seu site de fora do treinamento e da citação.",{"question":2246,"answer":2247},"O que é o llms.txt e onde ele fica?","É um arquivo de texto na raiz do site, em \u002Fllms.txt, que descreve em linguagem natural o que o site é, quem o mantém e como o conteúdo está organizado. Serve para orientar modelos de linguagem sobre o contexto do site, como um resumo curado para IA. Não é um padrão obrigatório ainda, mas é barato de manter e ajuda no reconhecimento de entidade.","\u002Fimages\u002Fblog\u002Fseo\u002Fseo-logoimage.png",{},"\u002Fblog\u002Fseo-geo-aeo-nuxt",{"title":5,"description":2234},"Como estruturar SEO, GEO e AEO num site Nuxt: og:image dinâmica, Schema.org com useSchemaOrg e llms.txt para os crawlers de IA.","SEO, GEO e AEO na prática com Nuxt","blog\u002Fseo-geo-aeo-nuxt",[2256,2257,2258,2259,2260,2261,2262,2263],"nuxt","seo","geo","aeo","schema-org","og-image","llms-txt","vue","oMnnp53yOqOL4JA4uW8FJJI-3AjLBJyuXds170k5gc8",1783648795752]