Mock Data: เมื่อ Framer Motion ต้องการ Client Component ร่วมกับ Next.js 13
เลือกใช้ Next.js เพื่อจะใช้ประโยชน์จาก Server Component แต่ Framer Motion ดันต้องการ Client Component ในการทำ Animation จะทำอย่างไรดี?
เบื้องหลังการสร้าง CrossBoot โปรแกรมสร้าง USB Bootable Windows บน macOS แก้ปัญหาไฟล์เกิน 4GB และเทคนิค Cross-Compile wimlib แบบ Static Linking

เรื่องมันเกิดจาก มี MacBook กับ Desktop PC เครื่องนึง ซึ่งเครื่อง Desktop เดี๋ยวลง Windows เดี๋ยวทำ Hackintosh แล้วแต่อารมณ์ เวียนว่ายตายเกิดอยู่อย่างนั้น LMAO (SSD TBW น่าจะเต็มเอาสักวัน) ไอ้จังหวะจะลง Hackintosh ไม่เท่าไหร่ ทำบน MacBook ได้เลย ชิลลล แต่พอจะลง Windows นี่ดิ หยาบสุดดด! หันซ้าย หันขวา จะทำตัว Windows Setup Bootable ยังไงดี!?
โอเค ระดับ macOS แล้ว เจ้าตลาดเยอะแยะ ไหนดูซิ๊...
เปิดมาก่อนเลยตัวดีตัวดังฝั่ง macOS นั่นคือ balenaEtcher ใครจะเขียน ISO ต้องคุ้นชื่อนี้บ้างแหละ โอเค เตรียมไฟล์ Windows ISO ลงแอปเรียบร้อย เสียบ USB เข้าไป ไหนดูซิ๊ ผ่าม...
It looks like you are trying to burn a Windows image. Unlike other images, Windows images require special processing...
เอ้า พี่แกอยู่มานาน กลับไม่รองรับการเขียน Windows Setup Bootable บน macOS ซะงั้น
เคเลยยย ได้ งั้นไปดูตัวอื่น Ventoy ของดีชาว Linux... ปุ่ม Download สำหรับ macOS อยู่ไหน...??? ไม่มี!
ไม่เป็นไร มี Rufus ตัวดัง ไม่รู้จักนี่เชยยยยย (หยอกกกกกกกก)...
rufus-4.12.exe
rufus-4.12p.exe
rufus-4.12_x86.exe
rufus-4.12_arm64.exe
...
macOS อยู่ไหนนนนน!!! 🤦🏻♂️
ส่วน Tools ติดเครื่องอย่าง Bootcamp ก็ไม่สามารถเปิดขึ้นมาใช้งานบน Mac Apple Silicon ได้เลย
ในเมื่อ GUI ไม่มี ก็ต้องกลับสู่สามัญด้วย Command Line
ขั้นแรกลง HomeBrew (ฉายา "The Missing Package Manager for macOS")
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
เช็คหน่อยว่าลงเรียบร้อยดีไหม
brew -v
ลง HomeBrew เสร็จแล้วก็ลง wimlib ต่อ
brew install wimlib
เช็ค wimlib สักหน่อย ถ้าขึ้น Option ต่าง ๆ แสดงว่าลงเรียบร้อยดี
winlib --help
จากนั้นก็ไป Format USB ให้เรียบร้อย จะผ่าน Disk Utility หรือ Terminal ก็ได้ตามสะดวกเลย แต่ต้อง Format เป็น MS-DOS (FAT32) นะ
จากนั้นก็ไป Mount ไฟล์ ISO Windows ที่เราเตรียมไว้ ดับเบิ้ลคลิกที่ไฟล์ ISO ได้เลย ก็จะเห็นไฟล์ต่าง ๆ ใน ISO
ถามว่าคัดลอกทั้งหมดไปเลยได้ไหม ตอบเลยว่า ไม่!! เพราะไฟล์ install.wim มันใหญ่เกิน 4GB ซึ่ง FAT32 รองรับไฟล์ขนาดไม่เกิน 4GB
แล้วทำไม่ใช้ ExFAT? เพราะแทบทุกบอร์ดไม่สามารถ Boot จาก ExFAT ได้ เอาจริงมันก็มีวิธีทำ ExFAT ให้ Boot ได้แหละ แต่ต้องทำ Bootloader เพิ่มเติม ซึ่งมันจะไม่ผ่าน Secure Boot โดย Defualt ซึ่งไม่ต้องการแบบนั้น
แล้วต้องทำไง?
บ้าน ๆ เลย ก็นั่งคัดลอกทุก File, Folder ยกเว้น install.wim ที่อยู่ในโฟลเดอร์ sources ไปลง USB ให้เรียบร้อยก่อน ถ้าขี้เกียจคัดลอกเองก็ใช้คำสั่ง
rsync -avh --exclude=sources/install.wim /Volumes/[ISO_NAME]/ /Volumes/[USB_NAME]/
มันก็จะคัดลอกทุกอย่างไปให้ ยกเว้นไฟล์ install.wim ที่มีขนาดใหญ่เกิน 4GB
จากนั้นก็มาจัดการกับไฟล์ install.wim กันต่อ
wimlib-imagex split /Volumes/[ISO_NAME]/sources/install.wim /Volumes/[USB_NAME]/sources/install.swm 3800
มันก็จะทำการ Split ไฟล์ install.wim ให้เป็นไฟล์ย่อย ๆ ขนาดไม่เกิน 3800MB แล้วก็ไปวางไว้ในโฟลเดอร์ sources ของ USB ให้เรียบร้อย เป็นอันเสร็จ
แต่นับดูว่ากี่ขั้นตอน แถมจะพิมพ์ผิดพิมพ์ถูกอีก ยิ่งถ้าเป็น End User นะ แค่เห็น Terminal ก็โบกมือบ้าย บายแล้ว 👋🏻
ใครขยันทำพิมพ์ผ่าน Terminal เองตลอด ๆ ก็เอาเลย But not me
Note: จริง ๆ จะมีวิธีใช้คำสั่ง dd เพื่อเขียน ISO ลง USB โดยตรง แต่ไม่แนะนำสำหรับ Windows ISO เพราะมันจะเป็น System Partition แบบ CD ทำให้หลาย ๆ บอร์ดไม่สามารถ Boot ได้
ถ้าไม่อยากมานั่งทำผ่าน Terminal เองตลอด ก็ทำ GUI macOS App มีหน้าตาจิ้ม ๆ ทำเองให้หมด ไม่ต้องมานั่งพิมพ์เองให้เสียเวลา กดแล้วไปกินกาแฟรอเลย
โจทย์คือ ต้องรองรับ Secure Boot โดยไม่ต้องทำการเพิ่ม Secure Boot Key เองใน BIOS/UEFI ฉนั้นเราจะไม่ยุ่งกับ Bootloader เลย เลิกคิดไปใช้ ExFAT ได้เลย เราจะอยู่กับ FAT32 ที่เป็น Recommended และต้องรองรับการ Boot ทั้ง UEFI, Legacy BIOS แถมอีกเรื่องคือต้องทำ Windows 11 Requirements Bypass ได้
จริง ๆ ในใจอยากเขียนเป็น Native App แต่ก็ต้องใช้เวลาเรียนรู้ใหม่หมด เพราะไม่เคยจับ Swift เลย แถม Learning Curve มันก็ประมาณนึงแหละ แค่ SwiftUI ไม่พอ ต้องไปดูเรื่อง UIKit อีก (ขอสาป SwiftUI เหมือนภาษาที่เขียนไม่เสร็จสักที)
ด้วยความที่ตัวเองถนัดเรื่อง Web Dev อยู่เป็นทุนเดิม เลยเทใจไปให้ Electron (ที่ทุกคนรัก 55555555) ตอนเลือกก็ไม่ค่อยคิด พอมาใช้จริง Bundle Size ใหญ่ทะลุโลกมากกกกกก
Electron + React + SCSS ด้วยความใช้ React มาก่อน กับถนัดเขียน SCSS ก็เลยเลือกใช้สองตัวนี้แหละ เปิด Figma ขึ้นมา นึกแล้วนึกอีก จะ Design ออกมายังไงดี จะให้มันพ่นข้อความออกมาเยอะ ๆ สาย Geek น่าจะชอบ เห็นว่าทำอะไรอยู่ แต่คิดไปคิดว่ามันก็รกไปเปล่า ๆ เลยเอา Concept ของ Apple มาใช้
เน้นน้อย ๆ เรียบง่าย มีเท่าที่ต้องใช้จริง ๆ - Apple น่าจะไม่ได้กล่าว
จึงได้หน้าตาออกมาเป็น
มีส่วนสำหรับเลือกไฟล์ ISO แต่คิดว่าถ้า User มีไฟล์ใน Finder ใกล้มืออยู่แล้ว ทำ Drop Zone ด้วยก็น่าจะง่ายดี ไม่ต้องไป Browse Finder อีก ด้วยที่ Electron มันก็คือ Chrome ตัวนึงนี่แหละ มันก็คือ Browser ฉบับย่อส่วน การทำงานทั้งหมดก็จะเหมือน Browser เลย ก็เขียนรับไฟล์มาปกติ... ไม่ได้ Path เต็ม เลยต้องใช้ Electron สื่อสารผ่าน IPC เพื่อให้ทำงานระดับ System Level ได้ ขอบคุณ Claude AI มาก ช่วยได้เยอะเลย
เลือก ISO เสร็จก็เลือก USB ที่ต้องการ ปัญหาเดิมเลย ต้องผ่าน IPC เพื่อจะได้รายชื่อ USB ที่เสียบอยู่ได้ แถมยังจะติด macOS Permission อีก ได้แล้วก็มาทำเป็น Drop Down ให้ User เลือกได้ง่าย ๆ
ทำ Auto Refresh เมื่อเสียบ USB หรือถอด USB ออกยังไง หาข้อมูลได้ก็ไปเจอตัว usb-detection แต่ด้วยที่ต้อง Compile แล้วมันไม่ผ่าน ทำไงก็ไม่ผ่าน (อาจจะเพราะเป็น Apple Silicon ด้วยมั้ง) สรุปก็เลยไม่ได้ใช้ ทำปุ่ม Refresh ให้ User กดเอาเองละกัน แหะ ๆ
ด้วยความที่อยากให้มันใช้งานง่าย เหมาะกับทุกเพศทุกวัย เลยยุบทุกอย่างให้เหลือปุ่มเดียว ทำงานรวดเดียวจบ เมื่อเลือก ISO กับ USB เสร็จแล้ว ค่อย Active ปุ่มให้ User กด Create
เมื่อกด Create ก็จะทำการ Format Disk ที่ต้องการให้เป็น FAT32 จากนั้นคัดลอกไฟล์ต่าง ๆ จาก ISO ไปยัง USB ให้เรียบร้อย ยกเว้น install.wim
เนื่องจากไฟล์ install.wim มีขนาดใหญ่เกิน 4GB ซึ่งเป็นข้อจำกัดของ FAT32 จึงต้องทำการ Split ไฟล์ install.wim ให้เป็นไฟล์ย่อย ๆ ก่อน โดยใช้ wimlib-imagex split
ตอนแรกก็สั่งง่าย ๆ คล้าย ๆ
wimlib-imagex split /Volumes/[ISO_NAME]/sources/install.wim /Volumes/[USB_NAME]/sources/install.swm 3800
ปัญหาที่เจอหลัก ๆ เลยคือ ด้วยที่ USB มันช้า ถึงแม้จะเป็น USB 3 ก็ตาม (เมื่อ USB Drive Cache เต็ม มันก็จะช้าลงสุด ๆ) ทำให้ wimlib มันทำการ Split แล้วหยุดรอ Disk I/O วนอยู่อย่างนั้น Split ก็ไม่เสร็จ เขียนก็ไม่เสร็จ
เลยเปลี่ยนให้ wimlib ทำการ Split ไว้ใน Temp Directory ก่อน แล้วค่อยคัดลอกไฟล์ .swm ไปยัง USB ทีเดียว ทำให้ Split ได้เร็วมาก ๆ หลังจากนั้นก็รอเขียนอย่างเดียว
แน่นอนว่ายังไงก็ต้องมี Progress Bar ให้ User ดูว่ามีการเขียนไฟล์อยู่กี่ % แล้ว ไม่ใช่ว่าค้างไปดื้อ ๆ โดยแบ่งเป็น 2 ช่วงหลัก ๆ คือ Split และ Write
ช่วง Split จะใช้เวลาไม่นานจะให้ Progress Bar อยู่ในช่วง 0-15% ซึ่งเราสามารถดึงค่าการ Split จาก wimlib ได้โดยตรง ส่วนช่วง Write จะให้เป็น 15-100% เนื่องจากใช้เวลาพอสมควร
แน่นอนว่าการเขียนลง Temp Directory หาก User ยกเลิกกลางทาง หรือ App Crash กลางทาง หรืออะไรก็ตาม จะทำให้ File ที่ Split ไว้ใน Temp Directory ค้างอยู่ ซึ่งจะกินพื้นที่มาก ๆ แถม User เข้าไปลบยากด้วยเนื่องจากเป็น Hidden Folder และอยู่ใน Directory ที่ไม่คุ้นเคย
จึงต้องมีการจัดการ Cleanup หลังการใช้งานทุกครั้ง แต่การ Cleanup หลังจากทำงานเรียบร้อยยังไม่พอ ไหนจะกรณีที่ User ทำการ Force Close หรืออะไรก็ตามระหว่างทางมันจะไม่เข้า Cleanup Function จึงต้องทำการ Cleanup ทุกครั้งที่เปิดใช้งานด้วย
แน่นอนว่าการจะ Split ไฟล์ install.wim ยังไงก็หนีไม่พ้นต้องใช้ winlib ซึ่ง pre-build บน macOS มีให้ใช้ผ่าน HomeBrew เท่านั้น ส่วนหน้าเว็บจะมีเฉพาะ Windows
โอเค ไม่ยาก ลงใน HomeBrew แล้วไปจิ๊กไฟล์ bin ออกมา ไม่ยากใช่มั้ยล้าาาาา... ตอบเลยว่าทำแบบนี้ไม่ได้ เนื่องจาก bin ที่ดึงออกมาจาก HomeBrew ตรง ๆ จะเป็น Dynamic Library ซึ่งมันจะผูก Linking ไปยัง winlib HomeBrew ของเครื่องที่ไปดึง winlib มา ตอนแรกไม่รู้เรื่อง แจกให้คนอื่นลองใช้ แตกกกกก
บนหน้าเว็บ wimlib จะมี Source Code แล้วมา Compile เอง ให้โหลดมาเตรียมไว้เลย แตกไฟล์ให้เรียบร้อย แล้วเปิด Terminal เข้าไปใน Directory ที่แตกไฟล์แล้ว หรือจะดึง Source Code ผ่าน Git ก็ได้
git clone https://wimlib.net/git/wimlib
cd wimlib
เตรียม Environment สำหรับ Compile ตัว wimlib
brew install autoconf automake libtool pkg-config
สร้าง Config (Bootstrap) คำสั่งนี้จะไปอ่านไฟล์ตั้งต้น แล้วสร้างไฟล์ configure ให้
./bootstrap
Clean Build เดิม ล้างค่า config เก่าก่อนเสมอ เพื่อกันความผิดพลาด
make distclean
Configure & Compile
./configure \
./configure \
--host=arm-apple-darwin \
--disable-shared \
--enable-static \
--without-ntfs-3g \
--without-fuse \
--without-libarchive \
CFLAGS="-arch arm64 -mmacosx-version-min=11.0"
make -j$(sysctl -n hw.ncpu)
ตรงนี้จะ Complie ลงไปต่ำกว่า macOS 11 ไม่ได้ (ได้ก็ไม่มีประโยชน์) เพราะ Mac ที่เป็น Apple Silicon เปิดตัวมาพร้อมกับ macOS 11
--disable-shared --enable-static คือ Flag ที่สั่งให้ตัว compile ไม่สร้าง Dynamic Library (.dylib) แต่ให้ฝัง Library ที่จำเป็นเข้าไปในตัวโปรแกรมเลย (Static Linking) ทำให้เอาไปรันเครื่องอื่นได้โดยไม่ต้องลง lib เพิ่ม
จะได้ไฟล์ wimlib-imagex ออกมา แนะนำเปลี่ยนชื่อก่อนเป็น wimlib-arm64 เดี๋ยวเราจะรวม arm กับ x86_64 ด้วยกันอีกที
mv wimlib-imagex wimlib-arm64
Clean Build เดิมอีกครั้ง
make distclean
Configure & Compile
./configure \
--host=x86_64-apple-darwin \
--disable-shared \
--enable-static \
--without-ntfs-3g \
--without-fuse \
--without-libarchive \
CFLAGS="-arch x86_64 -mmacosx-version-min=11"
make -j$(sysctl -n hw.ncpu)
ตรงนี้จะ Compile ให้ต่ำกว่า macOS 11 ก็ได้ แล้วแต่จะเอาไปใช้งานเลย เพื่อให้ครอบคลุมเครื่องรุ่นเก่าๆ
แนะนำเปลี่ยนชื่อก่อนเป็น wimlib-x86
mv wimlib-imagex wimlib-x86
ตอนนี้เรามี binary 2 ตัว แยกกันทำงาน เราจะจับมารวมเป็นไฟล์เดียวที่เรียกว่า "Fat Binary" หรือ Universal Binary
lipo -create -output wimlib-imagex wimlib-arm wimlib-x86
ตรวจสอบความเรียบร้อยของ binary ว่าเป็น Universal Binary หรือไม่
file wimlib-imagex
# ควรได้ผลลัพธ์: Mach-O universal binary with 2 architectures: [x86_64] [arm64]
และที่สำคัญคือ ต้องตรวจสอบว่า binary ที่ Compile ออกมาเป็น Static Linking หรือไม่
otool -L wimlib-imagex
# ควรเจอแค่: /usr/lib/libSystem.B.dylib
ถ้าได้ตามนี้คือเรียบร้อย ยินดีด้วย จบการ Cross-Compile และทำ Static Linking แล้ว แค่นี้ก็สามารถเอา Binary นี้ไป Bundle ใน App ได้เลย
ล่าสุดย้ายไป SwiftUI แล้ว Build ออกมาเล็กลงเยอะจาก Electron ~100MB เหลือ 5MB
ไปลองเล่นกันได้ที่
A simple tool for creating Windows bootable USB drives on macOS. Supports Secure Boot, UEFI, Legacy BIOS, and Windows 11 bypass.

เลือกใช้ Next.js เพื่อจะใช้ประโยชน์จาก Server Component แต่ Framer Motion ดันต้องการ Client Component ในการทำ Animation จะทำอย่างไรดี?

ประสบการณ์การฝึกงานที่ ClickNext ในตำแหน่ง Frontend Developer ประสบการณ์ไม่มีวันลืม เป็นอย่างไร มีอะไรได้เรียนรู้บ้าง มาดูกัน!