چرا `serve` یک وبسایت قبیح نشان میداد در حالی که `publishSite` کامل بود
منتشر شده در 22 April 2026
آیا این لحظه را میشناسید که سایت شما در محلی بهنظر نمیرسد، اما وقتی آنلاین میشود، همه چیز عالی میشود؟ این دقیقاً همان چیزی بود که برای من با پلاگین Gradle JBake پیش آمد. وظیفه`serve`دکمههای مربعی، متن تیره بر بground سیاه و CSS عجیبانه غایب نمایش میداد. اما`publishSite`سایت یکسانی را، بهطور کامل، تولید میکرد. ملزم نبود نه CSS، نه مرورگر، نه کش بود. یک خط کد Kotlin بود — و یک عادت بد با آرگومانهای خط فرمان.
- تك
-
[]
صحنه: چهار اسکرینشات، دو رندر
این پس از یک crash سیستم بود. من چهار بار اسکرینشات گرفته بودم تا رندر محلی را مقایسه کنم (./gradlew serve`روی`localhost:8820) با نمایش آنلاین (`publishSite`در GitHub Pages). دو اسکرینشوت برای هر صفحه: بالا و پایین.
رندر محلی
بالای صفحه— دکمههای Project و Template هستندکوچک، مستطیل, به رنگهای استاندارد (آبی و سبز). کارت Start Writing یکپسزمینه سیاه یکنواخت, بدون چارچوب.
پایین صفحه— زیرنویس "مقالات و منابع اخیر" استتقریباً نامقروء, به شدت تیره روی پسزمینه سیاه. تاریخها زیر عکسهای وبلاگ ("17 October 2013", etc.) هستندغایبها.
رندر آنلاین
بالای صفحه— دکمههای مشابه هستندبزرگ، گوسفند، سبز نئون flashy، متن با حروف بزرگ. کارت یکچارچوب سفید丸ی با سایه افتراقی.
پایین صفحه— زیرنویس استبهراحتی خواندنی. تاریخها هستندقابل مشاهده. کارتهای مقالات دارندگوشههای گردو عناوین هستندضخیم.
اولین واکنش: تم. من از یک سیستم تم داینامیک (روشن، تیره، 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`به این صورت تعریف میشود:
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 این را به این معنا میدانست:
-
-b→ پارس کردن فلگ "bake" (بولین), مصرف شده -
/path/to/site→ میشود آرگومنت موقعیتی 1 (منبع) -
-s→ تجزیهٔ پرچم "serve" ( بولین )، سرور راهاندازی شدفوریاً -
/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`در آخر :
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
رندرینگ محلی اکنونپیکسل یکسانبه خروجی مستقر.
چرا این باگ خبیث بود
میبینید گرتن سخت بود ؟
-
بدون خطای صریح: JBake crash نمیکرد. او "کار میکرد"، به سادگی با یک پوشه اشتباه.
-
بیلد کار میکرد:`./gradlew bake`فایلها را به درستی در … تولید میکرد`build/bake/`.
-
استقرار کار میکرد:`publishSite`محتوا خوب را آنلاین push می-count
-
تنها
serveشکسته بود: وظیفه توسعه، کاری که بهصورت مستمر برای تکرار استفاده میشود -
عادت از
-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 است که تقلب میکند.