Pourquoi `serve` affichait un site moche alors que `publishSite` était parfait
เผยแพร่เมื่อ 22 April 2026
คุณเคยเจอช่วงเวลาที่เว็บไซต์ของคุณบนเครื่องโลคอลดูไม่ดีเอาเสียเลย แต่พอดีพลอยขึ้นออนไลน์แล้วทุกอย่างกลับสมบูรณ์แบบไหม? นั่นคือสิ่งที่เกิดขึ้นกับปลั๊กอิน Gradle JBake ของฉัน งาน`serve`แสดงปุ่มสี่เหลี่ยม ข้อความสีเข้มบนพื้นหลังสีดำ และ CSS ที่หายไปอย่างน่าประหลาด แต่กระนั้น`publishSite`สร้างเว็บไซต์เดียวกันได้อย่างไร้ที่ติ ตัวการไม่ใช่ CSS ไม่ใช่เบราว์เซอร์ และไม่ใช่แคช แต่เป็นโค้ด Kotlin เพียงบรรทัดเดียว — และนิสัยที่ไม่ดีในการจัดการอาร์กิวเมนต์บนบรรทัดคำสั่ง
ฉาก: สกรีนช็อตสี่ภาพ, เรนเดอร์สองแบบ
มันเกิดขึ้นหลังระบบล่ม ฉันได้จับภาพหน้าจอไว้สี่ภาพเพื่อเปรียบเทียบการแสดงผลในเครื่อง (./gradlew serve`บน`localhost:8820) ด้วยการแสดงผลแบบออนไลน์ (`publishSite`บน GitHub Pages) สองภาพหน้าจอต่อหน้า : ด้านบนและด้านล่าง
การเรนเดอร์ภายในเครื่อง
กลับขึ้นด้านบน— ปุ่ม Project และ Template เป็นเล็ก, เป็นรูปสี่เหลี่ยมผืนผ้า, ด้วยสีมาตรฐาน (สีน้ำเงินและสีเขียว) การ์ด Start Writing มีพื้นหลังสีดำเรียบ, โดยไม่มีกรอบ
ส่วนท้ายของหน้า— คำบรรยายใต้หัวข้อ "บทความและแหล่งข้อมูลล่าสุด" คือแทบจะอ่านไม่ออก, มืดเกินไปบนพื้นหลังสีดำ วันที่ใต้รูปภาพบล็อก ("17 October 2013" ฯลฯ) เป็นที่ไม่อยู่No text was provided to translate.
แสดงผลออนไลน์
กลับขึ้นด้านบน— ปุ่มเดียวกันนั้นเป็นใหญ่, รูปไข่, สีเขียวนีออนฉูดฉาด, ข้อความเป็นตัวพิมพ์ใหญ่ การ์ดมีกรอบสีขาวมุมมนพร้อมเงาตกกระทบ.
ส่วนท้ายของหน้า— คำบรรยายคืออ่านได้ชัดเจน. วันที่คือที่มองเห็นได้. การ์ดของบทความมีมุมโค้งและชื่อเรื่องคือตัวหนา.
สิ่งแรกที่นึกถึงคือธีม ฉันใช้ระบบธีมแบบไดนามิก (สว่าง มืด คอนทราสต์สูง) โดยอิงจาก`localStorage`. บางที local store อาจทำให้ธีม high-contrast ถูกเรียกใช้งานหรือเปล่า? ไม่ ฉันเขียนไว้แล้วhttps://cheroliv.com/blog/2025/0098_preloading_css_variable_post.html[บทความเต็มเกี่ยวกับการโหลดธีมล่วงหน้า], ฉันรู้ว่ามันทำงานอย่างไร และอีกอย่าง แม้ในโหมด high-contrast โครงสร้าง CSS (ปุ่มวงรี เงา) ก็ควรจะอยู่ตรงนั้น แต่มันกลับไม่อยู่
ความคิดที่สอง: แคชของเบราว์เซอร์ ไม่ ฉันได้ทดสอบด้วยโปรไฟล์ที่สะอาดแล้ว diff ยังคงอยู่
รีเฟล็กซ์ที่สาม:`serve`ไม่ได้ให้บริการไฟล์เดียวกันกับ`publishSite`.
การวินิจฉัย: serve ไม่ได้ชี้ไปยังโฟลเดอร์ที่ถูกต้อง
ปลั๊กอิน Gradle ของฉัน`bakery`มีสองภารกิจหลัก:
-
bake: สร้างเว็บไซต์แบบสแตติกใน`build/bake/` -
serve: เริ่มเซิร์ฟเวอร์เว็บภายในเครื่อง -
publishSite: หน่อ`build/bake/`ไปยัง GitHub Pages
ความแตกต่างนั้นสามารถมาจากเพียง`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 รอ…อาร์กิวเมนต์ตามตำแหน่งสำหรับ source และ destination แล้วตามด้วย flags ที่ไม่บังคับ ซิกเนเจอร์คือ :
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`ดังนั้นบิลด์จึงถูกเขียนทับหรือถูกละเลย และเป็น CSS เริ่มต้นเก่า (ที่ไม่มีตัวแปร custom ไม่มีมุมโค้ง ไม่มีเงา) ที่ถูกเสิร์ฟ
เมื่อเปรียบเทียบแล้ว`bake` et publishSite`ใช้ปลั๊กอิน Gradle JBake อย่างเป็นทางการ(`jbake-gradle-plugin) ที่เขียนอย่างเรียบร้อยใน`build/bake/`ผ่าน Gradle API พวกเขาไม่ได้ผ่าน CLI
วิธีแก้: อาร์กิวเมนต์แบบตำแหน่ง ไม่ใช่แฟล็ก
การแก้ไขเป็นเรื่องง่ายดาย — เมื่อรู้แล้ว ก็เพียงส่ง source และ destination เป็นอาร์กิวเมนต์แบบตำแหน่ง แล้ว`-s`สุดท้ายนี้:
args = listOf(
file(site.bake.srcPath).absolutePath,
layout.buildDirectory.get()
.asFile.resolve(site.bake.destDirPath)
.absolutePath,
"-s"
)
แค่นั้นเอง เปลี่ยนแค่สามบรรทัด บั๊กก็แก้แล้ว
หลังจากเผยแพร่ปลั๊กอินในเครื่องแล้ว (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 "AVANT (bug)" {
RECTANGLE JBakeCLI1 {
+ args = ["-b", "site", "-s", "build/bake"]
}
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 "APRÈS (fix)" {
RECTANGLE JBakeCLI2 {
+ args = ["site", "build/bake", "-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`มีขนาด 31 402 ไบต์พอดี — เหมือนกับไฟล์ที่สร้างโดย`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 ไม่ได้แครช มัน "ทำงาน" อยู่ เพียงแต่ใช้โฟลเดอร์ผิด
-
บิลด์ทำงานได้ :
./gradlew bake`สร้างไฟล์อย่างถูกต้องใน`build/bake/. -
การปรับใช้ทำงานอยู่:`publishSite`ผลักดันเนื้อหาที่ดีไปยังออนไลน์
-
มีเพียง
serveเท่านั้นที่เสีย: งานพัฒนา งานที่เราใช้อย่างต่อเนื่องเพื่อวนซ้ำ -
ความเคยชินกับ
-key value: ในฐานะนักพัฒนา พวกเราถูกหล่อหลอมจากประสบการณ์หลายปีกับ CLI Unix (-o output`,-i input). JBake CLI เป็นข้อยกเว้น — source และ destination เป็นอาร์กิวเมนต์แบบระบุตำแหน่ง
บทสรุป
หากคุณดูแลปลั๊กอิน Gradle ที่ครอบ JBake (หรือเครื่องมือ CLI ใด ๆ)อ่านเอกสารของอาร์กิวเมนต์แม้ว่าคุณจะคิดว่าคุณรู้จักพวกเขาแล้วก็ตาม สมมติฐานโดยนัย (-s= "set destination") อาจทำให้คุณเสียเวลาหลายชั่วโมงในการดีบักด้วยภาพ
ตรงนี้ การแก้ไขคือการเปลี่ยน:
args = listOf("-b", src, "-s", dest) // ❌ BUG
en :
args = listOf(src, dest, "-s") // ✅ FIX
ย้ายโทเคนไปสามตัว แล้วเว็บไซต์โลคอลของฉันก็กลับมาสวยเหมือนเว็บไซต์ในโปรดักชันอีกครั้ง
บทเรียน: เมื่อผลลัพธ์การเรนเดอร์แตกต่างกันระหว่าง local กับ prod โดยไม่มีเหตุผลที่ชัดเจน ให้สงสัย pipeline ก่อน — ไม่ใช่ CSS ไม่ใช่เบราว์เซอร์ และยิ่งไม่ใช่เฟรมเวิร์ก มักเป็นขั้นตอนก่อนการเรนเดอร์โดยตรงที่โกง