زمان مطالعه : 10 minutes

آیا این لحظه را می‌شناسید که سایت شما در محلی به‌نظر نمی‌رسد، اما وقتی آن‌لاین می‌شود، همه چیز عالی می‌شود؟ این دقیقاً همان چیزی بود که برای من با پلاگین Gradle JBake پیش آمد. وظیفه`serve`دکمه‌های مربعی، متن تیره بر بground سیاه و CSS عجیبانه غایب نمایش می‌داد. اما`publishSite`سایت یکسانی را، به‌طور کامل، تولید می‌کرد. ملزم نبود نه CSS، نه مرورگر، نه کش بود. یک خط کد Kotlin بود — و یک عادت بد با آرگومان‌های خط فرمان.

تك

[]

صحنه: چهار اسکرین‌شات، دو رندر

این پس از یک crash سیستم بود. من چهار بار اسکرین‌شات گرفته بودم تا رندر محلی را مقایسه کنم (./gradlew serve`روی`localhost:8820) با نمایش آنلاین (`publishSite`در GitHub Pages). دو اسکرین‌شوت برای هر صفحه: بالا و پایین.

رندر محلی

بالای صفحه— دکمه‌های Project و Template هستندکوچک، مستطیل, به رنگ‌های استاندارد (آبی و سبز). کارت Start Writing یکپس‌زمینه سیاه یکنواخت, بدون چارچوب.

Rendu local - haut de page

پایین صفحه— زیرنویس "مقالات و منابع اخیر" استتقریباً نامقروء, به شدت تیره روی پس‌زمینه سیاه. تاریخ‌ها زیر عکس‌های وبلاگ ("17 October 2013", etc.) هستندغایب‌ها.

Rendu local - bas de page

رندر آنلاین

بالای صفحه— دکمه‌های مشابه هستندبزرگ، گوسفند، سبز نئون flashy، متن با حروف بزرگ. کارت یکچارچوب سفید丸ی با سایه افتراقی.

Rendu en ligne - haut de page

پایین صفحه— زیرنویس استبه‌راحتی خواندنی. تاریخ‌ها هستندقابل مشاهده. کارت‌های مقالات دارندگوشه‌های گردو عناوین هستندضخیم.

Rendu en ligne - bas de page

اولین واکنش: تم. من از یک سیستم تم داینامیک (روشن، تیره، high-contrast) استفاده می‌کنم که مبنی بر`localStorage`. شاید فروشگاه محلی تم high-contrast را فعال کرده باشد؟ نه. من پیشاً نوشته بودمhttps://cheroliv.com/blog/2025/0098_preloading_css_variable_post.html[یک مقاله کامل درباره بارگذاری پیش‌فرض تم‌ها], من می‌دانم چطور کار می‌کند. و سپس، حتی در حالت high-contrast، ساختار CSS (دکمه‌های بيضوی، سایه‌ها) باید وجود داشته باشد. او وجود نداشت.

انعکاس دوم: کش مرورگر. خیر، من تست را با پروفایل‌های تمیز انجام داده بودم. تفاوت همچنان پابرجا بود.

بازتاب سوم :`serve`فایل‌های یکسانی را خدمت نمی‌داد که`publishSite`.

تشخیص : serve به درستی به پوشه صحیح اشاره نمی‌کرد

پلاگین Gradle من`bakery`دو کار اصلی :

  • bake: سایت استاتیک را در`build/bake/`

  • serve: یک سرور وب محلی را راه‌اندازی می-conduct

  • `publishSite`بزن`build/bake/`به GitHub Pages

تفاوت nemitavanad be‑joz az …​ biâyad`serve`. Si publishSite`او محتوای صحیح را منتشر می‌کرد، یعنی`build/bake/`بوده خوب بود. اگر`serve`نمایش می‌داد چیزی دیگر، به این معناست که کار نمی‌کرد`build/bake/.

بیایید کد را نگاه کنیم. در`SiteManager.kt`, کار`serve`به این صورت تعریف می‌شود:

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`نقطه‌ی ورودی CLI JBake 2.7.0 است. ایده: گذشتن-b`برای پوشه منبع و`-s`برای پوشه مقصد، سپس حالت سرور را اجرا کنید. اما…​

دلیل اصلی: JBake CLI کار نمی‌کند به این شکل

JBake 2.7.0 در انتظار برخیآرگومان‌های موقعیتیبرای源 و مقصد، سپس پرچم‌های اختیاری. امضا به صورت زیر است :

jbake <source> <destination> [options]

اما در کد من، می‌نوشتم :

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

JBake این را به این معنا می‌دانست:

  1. -b→ پارس کردن فلگ "bake" (بولین), مصرف شده

  2. /path/to/site→ می‌شود آرگومنت موقعیتی 1 (منبع)

  3. -s→ تجزیهٔ پرچم "serve" ( بولین )، سرور راه‌اندازی شدفوریاً

  4. /path/to/build/bake→ به یک استدلال یتیم، نادیده گرفته یا نادرست تفسیر شده تبدیل می‌شود

نتیجه: JBake می‌گرفت`/path/to/site`به عنوان منبع,مقصد را در نظر نمی‌گرفتارائه شده (build/bake)، و استفاده می‌کرد از دایرکتوری پیش‌فرضش (معمولاً`./output`یا یک کپی موقت). فایل`css/styles.css`build بنابراین بازنویسی یا نادیده گرفته شد و یک CSS پیش‌فرض قدیمی (بدون متغیرهای سفارشی، بدون گرد کردن، بدون سایه) ارائه می‌شد.

در مقایسه،bake et publishSite`آن‌ها آن راپلاگین Gradle JBake رسمی(`jbake-gradle-plugin) که به خوبی می‌نویسد در`build/bake/`از طریق API Gradle. آنها از طریق CLI رد نمی‌شوند.

حل: آرگومان‌های موقعیت‌پذیر، نه پرچم‌ها

اصلاح آسان — وقتی می‌دانید. کافی است که منبع و مقصد را به‌عنوان آرگومنت‌های موقعیت‌پذیر بدهید، سپس`-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"
)

این همه است. سه خط تغییر یافت، bug رفع شد.

بعد از انتشار محلی پلاگین`publishToMavenLocal`), un `./gradlew serve`JBake را با سینتکس صحیح اجرا کنید :

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

و این بار، سرور Jetty جاسازی شده در JBake به خوبی محتوای`build/bake/`— متشابه با آنچه آنلاین منتشر شده است.

@startuml
!define RECTANGLE class

package "قبل (bug)" {
  RECTANGLE JBakeCLI1 {
    + args = ["-b", "سایت", "-s", "ساخت/پخت"]
  }

  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 "پس از (fix)" {
  RECTANGLE JBakeCLI2 {
    + args = ["سایت", "ساخت/پخت", "-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

بررسی سریع با curl

برای اطمینان حاصل که سرور به درستی محتوای مناسب را ارائه می‌دهد، یک ساده`curl`تایید می‌کند که`index.html`شامل است`data-bs-theme="light"`و که`build/bake/css/styles.css`وزن آن ۳۱٬۴۰۲ بایت است — مطابق با فایل تولید شده توسط`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

رندرینگ محلی اکنونپیکسل یکسانبه خروجی مستقر.

چرا این باگ خبیث بود

می‌بینید گرتن سخت بود ؟

  1. بدون خطای صریح: JBake crash نمی‌کرد. او "کار می‌کرد"، به سادگی با یک پوشه اشتباه.

  2. بیلد کار می‌کرد:`./gradlew bake`فایل‌ها را به درستی در …​ تولید می‌کرد`build/bake/`.

  3. استقرار کار می‌کرد:`publishSite`محتوا خوب را آنلاین push می-count

  4. تنها serve شکسته بود: وظیفه توسعه، کاری که به‌صورت مستمر برای تکرار استفاده می‌شود

  5. عادت از -key value: به عنوان یک توسعه‌دهنده، ما توسط سال‌های CLI یونیکس تحت تأثیر قرار می‌گیریم-o output`, -i input). JBake CLI یک استثنا است — منبع و مقصد موقعیتی هستند.

نتیجه

شما یک پلاگین Gradle را که JBake (یا هر ابزار CLI دیگری) را به صورت لفه (wrapper) محاطه می‌کنید، نگهداری می‌کنیدمستندات آرگومان‌ها را بخوانیدحتی اگر فکر می‌کنید شما آنها را می‌شناسید. یک فرضیه ضمني (-s= "set destination") می‌تواند ساعت‌ها از دیباغینگ بصری شما را به هدر بدهد.

اینجا، حل به‌صورت حرفی برای تغییر :

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

en :

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

سه توکن جابجا شده‌اند و سایت محلی من دوباره به همان زیبایی سایت تولیدی بر می‌گردد.

درس: وقتی render در محیط local و prod متفاوت شود بدون دلیل واضح، ابتدا pipeline را مشتبه بدانید — نه CSS، نه مرورگر، و نه حتی framework. معمولاً مرحله‌ای دقیق قبل از render است که تقلب می‌کند.

مقالات مرتبط