waktu membaca : 10 minutes

Apakah Anda pernah mengalami saat ketika situs lokal Anda terlihat tidak ada, tapi setelah dideploy online semuanya menjadi sempurna? Itu yang terjadi dengan plugin Gradle JBake saya. Tugas`serve`Menampilkan tombol berbentuk kotak, teks gelap di latar belakang hitam, dan CSS yang aneh tidak ada. Namun`publishSite`Menghasilkan situs yang sama, itu, sempurna. Penyebabnya bukan CSS, bukan peramban, bukan cache. Ini adalah satu baris kode Kotlin — dan kebiasaan buruk dengan argumen baris perintah.

ketuk

[]

Adegan: empat screenshot, dua rendering

Itu terjadi setelah sistem crash. Saya telah membuat empat tangkapan layar untuk membandingkan rendering lokal (./gradlew serve`pada`localhost:8820) dengan rendering inline (`publishSite`pada GitHub Pages). Dua screenshot per halaman : bagian atas dan bagian bawah.

Render lokal

Atas halaman— Tombol Project dan Template adalahkecil, persegi panjang, ke warna standar (biru dan hijau). Kartu Start Writing memiliki sebuahlatar belakang hitam polos, tanpa kerangka.

Rendu local - haut de page

Bawah halaman— Subjudul Artikel dan Sumber Daya Terbaru adalahhampir tidak dapat dibaca, terlalu gelap di latar hitam. Tanggal di bawah gambar blog ("17 October 2013", dst.) adalahtidak hadir.

Rendu local - bas de page

Dirender secara online

Bagian atas halaman— Tombol-tombol yang sama adalahbesar, domba, hijau neon mencolok, teks dalam huruf besar. Kartu memiliki satubingkai putih melengkung dengan bayangan jatuh.

Rendu en ligne - haut de page

footer— Subjudul adalahmudah dibaca. Tanggal adalahterlihat. Kartu artikel memilikisudut melengkungdan judul-judul adalahtebal.

Rendu en ligne - bas de page

Refleks pertama: tema. Saya menggunakan sistem tema dinamis (terang, gelap, kontras tinggi) berdasarkan`localStorage`. Mungkin bahwa toko lokal memicu tema kontras tinggi? Tidak. Saya sudah menulis sebelumnya.https://cheroliv.com/blog/2025/0098_preloading_css_variable_post.html[sebuah artikel lengkap tentang pra-pemuatan tema], saya tahu cara kerjanya. Dan kemudian, bahkan dalam mode high-contrast, struktur CSS (tombol oval, bayangan) seharusnya ada di sana. Dia tidak ada di sana.

Refleks kedua: cache browser. Tidak, saya sudah menguji dengan profil bersih. Perbedaannya tetap ada.

Refleks ketiga :`serve`tidak menyajikan file yang sama seperti`publishSite`.

Diagnosa : serve tidak menunjuk ke direktori yang benar

Plugin Gradle saya`bakery`memiliki dua tugas utama:

  • bake: menghasilkan situs statis di`build/bake/`

  • serve: menjalankan server web lokal

  • publishSite: tunas`build/bake/`ke GitHub Pages

Divergensi hanya bisa datang dari`serve`. Si publishSite`mempublikasikan konten yang benar, itu adalah`build/bake/`adalah baik. Jika`serve`menampilkan hal lain, berarti ia tidak berfungsi`build/bake/.

Mari kita lihat kode. Di`SiteManager.kt`, tugas`serve`adalah didefinisikan seperti ini :

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`adalah titik masuk CLI JBake 2.7.0. Ideanya: melewati-b`untuk folder sumber dan`-s`untuk folder tujuan, lalu jalankan mode server. Kecuali…​

Penyebab utama: JBake CLI tidak berfungsi seperti itu

JBake 2.7.0 menunggu beberapaargumen posisiuntuk sumber dan tujuan, lalu flags opsional. Tanda tandanya adalah :

jbake <source> <destination> [options]

Namun di kode saya, saya menulis:

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

JBake mengartikannya sebagai :

  1. -b→ parse flag 'bake' (boolean), telah dikonsumsi

  2. /path/to/site→ menjadi argumen posisi 1 (sumber)

  3. -s→ mengurai flag "serve" (boolean), server dimulaisegera

  4. `/path/to/build/bake`menjadi sebuah argumen yang terasing, diabaikan atau salah ditafsirkan

Hasil : JBake sedang mengambil`/path/to/site`sebagai sumber,tidak mempertimbangkan destinasiyang disediakan (build/bake), dan menggunakan repertoar standar-nya (sering`./output`atau salinan sementara). File`css/styles.css`Build tersebut sehingga di-overwrite atau diabaikan, dan CSS default lama (tanpa variabel kustom, tanpa radius, tanpa bayangan) yang disajikan.

Dalam perbandingan,bake et publishSite`menggunakanplugin Gradle JBake resmi( )`jbake-gradle-plugin) yang menulis dengan rapi di`build/bake/`via Gradle API. Mereka tidak melewati CLI.

Solusi: argumen positional, bukan flag

Koreksi ini trivial — setelah tahu. Cukup meneruskan sumber dan destinasi sebagai argumen posisional, lalu`-s`akhirnya :

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

Itu saja. Tiga baris diubah, bug telah diperbaiki.

Setelah publikasi lokal plugin ini ()publishToMavenLocal), un `./gradlew serve`Menjalankan JBake dengan sintaksis yang benar :

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

Dan kali ini, server Jetty yang terintegrasi dengan JBake melayani konten dari`build/bake/`— sama dengan yang dipublikasikan secara online.

@startuml
!define RECTANGLE class

package "SEBELUM (bug)" {
  RECTANGLE JBakeCLI1 {
    + args = ["-b", "situs", "-s", "membangun/memanggang"]
  }

  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 "SETELAH (perbaikan)" {
  RECTANGLE JBakeCLI2 {
    + args = ["situs", "membangun/memanggang", "-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

Pemeriksaan cepat dengan curl

Agar memastikan bahwa server menyajikan dengan baik konten yang benar, sebuah sederhana`curl`mengonfirmasi bahwa`index.html`mengandung`data-bs-theme="light"`dan bahwa`build/bake/css/styles.css`beratnya tepat 31 402 byte — identik dengan file yang dihasilkan oleh`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

Render lokal sekarangpixel-identikke render dideploy.

Mengapa bug ini jahat?

Kamu tahu mengapa ini sulit ditangkap?

  1. Tidak ada kesalahan eksplisitJBake tidak crash. Dia "berfungsi", hanya dengan sebuah direktori yang salah.

  2. Build berfungsi:`./gradlew bake`membuat dengan benar file-file di`build/bake/`.

  3. Penerapan berfungsi:`publishSite`mengunggah konten yang baik secara online

  4. Hanya serve yang rusak: tugas pengembangan, yang selalu digunakan untuk iterasi.

  5. Kebiasaan -key value: sebagai seorang developer, kita dikondisikan oleh beberapa tahun CLI Unix (-o output`, -i input). JBake CLI adalah sebuah pengecualian — sumber dan destinasi bersifat posisi.

Kesimpulan

Jika Anda memelihara plugin Gradle yang membungkus JBake (atau alat CLI apa pun),baca dokumentasi argumenmeskipun Anda kira Anda mengenal mereka. Sebuah hipotesis implisit (-s= "set destination") dapat menguras waktu berjam-jam untuk debug visual.

Di sini, perbaikan itu secara harfiah adalah mengubah:

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

en :

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

Tiga token telah dipindahkan, dan situs lokal saya kembali sama indah dengan situs produksi.

Pelajaran: ketika rendering berbeda antara lokal dan produksi tanpa alasan jelas, pertimbangkan dulu pipeline — bukan CSS, bukan browser, dan jauh lebih bukan framework. Seringnya langkah sebelum rendering yang menipu.

Artikel terkait