{"version":"https://jsonfeed.org/version/1","title":"Luís Otávio","home_page_url":"https://luisfadini.com","feed_url":"https://luisfadini.com/feed.json","description":"Posts sobre tecnologia, programação e projetos pessoais.","language":"pt-BR","items":[{"id":"https://luisfadini.com/blog/essencial-de-git","url":"https://luisfadini.com/blog/essencial-de-git","title":"O essencial de Git","summary":"O que eu uso e o que você, como iniciante ou não em programação, precisa saber para trabalhar com Git no dia a dia.","date_published":"2026-02-07T19:05:00.000Z","date_modified":"2026-02-05T01:20:00.000Z","tags":["desenvolvimento","git"],"content_text":"Para começar, já aviso que este não é um artigo tão técnico sobre Git. Se quiser algo mais aprofundado, recomendo o vídeo do Fabio Akita, [Entendendo GIT | (não é um tutorial!)](https://youtu.be/6Czd1Yetaac).\r\nEste é um tutorial relativamente simples, mostrando as funções essenciais que qualquer desenvolvedor que use Git precisa saber, não importa o nível.\r\n\r\n---\r\n\r\n## O básico de como o Git funciona\r\n\r\nO Git trabalha basicamente com três áreas:\r\n\r\n- Working directory: seus arquivos normais no projeto\r\n- Staging area: área de preparação\r\n- Repositório (.git): onde ficam os commits e o histórico\r\n\r\nO fluxo normal é simples:\r\n\r\n1. Você modifica arquivos\r\n2. Usa `git add` para enviar alterações para a staging area\r\n3. Usa `git commit` para registrar essas mudanças no histórico\r\n\r\nEntendendo isso, o restante dos comandos fica muito mais simples.\r\n\r\n---\r\n\r\n## Instalação\r\n\r\nPara instalar o Git, utilize o instalador no site oficial, [git-scm.com](https://git-scm.com/), ou como eu prefiro fazer, usar um gerenciador de pacotes.\r\n\r\nNas versões mais novas do Windows temos o [winget](https://github.com/microsoft/winget-cli), que é um gerenciador de pacotes oficial do Windows.  \r\nPara instalar o Git com ele basta usar o comando: `winget install --id Git.Git -e --source winget`\r\n\r\nNo macOS utilize o [homebrew](https://brew.sh): `brew install git`\r\n\r\nE no Linux, utilize o gerenciador de pacotes da sua distro favorita.\r\nNo meu caso utilizo Arch Linux e um AUR helper chamado [`yay`](https://github.com/Jguer/yay), então instalo com `yay -S git`\r\n\r\n---\r\n\r\n## Comandos básicos\r\n\r\n### git init\r\n\r\n`git init` é onde começa a \"magia\" do Git. Ele inicia um repositório no diretório atual, criando a pasta `.git`.\r\n\r\nPor padrão essa pasta não aparece em exploradores de arquivos, para visualizá-la selecione mostrar arquivos ocultos.\r\n\r\nNão é recomendado modificar nada dentro dessa pasta. O Git gerencia dela para você.\r\n\r\n### git add\r\n\r\n`git add` adiciona as alterações à área de preparação (staging area), indicando quais mudanças farão parte do próximo commit. Esse comando serve basicamente para indicar quais arquivos serão incluídos no seu [git commit](#git-commit).\r\n\r\nGeralmente você vai querer adicionar todos os arquivos modificados de uma vez, para isso utilize `git add .`, caso queira adicionar arquivo por arquivo, para por exemplo dividir em vários commits organizados utilize `git add `, para mais informações use o \r\n\r\n### git diff\r\n\r\n`git diff` mostra as diferenças entre arquivos modificados e o último commit.\r\n\r\n`git diff` mostra mudanças ainda não adicionadas à staging area, com a flag `--staged` mostra o que já está preparado para commit. É bem útil para evitar commits errados.\r\n\r\n### git commit\r\n\r\n`git commit` adiciona os arquivos que estão na sua área de preparação para o `.git`, assim criando uma versão histórica do seu código e podendo voltar para ela quando quiser, cada commit possui um hash sha1 associado a ele, podendo ser referenciado por seu hash completo ou por sua versão curta das 7 letras iniciais do hash.\r\n\r\nO uso mais básico desse comando vai ser com uma curta mensagem escrita descrevendo as mudanças ocorridas, recomendo utilizar uma convenção de nomenclaturas, por exemplo o [Conventional Commits](https://www.conventionalcommits.org/pt-br/v1.0.0/). Para adicionar a mensagem do commit, use: `git commit -m \"sua mensagem aqui\"`.\r\n\r\n### git log\r\n\r\n`git log` mostra o histórico de commits. Com a flag `--oneline` ele mostrará de forma mais resumida.\r\n\r\n### git status\r\n\r\n`git status` mostra os arquivos modificados e quais estão na área de preparação do Git para serem incluídos no próximo commit.\r\n\r\n### git branch\r\n\r\n`git branch` é utilizado para gerenciar branches (ramificações) no Git. Branches permitem que você desenvolva funcionalidades, corrija bugs ou teste ideias sem afetar a linha principal do projeto.\r\n\r\nPara listar as branches locais, use o comando `git branch`, além de mostrar as branches ele iniciará com um `*` a branch ativa.\r\nAssim como para commit existe o Conventional Commits, para branches existe o [Conventional Branches](https://conventional-branch.github.io/) e para criar uma nova branch use `git branch nome-da-branch`\r\n\r\n### git checkout\r\n\r\n`git checkout` é usado para trocar entre branches, navegar para commits antigos ou criar uma nova branch.\r\n\r\nPara trocar para uma branch use `git checkout nome-da-branch`.\r\n\r\nPara visualizar um commit específico usando o hash curto `git checkout hash`, detalhe que ao fazer isso você entra em estado de _detached HEAD_, ou seja, não estará em nenhuma branch.\r\n\r\nPara criar uma nova branch a partir da atual e já mudar para ela use `git checkout -b nome-da-branch`.\r\n\r\n### git switch\r\n\r\n`git switch` é bem similar ao [`git checkout`](#git-checkout), mas só funciona em versões mais novas do Git, ele funciona especificamente para trocar entre branches e criar.\r\n\r\nPara trocar entre branches use `git switch nome-da-branch` e para criar, trocando de branch use `git switch -c nome-da-branch`.\r\n\r\n### git clone\r\n\r\n`git clone` serve para copiar um repositório remoto para sua máquina, muito útil para quando você vai contribuir com um projeto já existente.\r\n\r\nQuando você executa `git clone https://github.com/usuario/repositorio`, o Git vai criar uma pasta com o nome do repositório, baixar todos os arquivos, baixar todo o histórico de commits e configurar o repositório remoto como `origin`, ou seja, você passa a ter uma cópia completa do projeto, incluindo histórico e branches.\r\n\r\nSe quiser clonar com outro nome de pasta, use `git clone https://github.com/usuario/repositorio meu-projeto`\r\n\r\nSe quiser apenas a versão mais recente, sem todo o histórico, chamado de shallow clone, use `git clone --depth=1 https://github.com/usuario/repositorio`\r\n\r\n### git pull\r\n\r\n`git pull` atualiza seu repositório local com as mudanças do repositório remoto. Seu uso mais comum é `git pull`, que já funciona e resolve a maioria dos casos. Mas de forma mais explicita, pode usar `git pull origin main`, que basicamente significa \"Traga as atualizações da branch `main` do repositório remoto `origin`\".\r\n\r\nRecomendo sempre rodar `git pull` antes de começar a trabalhar, especialmente em projetos com mais pessoas, pois se houver conflitos, o Git interromperá o processo de merge e pedirá que você resolva manualmente antes de concluir.\r\n\r\n### git push\r\n\r\n`git push` envia seus commits locais para o repositório remoto. O fluxo normal de uso desse comando é [`git add`](#git-add), [`git commit`](#git-commit) e então `git push`.\r\n\r\nNo seu uso básico, precisa apenas rodar `git push`, funcionando quando sua branch já está vinculada a uma branch remota.\r\n\r\nMas caso for a primeira vez enviando uma branch nova você precisa adicionar mais coisas no comando `git push -u origin nome-da-branch`, a flag `-u` serve para vincular sua branch local a uma branch remota. Depois disso pode usar o fluxo normal de `git push`.\r\n\r\nÉ importante lembrar que enquanto você não rodar `git push`, seus commits existem apenas na sua máquina.\r\n\r\n---\r\n\r\n## Arquivos de configuração\r\n\r\n### .gitignore\r\n\r\nO arquivo `.gitignore` é utilizado para dizer ao Git quais arquivos ou pastas devem ser ignorados pelo Git e não serem adicionados ao repositório, isso é extremamente importante porque nem tudo em um projeto deve ser versionado, por exemplo:\r\n\r\n- Dependências instaladas automaticamente\r\n- Arquivos temporários\r\n- Arquivos de sistema\r\n- Arquivos sensíveis\r\n- Arquivos de build\r\n- Logs\r\n\r\nO `.gitignore` trabalha com padrões:\r\n\r\n- `arquivo.txt` vai ignorar um arquivo específico\r\n- `*.log` vai ignorar todos os arquivos `.log`\r\n- `pasta/` vai ignorar uma pasta inteira\r\n- `!arquivo.txt` vai remover da regra de ignorar\r\n\r\nPor exemplo, se eu quero ignorar todos os `.logs`, mas manter o `important.log`, o `.gitignore` fica assim:\r\n\r\n```gitignore\n*.log\r\n!important.log\r\n```\r\n\r\nÉ importante falar que o `.gitignore` não afeta arquivos que já estão sendo rastreados pelo Git. Para remover do rastreamento use `git rm --cached nome-do-arquivo`, mas tem um detalhe importante que o arquivo irá continuar nos commits antigos.\r\n\r\n### .gitattributes\r\n\r\nO `.gitattributes` é um arquivo usado para definir como o Git deve tratar arquivos que já fazem parte do repositório.\r\n\r\nUm dos usos é padronizar quebras de linha, já que sistemas Windows e Linux/macOS funcionam de forma diferente, é comum surgirem conflitos por causa das diferenças de quebra de linha. Para evitar esse problema:\r\n\r\n```properties\n* text=auto\r\n```\r\n\r\nIsso faz com que o Git normalize automaticamente os arquivos de texto. Também é possível forçar um padrão específico:\r\n\r\n```properties\n*.js text eol=lf\r\n```\r\n\r\nO `.gitattributes` também pode ser usado para definir arquivos binários como imagens e PDFs, que não devem ser tratados como texto, isso evita que o Git tente gerar diff ou fazer merge como se fossem arquivos de código.\r\n\r\n```properties\n*.png binary\r\n*.jpg binary\r\n```\r\n\r\nAlém disso o `.gitattributes` possui mais usos a depender da plataforma, por exemplo ignorar uma linguagem de programação de ser contada como parte do repositório ou coisas assim, nesses casos, consulte a documentação do [GitHub](https://docs.github.com/en/repositories/working-with-files/managing-files/customizing-how-changed-files-appear-on-github), [Gitlab](https://docs.gitlab.com/user/project/repository/files/git_attributes/) ou até do próprio [Git](https://git-scm.com/docs/gitattributes).\r\n\r\n---\r\n\r\n## Conclusão\r\n\r\nO Git é muito completo e poderoso, mas o uso básico é relativamente simples.\r\n\r\nComo qualquer ferramenta, exige prática para que você se acostume com seus comandos e conceitos. Este post é apenas um overview. Há muito mais para se aprofundar, como merge, rebase, stash, cherry-pick e diferentes workflows de equipe.\r\n\r\nSe ainda acha o Git confuso, recomendo baixar e criar um repositório só para ir testando e nada melhor para pegar o jeito de usar o Git do que você usar em um projeto na prática, algo simples mesmo, uma API ou um pequeno site.\r\n\r\nAlém disso há várias formas de usar Git, eu particularmente costumo usar pela própria interface de [controle de versão do Visual Studio Code](https://code.visualstudio.com/docs/sourcecontrol/overview), mas existe outras interfaces, [LazyGit](https://github.com/jesseduffield/lazygit), [GitHub Desktop](https://docs.github.com/en/desktop/overview/about-github-desktop) e até mesmo uma do Git com o comando `git gui`."},{"id":"https://luisfadini.com/blog/atualizando-bios-linux","url":"https://luisfadini.com/blog/atualizando-bios-linux","title":"Atualizando BIOS com Linux","summary":"Como fiz para atualizar a BIOS do Acer Nitro V15 sem precisar instalar Windows","date_published":"2026-01-26T01:04:00.000Z","date_modified":"2026-01-26T01:04:00.000Z","tags":["linux","bios","acer","hiren's boot"],"content_text":"Como fiz para atualizar a BIOS do Acer Nitro V15 sem a necessidade de instalar o Windows, utilizando apenas Linux. Mas você pode se perguntar: vale um post no blog só pra isso? Bom, acredito que sim, por ser um notebook popular e por eu não ter encontrado essa solução em nenhum lugar anteriormente.\n\n---\n\n## Contexto\n\nPor que atualizar a BIOS? Bom, em algumas versões da BIOS do Acer Nitro V15, a memória reservada para hardware é de quase 2,5 GB, o que, para um notebook com 8 GB de RAM, é muita coisa. Nas versões mais recentes, a memória reservada para hardware é reduzida para aproximadamente 0,5 GB, o que para mim faria uma grande diferença, ainda mais considerando o preço atual das memórias.\n\nA Acer, apesar de ser uma marca enorme, entrega atualizações de BIOS exclusivamente para usuários de Windows, o que, para mim, não é algo que uma fabricante que se preze faria, ainda mais considerando que esse notebook é vendido com Linux de fábrica (mesmo sendo uma distro bem ruim, ainda assim é Linux).\n\nAlém disso, eu já uso Linux no dia a dia e não queria perder meu tempo instalando Windows só para atualizar a BIOS. Esse tipo de atualização deveria ser algo simples: um `.bin` (ou similar) em um pendrive, lido diretamente pela própria UEFI/BIOS, assim como acontece na maioria (ou quase todos) dos desktops.\n\nAlgumas soluções que passaram pela minha cabeça foram:\n\n- Pegar o SSD de um familiar emprestado que já tivesse Windows\n- Usar uma máquina virtual para tentar extrair um `.bin`\n- Deixar a BIOS desatualizada e seguir a vida\n\nE bom, não foi nenhuma dessas opções que eu usei.\n\n---\n\n## Hiren's Boot CD\n\nEm um post meio perdido no Reddit, no subreddit do Acer Nitro, um usuário comentou que também utilizava Linux e tinha conseguido atualizar a BIOS.  \nPerguntei como ele tinha feito, e a resposta foi simples: Hiren's Boot CD.\n\nNunca tinha usado o Hiren’s Boot até então, mas basicamente ele é um Windows PE. Bom, o que é Windows PE? De forma bem resumida, é um Windows portátil, parecido com um LiveCD de Linux. Ele roda direto do pendrive, consegue executar praticamente qualquer `.exe` e não precisa ser instalado no disco. O Hiren’s Boot nada mais é do que um Windows PE com vários utilitários extras já inclusos.\n\n---\n\n## Como fazer?\n\n**PROSSIGA COM CUIDADO. NÃO ME RESPONSABILIZO POR PERDAS DE DADOS. CASO UTILIZE LUKS, DESATIVE O fTPM POR SEGURANÇA.**\n\nPrimeiro, você precisa ter um pendrive de uns 8 GB. Em seguida, baixe o Hiren's Boot CD do site oficial:  \n[https://www.hirensbootcd.org/](https://www.hirensbootcd.org/)\n\nCom o pendrive em mãos e a ISO baixada, crie um pendrive bootável. Se o PC que estiver usando para criar esse pendrive for Windows, você pode usar ferramentas como o tradicional Rufus. No Linux, pode usar o comando `dd` (considero arriscado). Caso use Mac, não sei que ferramenta utilizar.\n\nMas, se quiser algo melhor, tanto para Windows quanto para Linux, use o [Ventoy](https://www.ventoy.net/en/index.html). Ele é perfeito. Uso em um pendrive de 32 GB cheio de ISOs de vários sistemas, entre eles: Mint, Ubuntu, Arch, Debian, Windows 10, Windows 11 e agora o Hiren's Boot.\n\nCom o pendrive pronto, basta inseri-lo no notebook (caso ainda não esteja), acessar a BIOS e ajustar a ordem de boot. Não tenho prints desse processo, mas uma busca rápida no Google resolve fácil. Depois disso, é só dar boot no Hiren’s Boot, abrir o navegador, acessar o site da Acer, baixar o updater da BIOS do notebook e executar o `.exe`. O notebook vai reiniciar, atualizar a BIOS e pronto.\n\n---\n\n## Meu GRUB sumiu\n\nDepois da atualização, meu GRUB simplesmente desapareceu. Isso acontece porque muitas BIOS assumem que só existe Windows e acabam ignorando completamente qualquer entrada de boot que não seja dele.\n\nPara resolver, dei boot no Arch Linux pelo Ventoy, montei as partições do SSD, entrei em um `chroot` e reinstalei o GRUB no diretório `/boot/EFI/`. Após reiniciar, o GRUB voltou a aparecer normalmente. Não entrarei em mais detalhes porque isso depende de várias coisas, por exemplo, se você usa criptografia, entre outros fatores."},{"id":"https://luisfadini.com/blog/homelab-2025","url":"https://luisfadini.com/blog/homelab-2025","title":"Revendo meu homelab de 2025 e melhorias pra 2026","summary":"Uma retrospectiva do meu homelab em 2025, o que funcionou, o que ficou de lado e mudanças para 2026.","date_published":"2026-01-06T01:01:00.000Z","date_modified":"2026-01-06T01:01:00.000Z","tags":["homelab","infraestrutura","proxmox","terraform","docker"],"content_text":"Agora que 2026 começou, achei que fazia sentido olhar pra trás e revisar como foi o meu homelab em 2025, falar o que realmente mudou, o que acabou ficando de lado e o futuro dele.\n\nNão foi um ano de grandes upgrades, mas serviu pra entender melhor como eu uso o ambiente no dia a dia, e isso acabou pesando bastante nos planos pra 2026.\n\n---\n\n## Software\n\nNo começo de 2025 instalei algumas aplicações novas, entre elas o [Actual Budget](https://github.com/actualbudget/actual). A ideia é muito boa, ainda mais por ser open-source, mas na prática acabei usando pouco. Esse tipo de ferramenta só funciona quando você mantém uma rotina bem rígida de registrar tudo, e no meu caso isso acabou virando mais atrito do que benefício, ainda mais considerando que eu já tinha um controle bem grande dos meus gastos.\n\nO que senti falta ali foi alguma integração com bancos, algo via Open Finance, por exemplo. Sem isso, o app até é bom, mas acaba ficando esquecido depois de um tempo.\n\nOutra adição foi o [Vaultwarden](https://github.com/dani-garcia/vaultwarden) rodando na VM de TrueNAS. Esse sim entrou de vez na rotina. Ele resolveu um problema real que eu tinha de gerenciar senhas entre navegadores e dispositivos diferentes. No desktop uso Google Chrome, no notebook uso o [Zen Browser](https://github.com/zen-browser/desktop) e no celular também Chrome, o que seria difícil sincronizar se não fosse o Vaultwarden.\n\nMesmo quando o servidor está desligado, consigo acessar as senhas normalmente, já que os clientes mantêm as credenciais localmente após a última conexão com o servidor.\n\nUm ponto que ficou pendente em 2025 foi a forma como faço updates nos containers Docker que rodam dentro de um LXC no Proxmox. Eu usava o [Watchtower](https://github.com/containrrr/watchtower/) pra automatizar isso, mas com o [projeto abandonado](https://github.com/containrrr/watchtower/discussions/2135), ficou claro que essa abordagem não é totalmente sustentável. Agora devo assumir o controle e fazer updates manuais, mesmo sendo mais trabalhoso, mas garante mais previsibilidade e estabilidade.\n\n---\n\n## Hardware\n\nEm termos de hardware, 2025 foi bem parado. O setup continuou basicamente o mesmo: apenas um servidor, roteador e a impressora 3D.\n\nO único upgrade relevante foi no servidor, que passou de 12 GB pra 24 GB de RAM. Antes ele rodava com 4 + 8 GB e agora está com 16 + 8 GB. Não é o cenário ideal, já que módulos diferentes impedem XMP, mas foi o melhor custo-benefício no momento, já que esse módulo de 16GB retirei do meu desktop, e sendo sincero, é um servidor, não preciso de XMP, preciso de estabilidade.\n\nApesar disso, chega a ser meio hipócrita falar em estabilidade quando esse servidor não tem backup adequado e ficou desligado por quase 3 meses. O TrueNAS roda com apenas um HD de 1 TB e o Proxmox com um único SSD de 512 GB. O mínimo ideal seria ter pelo menos redundância local, como um mirror em ZFS, algo que ficou claramente como dívida técnica.\n\n---\n\n## Mudanças para 2026\n\nAgora em 2026, as coisas começaram a andar um pouco mais rápido. Logo no início do ano comprei um roteador novo, um Acer Predator Connect W6x. Ele tem Wi-Fi 6, uma porta de 2.5 Gbps e quatro portas de 1 Gbps. Wi-Fi 6 em si não muda muita coisa pra mim, mas a porta de 2.5 Gbps abre mais espaço pra brincar com a rede interna.\n\nA ideia é instalar [OpenWRT](https://openwrt.org/) assim que ele chegar. Não parece ser um modelo muito comum rodando OpenWRT, até por ainda ser [snapshot](https://openwrt.org/toh/acer/predator_connect_w6x), então provavelmente vale um post separado pra documentar o processo.\n\nOutra mudança importante foi adicionar uma VPS [e2-micro no Google Cloud](https://docs.cloud.google.com/free/docs/free-cloud-features#compute), toda gerenciada via [OpenTofu](https://opentofu.org/), um fork open-source do [Terraform](https://developer.hashicorp.com/terraform). Isso acabou virando um gatilho pra repensar o resto do homelab, já que dá pra versionar e recriar uma VPS inteira, por que não fazer algo isso localmente no OpenWRT e no Proxmox?\n\nOnde o OpenTofu não fizer muito sentido, por exemplo no [SBC](https://github.com/bigtreetech/BTT-Pi) da impressora 3D, a ideia é usar [Ansible](https://ansible.com/) pra manter tudo minimamente padronizado.\n\nTambém estou projetando um mini rack usando perfis de alumínio 2020. A ideia é ser algo simples e barato, mas que ajude a organizar melhor o roteador e alguns projetos futuros. Hoje fica meio espalhado, até funciona.\n\nPra fechar, pretendo pegar um HBA da LSI pelo eBay pra melhorar o setup do TrueNAS e poder adicionar mais HDs da forma correta, passando o dispositivo PCIe inteiro pra VM em vez de discos individuais. Também quero, dependendo do orçamento ~~e do preço das memórias~~, adicionar um segundo SSD pro Proxmox rodar em mirror, reduzindo a chance de perder os LXCs e VMs caso um SSD falhe.\n\nPor fim, a ideia é criar um repositório no GitHub com todas as configs do homelab. Além de servir como histórico e documentação, pode ser usado para analisar, se inspirar e até reaproveitar ideias em outros ambientes."},{"id":"https://luisfadini.com/blog/desenvolvendo-site-pessoal","url":"https://luisfadini.com/blog/desenvolvendo-site-pessoal","title":"Desenvolvendo meu site pessoal com Svelte e Tailwind","summary":"Um post explorando um pouco de como construir esse meu site pessoal utilizando uma techstack moderna de Svelte e Tailwind","date_published":"2025-11-15T18:55:00.000Z","date_modified":"2026-01-01T05:45:00.000Z","tags":["svelte","tailwind","markdown","desenvolvimento","webdev","docker"],"content_text":"Bom, esse é oficialmente o primeiro post do blog. Talvez não seja a melhor escrita do mundo, mas é um começo. Aqui vou falar um pouco sobre como desenvolvi esse site, as decisões técnicas que tomei e, ao longo do caminho, aproveitar para testar algumas funcionalidades do markdown e ver se tudo está renderizando corretamente.\r\n\r\n```js\nconsole.log('Olá mundo!');\r\n```\r\n\r\n---\r\n\r\n## Escolha da techstack\r\n\r\nAcredito que o famoso `Olá mundo!` seja sempre o primeiro passo. Para este site não foi diferente. Como gosto mais da área de backend, não tenho tanta experiência com frameworks frontend. Quase tudo que já fiz foi com React, Next.js ou até mesmo JavaScript e HTML puro, como dá pra ver em um dos meus projetos:\r\n\r\n  \r\n\r\nOu então na versão antiga do meu portfólio que nunca chegou a ir ao ar. No momento em que escrevo este artigo, ainda estou pensando se deixo ela pública ou não.\r\n\r\nMas afinal, qual biblioteca escolhi? Depois de analisar opções como Vue, Solid (com o qual já tive uma experiência bem positiva) e Svelte, acabei escolhendo Svelte. Sempre vejo o Svelte sendo muito elogiado e cada vez mais adotado, inclusive por grandes sites como a App Store e o Spotify. E posso dizer que logo de cara já gostei bastante da experiência de desenvolvimento.\r\n\r\nDepois disso, pensei na parte de estilização. Considerei CSS puro, SASS ou TailwindCSS. CSS eu descartei na hora. SASS até considerei por ser algo que ainda não testei, mas no fim escolhi TailwindCSS, com o qual já tive ótimas experiências. Continuo achando excelente, é basicamente CSS em forma de classes, sem precisar ficar lidando com aquelas peculiaridades de comportamento dos diferentes navegadores.\r\n\r\nE, claro, para escrever os artigos do blog, markdown foi a melhor escolha possível. Criar várias páginas na mão com Svelte, ou qualquer framework, é completamente inviável a longo prazo. Depois de uns 20 ou 30 posts, você acaba com uma estrutura enorme e difícil de gerenciar, seja pra estilizar cada página ou criar componentes específicos.\r\n\r\nPara fazer o parse do markdown dentro do Svelte, usei o mdsvex, uma biblioteca que lembra bastante o MDX pela possibilidade de integrar componentes diretamente no markdown.\r\n\r\n---\r\n\r\n## Svelte\r\n\r\nBom, como comentei no tópico anterior escolhi usar o Svelte, apesar de ter considerado as outras opções como o React ou HTML, mas não me leve a mal, chega de React, toda hora vemos falar de React daqui, React dali, React... Então pensei \"Quer saber? Vou usar Svelte\" e como ja disse que experiencia boa.\r\n\r\nObviamente que para esse site poderia ter usado markdown e usar um script para converter para HTML usando o Unified, Remark e Rehype ou HUGO com um tema já pronto, que entregaria uma experiencia responsiva, sem trabalho nenhum de fazer isso do zero.\r\n\r\nMas apesar disso, [luisfadini.com](https://luisfadini.com) é meu pequeno espaço na internet, então se você está aqui, aqui terá minhas opiniões e etc, então para fazer o meu pequeno espaço na internet ser do meu jeito, resolvi usar o Svelte, que acaba sendo uma biblioteca bem confortável de se trabalhar. Olha esse exemplo de um contador simples:\r\n\r\n```svelte\n\r\n\r\nO valor é {contador}\r\n\r\n\r\n\tbutton {\r\n\t\tfont-size: 1em;\r\n\t\tbackground-color: blue;\r\n\t\tpadding: 4px;\r\n\t}\r\n\r\n```\r\n\r\nE assim está feito um contador funcional. Inclusive, aqui está ele:\r\n\r\n\r\n  O valor é {contador}\r\n\r\n  \r\n    button {\r\n      font-size: 1em;\r\n      background-color: blue;\r\n      padding: 4px;\r\n      cursor: pointer;\r\n    }\r\n  \r\n\r\n\r\nUm detalhe que acho muito legal no Svelte é o escopo dos estilos. As regras dentro da tag `` valem apenas para o componente/página atual, a menos que você use `:global`, que ai irá aplicar o estilo para componentes usados nessas página.\r\n\r\nTambém utilizei o SvelteKit, que funciona mais ou menos como o Next.js, possibilita rotas de API, otimizações de SEO, SSR enfim. Dá pra pensar no Svelte como sendo o React e no SvelteKit como o Next.js nesse ecossistema.\r\n\r\n---\r\n\r\n## Tailwind\r\n\r\nNão tenho muito a comentar sobre o Tailwind, entre as escolhas que eu falei que era o CSS puro, SASS ou Tailwind, preferi ir na escolha mais pratica que seria o Tailwind, até pela facilidade que já possuo usando o Tailwind por facilitar o design para mobile, algo que não gosto tanto. Mesmo que o HTML fica verboso, mas só de já lidar com todo o trabalho de design em mobile, com media queries e etc.\r\n\r\nApesar disso, não considero que o site tenha ficado bonito, mas acabei nesse estilo que está agora, um tema dark, não muito chamativo, algo feito mais por alguem que é focado no backend.\r\n\r\nMesmo não sendo o Tailwind, faz parte do tema do site, que seria os icones, e bom os icones que utilizei foram do Iconify, pois ele reune aproximadamente 275k icones de diversos provedores diferentes, para os icones presentes nos textos e nos links sociais estou usando o icones do Phosphor e para icones de linguagens de programação estou usando o Material Icon Theme, o mesmo da extensão do VS Code.\r\n\r\n---\r\n\r\n## Markdown\r\n\r\nNo começo, o site funcionava com `gray-matter` para separar metadata e conteúdo, e depois uma stack de Unified/Remark/Rehype para converter markdown em HTML. Eu tinha até criado um plugin pro Rehype que adicionava classes nas tags para estilização, mas no final percebi que o **tailwindcss-typography** já fazia esse trabalho muito bem com a classe `prose` e podendo personalizar um pouco, mesmo sendo um estilo ja definido.\r\n\r\nMas como você já deve ter percebido ao longo do post, eu queria inserir componentes Svelte dentro dos artigos. Com Remark/Rehype gerando apenas HTML isso não funciona, precisaria de um preprocessor do SvelteKit para converter o código Svelte para HTML. Então abandonei essa stack e passei a usar somente:\r\n\r\n- `gray-matter` para extrair metadata\r\n- `mdsvex` como preprocessor\r\n\r\nAssim sendo possível o Svelte renderizar tudo como se fosse qualquer outra página do site.\r\n\r\n---\r\n\r\n## Fazendo o deploy\r\n\r\nPara o deploy, escolhi usar Docker. Ele é bastante universal e funciona em praticamente qualquer servidor. Para isso, criei um Dockerfile com multi-stage build, dividido em duas etapas.\r\n\r\nNa primeira etapa (builder), o container é responsável por instalar as dependências e fazer a build do projeto. Na segunda, usando a imagem node:25-alpine, eu apenas rodo a aplicação com o mínimo necessário, o que ajuda a reduzir um pouco o tamanho da imagem final.\r\n\r\nO ideal, provavelmente, seria usar uma imagem distroless, algo que posso fazer em um próximo passo. Caso queira ver o Dockerfile completo, é só clicar aqui: [Dockerfile](https://github.com/LuisFadini/personal-website/blob/62e6924800b6f86f6443089d520bc8b3990b22e7/Dockerfile).\r\n\r\n```dockerfile\nFROM node:25-alpine AS builder\r\n# comandos específicos de build\r\n\r\nFROM node:25-alpine\r\nWORKDIR /app\r\nCOPY --from=builder /app/build build/\r\nCOPY --from=builder /app/node_modules node_modules/\r\n# rodar o projeto\r\n```\r\n\r\nAlém disso, para hospedar o projeto, utilizei o free tier do Google Cloud Platform. Nesse plano, eles oferecem uma instância e2-micro, com 2 vCPUs compartilhadas, 1 GB de RAM e apenas 1 GB de tráfego outbound por mês, sim, é pouco, mas a CDN da Cloudflare, que fica na frente do site, já resolve boa parte desse problema. Além disso, o site tem pouquíssimos acessos, então esse limite não chega a ser um grande impeditivo.\r\n\r\nNessa instância e2-micro, utilizei um docker-compose para subir os serviços necessários. Abaixo está uma versão simplificada do arquivo. Além do que está definido nele, também tenho rodando um Cloudflare DDNS. Pretendo documentar melhor esse deploy em um post futuro, entrando em detalhes do meu homelab utilizando Terraform.\r\n\r\n```yaml\nservices:\r\n  personal-website:\r\n    image: ghcr.io/luisfadini/personal-website:latest\r\n    networks:\r\n      - traefik\r\n    labels:\r\n      - \"com.centurylinklabs.watchtower.enable=true\"\r\n      - \"traefik.enable=true\"\r\n      - \"traefik.http.routers.personal-website.rule=Host(`${DOMAIN}`) && !PathPrefix(`/watchtower`)\"\r\n      - \"traefik.http.routers.personal-website.entrypoints=web\"\r\n      - \"traefik.http.services.personal-website.loadbalancer.server.port=3000\"\r\n\r\n  watchtower:\r\n    image: nickfedor/watchtower\r\n    volumes:\r\n      - /var/run/docker.sock:/var/run/docker.sock\r\n    environment:\r\n      - WATCHTOWER_ROLLING_RESTART=true\r\n      - WATCHTOWER_UPDATE_ON_START=true\r\n      - WATCHTOWER_CLEANUP=true\r\n    networks:\r\n      - traefik\r\n    labels:\r\n      - \"com.centurylinklabs.watchtower.enable=true\"\r\n\r\n  traefik:\r\n    image: traefik\r\n    command:\r\n      - \"--providers.docker=true\"\r\n      - \"--providers.docker.exposedbydefault=false\"\r\n      - \"--providers.docker.network=traefik\"\r\n      - \"--entrypoints.web.address=:80\"\r\n    networks:\r\n      - traefik\r\n    ports:\r\n      - \"80:80\"\r\n    volumes:\r\n      - /var/run/docker.sock:/var/run/docker.sock:ro\r\n    labels:\r\n      - \"com.centurylinklabs.watchtower.enable=true\"\r\n      - \"traefik.enable=false\"\r\n\r\nnetworks:\r\n  traefik:\r\n    name: traefik\r\n```\r\n\r\nAlém disso, configurei workflows no GitHub para automatizar todo o processo de build e deploy. Sempre que ocorre um push na branch main, um workflow faz a build automática do container, publica a nova imagem e criando um release no Github.\r\n\r\nEm seguida, outro workflow é responsável por disparar a atualização no servidor, solicitando ao Watchtower que faça o pull da nova imagem e reinicie o container. Dessa forma, o site é atualizado de forma praticamente automática e em quase tempo real.\r\n\r\nCaso queira ver esses workflows em mais detalhes:\r\n- [Workflow de build](https://github.com/luisfadini/personal-website/blob/main/.github/workflows/build-and-publish.yaml)\r\n- [Workflow de update](https://github.com/luisfadini/personal-website/blob/main/.github/workflows/update-deployment.yaml)\r\n\r\n---\r\n\r\n## Conclusão\r\n\r\nBom, talvez tenha ficado um pouco confuso esse post, então vou resumir em umas simples lista:\r\n\r\n- Svelte\r\n- SvelteKit\r\n- Tailwind\r\n- Tailwind Typography\r\n- Iconify\r\n- mdsvex\r\n- Docker"}]}