อาเพศ Engine “node” is incompatible

Ayuth Mangmesap
Ayuth’s Story
3 min readFeb 5, 2024

--

นั่งทำงานอยู่ดี ๆ มีคุณลูกค้าแชทมาว่า

  • สาว: “ต้นรถเป็นอะไรอะ”
  • หนุ่ม: “รถเสีย สตาร์ทไม่ติดเลยอะ”
  • สาว: “ทำไมไม่ใช้น้ำมัน 2T ดีดีล่ะ เดี๋ยวนี้เขาใช้แต่ไดเกียวกันทั้งนั้นแหละ… เพราะใช้แล้ว”
  • สาว ๆ: (ประสานเสียง) “เครื่องฟิต สตาร์ทติดง่าย”

นั่นมันโฆษณาน้ำมันไดเกียว เอาละพอยิ้มกรุ้มกริ่ม เรามาดูความเป็นจริงกันดีกว่า

วันดีคืนดีได้รับข่าวสารทางแชทมาว่าดีพลอยไม่ได้ช่วยดูให้หน่อย … เอาละแค่คำว่า “ดีพลอยไม่ได้” ก็อาเพศแล้วครับ เพราะเรายังนั่งเขียนโค้ดอยู่ในเครื่องตัวเองและปกติสุขทุกอย่าง

สืบไปสืบมาพบว่าที่ลงไม่ได้เพราะว่าเครื่องมันฟ้องว่า

> [deploy 12/12] RUN yarn install --pure-lockfile --non-interactive --production &&    yarn cache clean &&    chmod +x ./entrypoint.sh:
0.297 yarn install v1.22.18
0.309 info No lockfile found.
0.313 [1/4] Resolving packages...
79.71 warning @storybook/nextjs > @storybook/builder-webpack5 > fork-ts-checker-webpack-plugin > memfs@3.6.0: this will be v4
79.71 warning @storybook/nextjs > @storybook/builder-webpack5 > webpack-dev-middleware > memfs@3.6.0: this will be v4
101.0 warning jest-environment-jsdom > jsdom > abab@2.0.6: Use your platform's native atob() and btoa() methods instead
101.1 warning jest-environment-jsdom > jsdom > data-urls > abab@2.0.6: Use your platform's native atob() and btoa() methods instead
101.1 warning jest-environment-jsdom > jsdom > domexception@4.0.0: Use your platform's native DOMException instead
111.2 [2/4] Fetching packages...
150.8 error polished@4.3.0: The engine "node" is incompatible with this module. Expected version ">=20". Got "18.16.0"
150.9 error Found incompatible module.
150.9 info Visit https://yarnpkg.com/en/docs/cli/install for documentation about this command.

คัดเฉพาะส่วนที่สำคัญจะได้ว่า version ของ node มันไม่ตรงตาม requirement ของ dependency ที่ชื่อ polished

error polished@4.3.0: The engine "node" is incompatible with this module. Expected version ">=20". Got "18.16.0"

สืบไปสืบมาพบว่ามี package ตัวหนึ่งที่ใช้ dependency ตัวนี้อยู่ polished อยู่แต่ไม่ทราบเหมือนกันว่าทำไม ไปหาข้อมูลเลยพบว่าเราสามารถหาว่าเพราะอะไรทำไม package นี้ถูก install ได้จากคำสั่ง yarn why <package name> เราก็จะทราบว่ามี lib ตัวไหนใช้เจ้าสิ่งนี้อยู่

➜  $ yarn why polished                                                                                            
├─ @storybook/addon-actions@npm:7.4.6
│ └─ polished@npm:4.2.2 (via npm:^4.2.2)

├─ @storybook/addon-actions@npm:7.4.6 [33d69]
│ └─ polished@npm:4.2.2 (via npm:^4.2.2)

├─ @storybook/addon-interactions@npm:7.4.6
│ └─ polished@npm:4.2.2 (via npm:^4.2.2)

├─ @storybook/addon-interactions@npm:7.4.6 [33d69]
│ └─ polished@npm:4.2.2 (via npm:^4.2.2)

├─ @storybook/blocks@npm:7.4.6
│ └─ polished@npm:4.2.2 (via npm:^4.2.2)

└─ @storybook/blocks@npm:7.4.6 [33d69]
└─ polished@npm:4.2.2 (via npm:^4.2.2)

ปรากฏว่าน้อง @storybook/* ของเรานั่นเอง

เกร็ดความรู้เกี่ยวกับเลข Version ใน Node

ถ้าใครไม่คุ้นพวกเลขเวอร์ชันพวกนี้ขอสรุปให้สั้น ๆ ว่า Node จะมีสิ่งที่เรียกว่า Semantic Versioning หรือขนมธรรมเนียมประเภณีที่ทำให้ตัวเลข 3 ตัวนั้นมีความหมาย และถ้าปฏิบัติตามจะทำให้ดีต่อโลกใบนี้เและ Community เป็นอย่างมาก

Source: https://media.geeksforgeeks.org/wp-content/uploads/semver.png
  1. MAJOR version → จะอัพเวอร์ชันนี้ก็ต่อเมื่อสิ่งที่ package ที่เรา release ไปนั้นทำให้ของเก่าพัง เช่น ลบ deprecated function ออก เปลี่ยนชื่อ API หรือสิ่งอื่นใดที่ทำให้ผู้ใช้เวอร์ชันก่อนหน้านี้ใช้อย่างปกติสุขไม่ได้
  2. MINOR version → อัพ Minor version ก็ต่อเมื่อเราทำ Add feature เข้าไปเพิ่มและทำสิ่งที่เพิ่มเข้าไปไม่ทำให้ API Major ที่เป็นเลขเดียวกันใช้งานไม่ได้
  3. PATCH version → อัพ patch version เมื่อแก้บัคต่าง ๆ

กลับมาดูที่ปัญหาของเรา

ถ้าดูใน log อย่างพินิจพิจารณาแล้วละก็จะเห็นข้อความต่อนหนึ่งความว่า npm:^4.2.2 แน่นอนว่าอ่านแล้วจำไม่ได้หรอกจึงหาตารางใน stackoverflow มาเทียบดู

Source: https://stackoverflow.com/questions/22343224/whats-the-difference-between-tilde-and-caret-in-package-json
polished@npm:4.2.2 (via npm:^4.2.2)

ตีความได้ว่าทุกครั้งที่ yarn install เราจะเอา Minor + Patch version ที่มากกว่า 4.2.2 เสมอ และเวอร์ชันที่ทำให้อาเพศนี้เกิดขึ้นก็คือ polished@4.3

  • ✅ Version: 4.2.2 ไม่พัง
  • ❌ Verison: > 4.3 ที่ required Node.js เวอร์ชัน 20 ขึ้นไป ทำให้ตอน install dependencies ต่าง ๆ บน CI พัง 🫠

วิธีแก้ไข

ถ้าใช้ yarn สามารถกำหนด fixed version ของ sub dendency ได้โดยการใส่ resolution และตามด้วย package version ที่ไม่ทำให้โค้ดเราพัง

// package.json
{
...
"resolutions": {
"polished": "4.2.2"
}
}

จากนั้นทำการ yarn installใหม่อีกครั้งอาเพศต่าง ๆ ก็หายไปในทันที

เรื่องนี้สอนให้รู้ว่า

ถ้าจะ release เวอร์ชันใหม่และ require Node เวอร์ชันที่ใหม่กว่าอย่าอัพใน Minor/Patch version ให้ release มาใน Major version แทน เพราะสิ่งที่เองส่งผลให้ใครก็ตามที่นำ package นี้ไปใช้งานพังได้ง่าย ๆ เลย ตัวอย่างเช่น

  • 4.2.2 → Compatible with Node v18
  • 4.3.0 → Required Node v20 🙅‍♂️ ❌, ควรจะ required Node 20 เมื่อขึ้น Major version เท่านั้น เช่น v5.X.X → Node 20 ✅

อัพเดท 5/2/2024

ระหว่างเขียนบล็อกพยายามหา log + reproduce ให้ได้ error ณ ช่วงเวลาที่เกิดอาเพศตอนนั้นทว่า polished 4.3.0 เหมือนจะหายไปจากหน้าประวัติศาสตร์แล้วครับ และแน่นอนอาเพศเหล่านี้ก็สอนอะไรเราได้หลายอย่างเช่นกัน …

แหล่งอ้างอิง

--

--