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.jso 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