รับมือการใช้ Yarn Pnp บน Rails
ปัญหาของ node_modules ทำให้ Yarn เองก็ได้รับการพัฒนาการกลไกการจัดเก็บ dependencies ต่างๆ ให้ดีขึ้น ซึ่งถูกเรียกว่า Plug’n Play โดยเราจะได้ใช้งานกลไกนี้เป็นค่าพื้นฐานเมื่อติดตั้งเวอร์ชันมากกว่า 2.0 ขึ้นไป
เอ๊ะ! แล้วกลไก Plug’n Play มันกระทบกับโปรเจ็ค Rails ของเราอย่างไร สำหรับบทความนี้เราจะโฟกัสกับ Rails 7 ที่ใช้งานร่วมกับ jsbundling-rails โดยเลือกใช้ esbuild เป็นตัวคอมไพล์และบันเดิลโค้ด
ถ้าเราลองสร้างโปรเจ็คง่ายๆ ที่แค่ใช้ Stimulus และ Turbo เพียงเท่านั้นตามคำสั่ง rails new myapp -j esbuild -a propshaft
จากนั้นก็ทำการคอมไพล์ JavaScript ด้วยคำสั่ง yarn run build
ปรากฏว่าเจ้า esbuild จะพ่น error ออกมาว่าหา @hotwired/turbo-rails และ @hotwired/stimulus ไม่พบ
Error
เพราะอะไรกันถึงเป็นแบบนี้ ทั้งๆ ที่ก่อนหน้านี้เราก็ทำเหมือนเดิมทุกอย่าง เมื่อลองไปตรวจสอบโฟลเดอร์ของโปรเจ็คดู ก็พบว่าโฟลเดอร์ node_modules ที่ควรจะมีอยู่หายไป นั้นเป็นเพราะกลไก Plug’n Play จะไม่สร้างโฟลเดอร์ node_modules เก็บไว้ในโปรเจ็คเราอีกต่อไป จึงส่งผลให้ esbuild ไม่สามารถค้นหา dependencies ที่ใช้เจอ
Project Directory
จากที่ได้ทดลองหาวิธีแก้ปัญหา เราสามารถทำได้ 2 วิธี (อันนี้เท่าที่ลองเองนะครับ) คือ
-
กำหนดค่า nodeLinker ใน
.yarnrc.yml
ให้เรากำหนดค่าเป็น
nodeLinker: "node-modules"
และอาจรันคำสั่งyarn install
อีกครั้ง ด้วยการกำหนด nodeLiker ดังกล่าวทำให้ Yarn ทำการติดตั้ง dependencies เอาไว้ที่โฟลเดอร์ node_modules ในโปรเจ็คเราเหมือนเดิม -
ใช้ปลักอิน esbuild-plugin-pnp
แทนที่จะไปแก้ไขที่ตัวอย่างวิธีการนี้จะเป็นการเพิ่มเติมความสามารถให้กับ esbuild เพื่อให้ไปค้นหา dependencies จากโฟลเดอร์ที่ถูกต้องแทนการค้นหาจากโฟลเดอร์ node_modules ในโปรเจ็ค
// esbuild.js const { build } = require('esbuild') const { pnpPlugin } = require('@yarnpkg/esbuild-plugin-pnp') build({ entryPoints: ['./app/javascript/application.js'], outdir: './app/assets/builds', ... plugins: [ pnpPlugin() ] }) .then(() => { console.log(`⚡ Build Done!!!`) }) .catch(() => process.exit(1))
ไม่ว่าจะเลือกวิธีใดวิธีการหนี่งเราก็สามารถจะคอมไพล์และบันเดิลโค้ดของเราได้ตามปกติเหมือนเดิม เพียงแต่อยากจะแนะนำวิธีการที่ 2 มากกว่าวิธีการแรก