🌈greg✨

fazendo um blog com Nextjs, MDX, Tailwind

hj implementei um feed rss aqui entao vou falar um pouco sobre como fiz esse blog,
se quiser o feed rss Γ© gregs.vercel.app/feed.xml

to usando Nextjs que Γ© um framework pra React, os posts sΓ£o em mdx que Γ© tipo markdown mas aceita colocar componentes react no meio,
e tailwind uma lib de css utils, pra fazer os style rapidao

os posts sao renderizados no server e servidos staticamente (beem facil fazer com nextjs), faΓ§o deploy com vercel, por ser statico fica td na edge em cache nunca precisa bater num server

o codigo Γ© bem simples, a arquitetura ta assim agr
next usa a pasta pages como as rotas do app, rotas com [] sao dinamicas

β”œβ”€β”€ public
β”‚   β”œβ”€β”€ favicon.png
β”‚   └── assets // largo imagem e etc
β”œβ”€β”€ pages
β”‚   β”œβ”€β”€ _app.tsx
β”‚   └── [slug].tsx // rota dinamica, pagina dos posts em si
β”‚   └── index.tsx // tem uma lista dos ultimos posts
β”‚   └── 404.tsx // se tentar acessar algo que n existe, meti uma mensagem personalizada
β”œβ”€β”€ posts
β”‚   β”œβ”€β”€ slug_do_post.mdx
β”œβ”€β”€ lib
β”‚   β”œβ”€β”€ post.ts
β”‚   └── rss.ts
β”œβ”€β”€ components
β”‚   └── ...
β”œβ”€β”€ tailwind.config.js

o codigo ta no github aqui

pagina principal

se exportar uma funΓ§Γ£o getStaticProps next vai prΓ© renderizar a pagina no build,
ou seja ja transformar em html pronta, dependendo do que fizer nem vai js pro browser

// index.tsx

export const getStaticProps: GetStaticProps<{ allPosts: Post[] }> = async (ctx) => {
  const allPosts = getAllPosts(['title', 'date', 'slug'])
  const allPostsSorted = allPosts.sort((a, b) =>
    new Date(a.date).getTime() > new Date(b.date).getTime() ? -1 : 1,
  )

  // deixei aqui, mas poderia colocar no script de build no packge.json
  // e n tenho um bom motivo pra isso
  generateRSSFeed()

  return {
    props: { allPosts: allPostsSorted },
  }
}

// next usa o export default como o componente que vai renderizar na rota, essa Γ© index ou seja '/'
export default function All({ allPosts }: { allPosts: Post[] }) {
  ...

pagina do post

pra prΓ© renderizar paginas com rotas dinamicas se exporta um getStaticPaths, sΓ³ retornar os endereΓ§os que quer

export async function getStaticPaths() {
  return {
    paths: [{ params: { slug: 'slug do post ha ser prΓ© renderizado' } }],
  }
}

pra renderizar mdx to usando next-mdx-remote
a lib exporta duas funΓ§Γ΅es renderToString que transforma uma string mdx, tipo # oi em <h1>oi</> ,
e hydrate que 'hidrata' esse html no client se precisar, com os componentes e tal

// [slug].tsx

export async function getStaticPaths() {
  const posts = getAllPosts(['slug']) // aqui eu pego sΓ³ os slug dos posts que Γ© o que precisa pra rota
  return {
    paths: posts.map((post) => ({ params: { slug: post.slug } })),
    fallback: false,
  }
}

export async function getStaticProps({ params }) {
  const post = getPostBySlug(params.slug, ['title', 'date', 'slug', 'image', 'content']) // aqui pego tds as info do post dai
  const content = await renderToString(post.content, { components })
  return {
    props: {
      ...post,
      content,
    },
  }
}

export default function Post({ title, date, slug, image, content }) {
  ...
  <div className="prose max-w-none mt-6 md:mt-10 pb-8">{hydrate(content)}</div>
  ...

como pegar os posts

pra ter coisas mais meta nos posts (tipo a data que foi escrito e tal), to usando a lib gray-matter, que deixa fazer coisas assim

---
  date: '05/02/2021'
  title: 'blabla'
---

## titulo

... resto do post aqui

ela extrai date e title separado do conteudo post em si

como os posts estao em uma pasta (posts), eu leio os arquivos direto de la, assim nao preciso atualizar nada a mais alem do arquivo do post em si

da pra trocar esses readFile por um fetch pro CMS e gg funciona igual

const fullPath = join(postsDirectory, `${slug}.mdx`)
const fileContents = fs.readFileSync(fullPath, 'utf8')
const { data, content } = matter(fileContents)

sla acho que Γ© isso ai, nao sei mais o que explicar, se quiser fazer um blog pode clonar meu repo e mudar como quiser