รับมือการใช้ 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 วิธี (อันนี้เท่าที่ลองเองนะครับ) คือ

  1. กำหนดค่า nodeLinker ใน .yarnrc.yml

    ให้เรากำหนดค่าเป็น nodeLinker: "node-modules" และอาจรันคำสั่ง yarn install อีกครั้ง ด้วยการกำหนด nodeLiker ดังกล่าวทำให้ Yarn ทำการติดตั้ง dependencies เอาไว้ที่โฟลเดอร์ node_modules ในโปรเจ็คเราเหมือนเดิม

  2. ใช้ปลักอิน 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 มากกว่าวิธีการแรก