tempo de leitura : 10 minutes

Você conhece aquele momento em que o seu site local parece nada, mas uma vez colocado online tudo fica impecável? Isso aconteceu comigo com meu plugin Gradle JBake. A tarefa`serve`exibia botões quadrados, texto escuro sobre fundo preto, e um CSS estranhamente ausente. Porém`publishSite`gerava o mesmo site, ele, impecável. O culpado não era nem o CSS, nem o navegador, nem o cache. Era uma linha de código Kotlin — e um mau hábito com os argumentos na linha de comando.

tic

[]

A cena: quatro screenshots, dois renders

Era depois de uma falha do sistema. Eu tinha tirado quatro capturas de tela para comparar o renderizado local (./gradlew serve`sobre`localhost:8820) com a renderização online (`publishSite`no GitHub Pages). Dois screenshots por página: topo e base.

Renderização local

Topo da página— Os botões Project e Template sãopequenos, retangulares, nas cores padrão (azul e verde). O cartão Start Writing tem umfundo preto uniforme, sem moldura.

Rendu local - haut de page

Rodapé— O subtítulo "Últimos artigos e recursos" équase ilegível, muito escuro sobre fundo preto. As datas sob as imagens do blog ("17 October 2013", etc.) sãoausentes.

Rendu local - bas de page

Renderizado online

Topo da página— Os mesmos botões sãograndes, ovinos, verde neon flashy, texto em maiúsculas. O cartão tem umquadro branco arredondado com sombra projetada.

Rendu en ligne - haut de page

rodapé— O subtítulo ébem legível. As datas sãovisíveis. Os cartões dos artigos têmcantos arredondadose os títulos sãoem negrito.

Rendu en ligne - bas de page

Primeiro reflexo: o tema. Utilizo um sistema de tema dinâmico (claro, escuro, alto contraste) baseado em`localStorage`. Talvez o local store desencadeava um tema high-contrast? Não. Já havia escritohttps://cheroliv.com/blog/2025/0098_preloading_css_variable_post.html[um artigo inteiro sobre o pré-carregamento dos temas], eu sei como isso funciona. E então, mesmo em modo high-contrast, a estrutura CSS (botões ovais, sombras) devia estar lá. Ela não estava lá.

Segundo reflexo: o cache do navegador. Não, eu tinha feito o teste com perfis limpos. O diff persistia.

Terceiro reflexo:`serve`não servia os mesmos arquivos que`publishSite`.

O diagnóstico: serve não apontava para a pasta correta

Meu plugin Gradle`bakery`tem duas tarefas principais:

  • bake: gera o site estático em`build/bake/`

  • serve: inicia um servidor web local

  • publishSite: empurra`build/bake/`para GitHub Pages

A divergência só poderia vir de`serve`. Si publishSite`publicava o conteúdo correto, é que`build/bake/`estava bom. Se`serve`exibia outra coisa, o que significa que não servia`build/bake/.

Vamos olhar o código. Em`SiteManager.kt`, a tarefa`serve`é definida assim :

SiteManager.kt — La tâche serve (version buggy)
tasks.register("serve", JavaExec::class.java) { task ->
    task.apply {
        mainClass.set("org.jbake.launcher.Main")
        classpath = jbakeRuntime
        environment("GEM_PATH", jbakeRuntime.asPath)
        jvmArgs(/* ... */)
        args = listOf(
            "-b", file(site.bake.srcPath).absolutePath,
            "-s", layout.buildDirectory.get()
                .asFile.resolve(site.bake.destDirPath)
                .absolutePath
        )
    }
}

org.jbake.launcher.Main`é o ponto de entrada da CLI JBake 2.7.0. A ideia: passar-b`para a pasta de origem e`-s`para a pasta de destino, então iniciar o modo servidor. Mas…​

A causa raiz: O CLI do JBake não funciona assim

JBake 2.7.0 aguarda algunsargumentos posicionaispara a fonte e o destino, seguido de flags opcionais. A assinatura é :

jbake <source> <destination> [options]

Mas no meu código, eu escrevia :

args = listOf("-b", "/path/to/site", "-s", "/path/to/build/bake")

JBake interpretava isso :

  1. -b→ analisar o sinalizador \"bake\" (booleano), consumido

  2. /path/to/site→ torna-se argumento posicional 1 (fonte)

  3. -s→ analisar o opção "serve" (booleano), servidor iniciadoimediatamente

  4. /path/to/build/bake→ torna-se um argumento órfão, ignorado ou mal interpretado

Resultado: JBake estava tomando`/path/to/site`como fonte,não levava em conta o destinofornecida (build/bake), e utilizava seu diretório padrão (frequentemente`./output`ou uma cópia temporária). O arquivo`css/styles.css`o build era portanto sobrescrito ou ignorado, e é um velho CSS padrão (sem as variáveis personalizadas, sem os arredondamentos, sem as sombras) que estava sendo servido.

Em comparação,bake et publishSite`utilizam oplugin Gradle JBake oficial(`jbake-gradle-plugin) que escreve bem em`build/bake/`via a API Gradle. Eles não passam pela CLI.

A solução: argumentos posicionais, não flags

A correção é trivial — uma vez que se sabe. Basta passar a fonte e o destino como argumentos posicionais, depois`-s`por último:

SiteManager.kt — La tâche serve (version corrigée)
args = listOf(
    file(site.bake.srcPath).absolutePath,
    layout.buildDirectory.get()
        .asFile.resolve(site.bake.destDirPath)
        .absolutePath,
    "-s"
)

É isso. Três linhas alteradas, bug resolvido.

Após publicação local do plugin (publishToMavenLocal), un `./gradlew serve`lança JBake com a sintaxe correta :

jbake /home/user/project/site /home/user/project/build/bake -s

E desta vez, o servidor Jetty integrado ao JBake serve bem o conteúdo de`build/bake/`— idêntico ao que é publicado online.

serve vs publish diagram

Verificação rápida com curl

Para garantir que o servidor esteja servindo o conteúdo correto, um simples`curl`confirma que`index.html`contém`data-bs-theme="light"`e que`build/bake/css/styles.css`pesa bem 31 402 bytes — idêntico ao arquivo gerado por`bake`.

$ ./gradlew serve
# Dans un autre terminal :
$ curl -s http://localhost:8820/ | grep data-bs-theme
<html ... data-bs-theme="light" ...>

$ curl -I http://localhost:8820/css/styles.css
HTTP/1.1 200 OK
Content-Length: 31402
Content-Type: text/css

O render local agorapixel-idênticoao renderizado implantado.

Por que esse bug era sutil

Você vê por que era difícil de pegar?

  1. Nenhum erro explícitoJBake não travava. Ele "funcionava", simplesmente com uma pasta errada.

  2. O build funcionava:`./gradlew bake`gerava corretamente os arquivos em`build/bake/`.

  3. O despliegue estava funcionando:`publishSite`empurrava o bom conteúdo online

  4. Só serve estava quebrado: a tarefa de desenvolvimento, aquela que usamos constantemente para iterar.

  5. O hábito de -key value: como desenvolvedor, somos condicionados por anos de CLI Unix (-o output`, -i input). O CLI do JBake é uma exceção — a fonte e o destino são posicionais.

Conclusão

Se você mantém um plugin Gradle que envolve JBake (ou qualquer ferramenta CLI),leia a documentação dos argumentosmesmo se você pensa que os conhece. Uma hipótese implícita (-s = "set destination") pode custar horas de depuração visual.

Aqui, o fix era literalmente para mudar:

args = listOf("-b", src, "-s", dest)   // ❌ BUG

en :

args = listOf(src, dest, "-s")         // ✅ FIX

Três tokens deslocados, e meu site local volta a ficar tão bonito quanto o site em produção.

Lição: quando a renderização difere entre local e produção sem razão óbvia, suspeite primeiro do pipeline — não o CSS, não o navegador, e muito menos o framework. Frequentemente é a etapa logo antes da renderização que está trapaceando.

Articles connexes