الإجبار · فصل ٥

جرّب الاتفاق وهو بيتكسر

strict · devEngines · onFail · corepack enable npm · CI
🎯 الهدف: تخلي Yarn و npm يقعوا في مشروع pnpm، وتثبّت النسخة في CI من غير ما السيرفر يجيب مدير تاني.

المدير التاني يقع لوحده

بعد corepack use والتفعيل، من جوه المشروع:

terminal
yarn install

الرسالة بالإنجليزي، وفيها مسار الملف اللي اتقرأ:

terminal
This project is configured to use pnpm because /path/to/package.json has a "packageManager" field

الأمر يطلع بغير صفر. ملف yarn.lock مش هيتعمل. نفس الكلام لو الحقل Yarn وكتبت pnpm. المسار في الرسالة هو الملف الحاكم، حتى لو أنت واقف في فولدر تحته.

ده إجبار الاسم. النسخة متجبرة لأن الوسيط مش هيشغّل غير الرقم اللي بعد @. بس ده workflow guard مش سور أمان: مطور متعمد يقدر يتخطى الـ shim أو يطفي strict mode.

devEngines شرط زيادة

الحقل ده مش بدل packageManager. هو فحص توافق. onFail يقول يحصل إيه لو الاسم أو النسخة مش ماشيين مع المطلوب.

package.json
{  "packageManager": "pnpm@10.15.0",  "devEngines": {    "packageManager": {      "name": "pnpm",      "version": "10.15.0",      "onFail": "error"    }  }}

onFail قيمته error أو فاضي: اختلاف يوقف الأمر. warn يطبع ويكمل. ignore يسكت. الاتنين لازم يتفقوا: لو packageManager يقول yarn و devEngines يقول pnpm، Corepack يرفض. ولو النسخة المكتوبة مش جوّه المطلوب في devEngines، يرفض برضه.

متستخدمش مدى في devEngines وأنت عايز نسخة واحدة للأبد. المدى بيتسأل للريجستري. حط نفس الرقم في المكانين.

packageManager هو الرقم اللي هيشتغل. devEngines هو الشرط اللي يصرخ لو الرقم أو الاسم مش هما.

npm لسه الباب الخلفي

طالما corepack enable npm ما حصلش، npm install بيستخدم npm بتاع Node ومش بيسأل Corepack. قفل Yarn مش قفل للباب ده.

terminal
corepack enable npmnpm install

بعد التفعيل، npm الوسيط يشوف الحقل. مشروع pnpm يرفض npm install زي ما رفض yarn.

حزام تاني، لو جهاز في الفريق مش مفعّل shim لـ npm: سكربت preinstall بحزمة only-allow. npm و pnpm بيشغّلوا preinstall قبل التثبيت. الحزمة تخرج بغير صفر لو اسم المدير الحالي مش pnpm.

package.json
{  "scripts": {    "preinstall": "npx only-allow pnpm"  }}

الحزام ده مش بديل عن الحقل. هو يمسك اللي عدّى من غير shim. الحقل هو اللي يختار النسخة.

في متغير COREPACK_ENABLE_STRICT=0 يطفي رفض المدير الغلط. متتحطش في CI. دي للتجربة المحلية، وبتخلّي المدير التاني يشتغل بنسخته العامة. عكس الإجبار.

أقرب package.json هو اللي بيحكم

Corepack يطلع من الفولدر الحالي لفوق. لو لقى package.json في الهوم فيه packageManager، ممكن يعتبر كل فولدر تحته جزءًا من المشروع ده.

خلّصت الفصل لما

🧠 اختبر نفسك
١) الحقل pnpm وكتبت yarn. مين اللي بيرفض؟
Corepack، ما دام yarn شغال من الـ shim. الرسالة إن المشروع متظبط على pnpm.
٢) onFail قيمته warn. الاختلاف هيوقف الأمر؟
لأ. هيطبع تحذير ويكمل. الإيقاف عند error أو لما القيمة فاضية.
٣) هل packageManager حماية لا يمكن تجاوزها؟
لأ. هو workflow guard يعتمد على مرور الأمر عبر Corepack، مش security boundary.