ภาพรวมของ ES Modules (ESM) อย่างใกล้ชิด

npm เป็นตัวจัดการแพ็คเกจสำหรับแพลตฟอร์ม node.js JavaScript โดยวางโมดูลไว้เพื่อให้โหนดสามารถค้นหาโมดูลเหล่านั้นได้ และจัดการข้อขัดแย้งในการพึ่งพาอย่างชาญฉลาด

npm สามารถกำหนดค่าได้เพื่อรองรับกรณีการใช้งานที่หลากหลายเพื่อเผยแพร่ ค้นหา ติดตั้ง และพัฒนาโปรแกรมโหนด มีรายการคำสั่งที่ทรงพลัง

npm 8 เปิดตัวเมื่อวันที่ 7 ตุลาคม 2021 ในบทความนี้ เราจะมาดูที่ npm 8 และคาดการณ์ว่า npm 9 อาจเป็นเท่าใด

มีอะไรใหม่ใน npm 8

ไม่มีอะไรใหม่ใน npm 8 จุดประสงค์ของรีลีสนี้คือการยกเลิกการสนับสนุนสำหรับโหนดเวอร์ชันเก่า และเพื่อลบการสนับสนุนสำหรับ require('npm') ไม่มีการเปลี่ยนแปลงที่แตกหักอื่น ๆ โดยเฉพาะอย่างยิ่ง การเปลี่ยนแปลงเหล่านี้คือ:

  • ยกเลิกการรองรับโหนด 10 และ 11
  • เพิ่มเพดานการสนับสนุนในโหนด 12 และ 14 เป็น LTS (^12.13.0/^14.15.0)
  • ยกเลิกการสนับสนุนไปที่ require('npm')
  • อัปเดตการอ้างอิงบางส่วนเนื่องจากการรองรับ node10 และ node 11 ที่ลดลง

มันง่ายและชัดเจน

หากคุณต้องการอัปเกรดเป็น npm 8 ตรวจสอบให้แน่ใจว่า node.js ของคุณอัปเกรดเป็นเวอร์ชัน >=12.0.0 แล้ว nvm เป็นวิธีง่ายๆ ในการจัดการเวอร์ชันสำหรับโหนดและ npm

มีอะไรใหม่ใน npm 9?

คำร้องขอความคิดเห็น (RFC) เป็นเอกสารอย่างเป็นทางการที่ร่างโดย Internet Engineering Task Force (IETF) ซึ่งอธิบายข้อกำหนดสำหรับเทคโนโลยีเฉพาะ npm 8 เป็น RFC ที่ให้สัตยาบัน ซึ่งปัจจุบันเป็นมาตรฐานที่เป็นทางการ

RRFC ของ npm 8 กล่าวถึงข้อเสนอแนะในการเพิ่มเวอร์ชันที่รองรับเป็น ^12.20.0 || ^14.13.1 || >=16.0.0 ซึ่งจะเป็นการย้ายไปยังเวอร์ชัน node.js ที่รองรับโมดูลสไตล์ ESM เนื่องจากไม่ได้สร้าง npm 8 จึงอาจเป็นฟีเจอร์ใน npm 9

CJS กับ ESM

เราได้กล่าวถึงรูปแบบโมดูล JavaScript เช่น CJS, AMD, UMD, ESM, System และ IIFE

CommonJS (CJS) เป็นมาตรฐานที่ node.js ใช้เพื่อห่อหุ้ม JavaScript ในโมดูล CJS ใช้ฟังก์ชัน require() และ module.exports

  • require() เป็นฟังก์ชันที่สามารถใช้เพื่อนำเข้าสัญลักษณ์ไปยังขอบเขตปัจจุบันจากโมดูลอื่น คำสั่ง require สามารถใช้ได้ทุกที่ในโค้ด และโมดูลที่อ้างอิงจะถูกโหลดและประมวลผลพร้อมกัน
  • module.exports เป็นอ็อบเจ็กต์ที่โมดูลปัจจุบันส่งคืนเมื่อจำเป็นในโมดูลอื่น

ES Modules (ESM) กลายเป็นมาตรฐานอย่างเป็นทางการที่ใช้ใน JavaScript นับตั้งแต่ ES2015 มันถูกใช้กันอย่างแพร่หลายในการพัฒนาไคลเอนต์ JavaScript TypeScript ยังถูกนำมาใช้ซึ่งเป็น superset ที่มีประเภทเพิ่มเติมอีกด้วย ESM ใช้คำสั่ง import และ export เพื่อจัดการโมดูล

  • คำสั่ง import แบบคงที่สามารถใช้เพื่อนำโมดูลเข้าสู่ขอบเขตปัจจุบัน dynamic import() ใช้งานได้ตั้งแต่คำสั่ง ES2020 .import สามารถใช้ได้ทุกที่ในโค้ด เนื่องจาก imports ถูกโหลดแบบอะซิงโครนัส ขอแนะนำให้วางไว้ที่ด้านบนของไฟล์
  • ในทางกลับกัน คำสั่ง export สามารถใช้เพื่อทำให้รายการต่างๆ เป็นแบบสาธารณะได้อย่างชัดเจน

CJS เป็นค่าเริ่มต้นสำหรับโหนด

ดังที่เราได้กล่าวไปแล้ว CJS เป็นค่าเริ่มต้นสำหรับโหนด ทำตามขั้นตอนที่อธิบายไว้ใน "แอป React ที่พร้อมใช้งานจริง" เราใช้ "สร้างแอป React" เป็นตัวอย่างในการสำรวจวิธีการทำงานของเซิร์ฟเวอร์โหนด

npx create-react-app react-esm
cd react-esm

ดำเนินการคำสั่ง npm run build และไดเร็กทอรี build ที่สร้างขึ้นจะมีโค้ดที่จะปรับใช้

Express เป็นเฟรมเวิร์กเว็บแอป Node.js ที่เรียบง่ายและยืดหยุ่นสำหรับเว็บและแอปพลิเคชันมือถือ เซิร์ฟเวอร์ Express เป็นตัวเลือกยอดนิยมในการปรับใช้บิลด์ที่ใช้งานจริง

เนื่องจาก Express เป็นส่วนหนึ่งของแอป Create React จึงไม่จำเป็นต้องติดตั้งอีกครั้ง

ตั้งค่าไฟล์การกำหนดค่าสำหรับเซิร์ฟเวอร์ Express ใน server/index.js:

เห็นได้ชัดว่าโค้ดข้างต้นอยู่ในรูปแบบ CJS พร้อมด้วยคำสั่ง require (บรรทัดที่ 1 และบรรทัดที่ 4)

บรรทัดที่ 2 สร้างเซิร์ฟเวอร์ Express

บรรทัดที่ 5–8 ให้บริการหน้าเว็บที่ใช้งานจริง

บรรทัด 10–12 เริ่มต้นเซิร์ฟเวอร์ Express ที่พอร์ต 8080

เรียกใช้ node server และสามารถเข้าถึงอินเทอร์เฟซผู้ใช้ได้ที่ http://localhost:8080

ตั้งค่าโหนดให้รัน ESM

ตอนนี้เราเปลี่ยนรหัสเพื่อใช้ import แทน require()

เรียกใช้ node server และเราเห็นข้อผิดพลาดต่อไปนี้:

คำเตือนที่บรรทัด 10 มีสองวิธี:

  • ตั้งค่า "type": "module" ใน package.json
  • เปลี่ยน server/index.js เป็น server/index.mjs และเรียกใช้ node server/index.mjs

โซลูชันทั้งสองใช้งานได้ นี่คือการแก้ไข package.json (บรรทัด 5):

สำหรับไฟล์ที่ไม่มีนามสกุล จะถือเป็นโมดูล CJS หากไม่มี "type" หรือตั้งค่าประเภทเป็น "commonjs" ในพาเรนต์ package.json จะถือเป็นโมดูล ES หากตั้งค่า "type" เป็น "module"

นอกจากนี้ ไฟล์ที่ลงท้ายด้วย .cjs จะถือเป็นโมดูล CJS และไฟล์ที่ลงท้ายด้วย .mjs จะถือเป็นโมดูล ES

เราตั้งค่า "type" เป็น "module" ตอนนี้โหนดถือว่าไฟล์เป็นโมดูล ES เรียกใช้ node server อีกครั้ง:

มันไม่บ่นเกี่ยวกับ import อีกต่อไป แต่ปัญหา __dirname คืออะไร

__dirname เป็นตัวแปร CJS ซึ่งไม่มีในโมดูล ES สามารถจำลองแบบได้ผ่านทาง import.meta.url

วัตถุ import.meta เปิดเผยข้อมูลเมตาเฉพาะบริบทไปยังโมดูล JavaScript ประกอบด้วยข้อมูลเกี่ยวกับโมดูล เช่น URL ของโมดูล

แก้ไข server/index.js ดังนี้:

เรียกใช้ node server และโมดูล ES ทำงานได้อย่างสมบูรณ์

หรืออีกทางหนึ่ง เราสามารถใส่คำนำหน้า node: ได้ ซึ่งในกรณีนี้จะข้ามแคชที่ต้องการ ตัวอย่างเช่น "node:path" (บรรทัด 4) และ "node:url" (บรรทัด 5) จะส่งคืนโมดูล "path" และ "url" ในตัวเสมอ

เราได้เห็นความแตกต่างบางประการระหว่าง CJS และ ESM ต่อไปนี้เป็นรายการเกี่ยวกับวิธีการแปลงไฟล์ CJS เป็นโมดูล ES:

  • ไม่ require, exports หรือ module.exports—ใช้ import หรือ export แทน
  • ไม่ __filename หรือ __dirname ใช้ import.meta.url แทน
  • ไม่มีการโหลดโมดูล JSON — ใช้ import.meta.url กับ fs แทน
  • ไม่มีการโหลดโมดูลดั้งเดิม — ใช้ module.createRequire() หรือ process.dlopen แทน
  • ไม่ require.resolve ใช้ new URL('./local', import.meta.url) แทน
  • ไม่ NODE_PATH — ใช้สัญลักษณ์แทน
  • ไม่ require.extensions — ห้ามใช้
  • ไม่ require.cache — ห้ามใช้

บทสรุป

npm 8 ยกเลิกการรองรับโหนด 10 และ 11

คุณคิดอย่างไรเกี่ยวกับ npm 9? ควรยกเลิกการรองรับเวอร์ชันโหนดที่ไม่รองรับโมดูล ES หรือไม่

หลังจากประสบปัญหากับไวยากรณ์ที่แตกต่างกันสำหรับไคลเอ็นต์และเซิร์ฟเวอร์ JavaScript ไม่ใช่เรื่องน่าตื่นเต้นหรือไม่ที่เห็นว่า ESM ได้รับสตรีมเพื่อใช้สำหรับทั้งไคลเอ็นต์และเซิร์ฟเวอร์

ถึงเวลาแล้วที่จะใช้โมดูลสไตล์ ESM ในแอปพลิเคชันโหนด

ขอบคุณที่อ่าน. ฉันหวังว่านี่จะเป็นประโยชน์ หากคุณสนใจ โปรดดูที่ บทความสื่ออื่น ๆ ของฉัน