време за читање : 10 minutes

Znate li o tom trenutku kad vaš lokalni sajt izgleda kao ništa, ali kada se objavi na mreži sve je u redu? To je mi se desilo sa mojim Gradle JBake pluginom. Zadatak`serve`prikazivao kvadratni dugmad, temni tekst na crnoj pozadini, i bizarno odsutan CSS. Ipak`publishSite`je generisao isti sajt, onaj, bez greške. Krivac nije bio ni CSS, ni preglednik, ni keš. Bio je jedna linija Kotlin koda — i loša navika sa argumentima komandne linije.

tik

[]

Сцена: четири скриншота, два рендера

Било je nakon краха система. Снимio сам четири слике екрана да упоређим локални рендер (./gradlew serve`na`localhost:8820) sa inline renderovanjem (`publishSite`na GitHub Pages). Dva screenshots po stranici : gore i dole.

Lokalni render

Vrh stranice— Дугмићи Project i Template суmali, pravougaoni, u standardnim bojama (plava i zelena). Kartica Start Writing imajednobojno crno pozadina, bez okvira.

Rendu local - haut de page

podnožje— Podnaslov "Последњи чланци и ресурси" јепочти нијечитљив, previše tamno na crnom pozadini. Datumi ispod slika bloga ("17 October 2013", itd.) suodsutne.

Rendu local - bas de page

Izrenderivano na mreži

Врх странице— Isto dugma suвелики, овјарски, неоново зелен, јучест, tekst u velikim slovima. Karta imazaobljeni beli okvir s senkom.

Rendu en ligne - haut de page

Futer— Podnaslov jedobro čitavo. Datumi suвидљиви. Kartice artikala imajuzaobljeni kutovii naslovi suuvlaceno.

Rendu en ligne - bas de page

Први рефлекс: тема. Користим систем теме динамичке (светла, тама, high-contrast) базиран на`localStorage`. Možda je lokalni store pokretao temu high-contrast? Ne. Već sam napisaohttps://cheroliv.com/blog/2025/0098_preloading_css_variable_post.html[ceo članak o učitanju tema unapred], Znam kako to radi. I pak, čak i u high-contrast modu, CSS struktura (ovaoblasta dugmeta, senke) trebalo da bude tamo. Nije bila.

Drugi refleks: keš pretraživača. Ne, testirao sam na čistim profilima. Razlika je ostala.

Трећи рефлекс :`serve`nije služio iste fajlove kao`publishSite`.

Dijagnostika : serve nije ukazivalo na pravilan folder

Moj Gradle plugin`bakery`ima dva glavna zadatka:

  • bake: generira statički sajt u`build/bake/`

  • serve: Pokreni lokalni web server

  • publishSite: dira`build/bake/`ka GitHub Pages

Divergencija je mogla da dođe samo iz`serve`. Si publishSite`Objavljivao je ispravan sadržaj, jer je`build/bake/`Bilo je dobro. Ako`serve`prikazivao je nešto drugo, zato što nije služio`build/bake/.

Pogledajmo kod. U`SiteManager.kt`, zadatak`serve`je definisana kao ovo:

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`je ulazna tačka CLI JBake 2.7.0. Ideja: proći-b`за изворни директоријум и`-s`за одредешњи folder, pokreni server мод. Осим што…​

Главна причина: JBake CLI ne radi tako

JBake 2.7.0 ocekujepozicioni argumentiza izvor i destinaciju, zatim opcione flagove. Potpis je:

jbake <source> <destination> [options]

Али у мојем коду јех писао:

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

JBake je tumačio da je:

  1. -b→ parsiraj flag "bake" (boolean), ispotrošeno

  2. /path/to/site→ postaje pozicioni argument 1 (izvor)

  3. -s→ parsiraj flag "serve" (bool), server pokrenutодмах

  4. /path/to/build/bake→ postaće siromasni argument, zanemaren ili pogrešno tumačen

Резултат: JBake узимао`/path/to/site`kao izvor,није узимало у обзир одредиштеобесбечена (build/bake), i koristilo je svoj podrazumevani repertoar (često`./output`или времену копију). Датотека`css/styles.css`build-a je bio prepisan ili ignorisan, a bio je staro podrazumevano CSS (bez custom promenjivih, bez zaobljenja, bez senki) koje je bilo servisano.

U poredbi,bake et publishSite`koristezvanični Gradle JBake plugin(`jbake-gradle-plugin) koji piše uređeno u`build/bake/`kroz Gradle API. Ne prolaze kroz CLI.

Решение : позициони аргументи, не флагови

Korekcija je trivijalna — jednom kada znaš. Dovoljno je proslediti izvor i destinaciju kao pozicionalni argumenti, pa`-s`на крају

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"
)

To je sve. Tri linije promenjene, greška rešena.

После локалног објављивања плагина (publishToMavenLocal), un `./gradlew serve`pokreni JBake sa ispravnom sintaksom:

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

И ови пут, Jetty сервер интегрован у JBake добро служи садржају`build/bake/`— идентично што је објављено онлайн.

@startuml
!define RECTANGLE class

package "PRE (bug)" {
  RECTANGLE JBakeCLI1 {
    + args = ["-b", "сајт", "-s", "graditi/peci"]
  }

  RECTANGLE Source1 {
    + site/
  }

  RECTANGLE Dest1 {
    + ??? (dossier temporaire)
  }

  RECTANGLE Jetty1 {
    + sert mauvais fichiers
  }

  JBakeCLI1 --> Source1 : lit
  JBakeCLI1 -[#red]x Dest1 : destination ignorée
  Jetty1 --> Dest1 : sert
}

package "POSLE (fix)" {
  RECTANGLE JBakeCLI2 {
    + args = ["сајт", "graditi/peci", "-s"]
  }

  RECTANGLE Source2 {
    + site/
  }

  RECTANGLE Dest2 {
    + build/bake/
  }

  RECTANGLE Jetty2 {
    + sert les bons fichiers
  }

  JBakeCLI2 --> Source2 : lit
  JBakeCLI2 --> Dest2 : écrit dans
  Jetty2 --> Dest2 : sert OK
}
@enduml

Brza provera sa curl

Da biste se uverili da server ispravno služi dobrog sadržaja, jednostavno`curl`potvrđuje da`index.html`sadrži`data-bs-theme="light"`i da`build/bake/css/styles.css`teži tacno 31 402 bajta — identičan datoteci generisanoj od`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

Локални рендер је садапиксељ-идентичанна разгредовани приказ.

Zašto je ovaj bug bio lukav?

Видиш зато је било тешко да се ухвати?

  1. Nema explicitne greške: JBake nije pao. "Funkcionisao" je, jednostavno sa pogrešnim direktorijumom.

  2. Build je radio : ./gradlew bake`исправно генерисао фајлове у`build/bake/.

  3. Распоред је радио:`publishSite`Postavljao je dobar sadržaj na internetu.

  4. Samo serve je bio pokvaren: zadatak razvoja, onaj koji stalno koristimo za iteriranje

  5. Navika od -key value: kao programer, smo uslovljeni godinama rada u Unix CLI (-o output`, -i input). JBake CLI je izuzetak — izvor i destinacija su pozicionirani.

Zaključak

Ako održavate Gradle plugin koji omotava JBake (ili bilo koji CLI alat),pročitajte dokumentaciju argumenataćak i ako mislite da ih poznajete. Jedna implicitna hipoteza (-s = "set destination")` може вам коштати сате визуелног дебаговања.

Ово, поправка је била дословно да се промени:

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

en :

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

Tri pomerena token, i moj lokalni sajt ponovo postaje leпокao kao sajt u produkciji.

Lekcija: kad se renderovanje razlikuje između lokalnog i produkcijskog okruženja bez očiglednog razloga, prvo sumnjajte na pipeline — ne na CSS, ne na pretraživač, a još manje na framework. Često je korak ispravno prije renderovanja koji vara.

Повезани чланци