Node.js بدون وحدات node_modules

في الأسبوع الماضي ، أعلن مطورو Yarn (مدير الحزم لـ Javascript) عن ميزة جديدة - تثبيت Plug'n'Play. تتيح لك هذه الميزة تشغيل مشاريع Node.js دون استخدام مجلد node_modules ، حيث يتم تثبيت تبعيات المشروع عادةً قبل البدء. يوضح وصف الميزة أنه لن تكون هناك حاجة إلى node_modules - سيتم تحميل الوحدات من ذاكرة التخزين المؤقت العامة لمدير الحزم.


في الوقت نفسه ، أعلن مطورو NPM أيضًا عن حل مماثل للمشكلة.


دعونا نلقي نظرة فاحصة على هذه الحلول ومحاولة اختبارها في مشاريع حقيقية.


تاريخ المشكلة


في البداية ، كان نظام NodeJS المعياري يعتمد بالكامل على نظام الملفات. require() تعيين أي استدعاء require() لنظام الملفات. لتنظيم وحدات الطرف الثالث ، تم اختراع مجلد node_modules ، حيث يجب تنزيل الوحدات والمكتبات القابلة لإعادة الاستخدام وتثبيتها. وهكذا ، تلقى كل مشروع مجموعته المستقلة من التبعيات ، مما أدى إلى إهدار مساحة القرص بشكل غير فعال.


يستغرق تثبيت التبعية معظم وقت البناء في أنظمة CI ، لذا فإن تسريع هذه الخطوة سيؤثر بشكل إيجابي على وقت البناء ككل.


مبسط ، يتكون تركيب الوحدات من الخطوات التالية:


  1. يتم حساب الإصدار المحدد من الوحدة من الفاصل الزمني الصحيح.
  2. يتم تنزيل جميع وحدات الإصدارات المطلوبة من المستودع وتخزينها في ذاكرة التخزين المؤقت المحلية
  3. يتم نسخ الوحدات من ذاكرة التخزين المؤقت المحلية إلى مجلد المشروع node_modules

إذا تم بالفعل تحسين الخطوتين الأوليين بما فيه الكفاية وتم تنفيذهما بسرعة ، عندما يكون لديك بالفعل وحدات تخزين مؤقت ، فإن الخطوة الثالثة تظل دون تغيير تقريبًا مقارنة بالإصدارات الأولى من العقدة و npm.


يقترح النهج الجديد التخلص من الخطوة الثالثة واستبدال النسخ الفعلي للملفات بإنشاء جدول يقوم بتعيين الوحدات المطلوبة إلى نسخها في ذاكرة التخزين المؤقت المحلية.


باستخدام الارتباطات الرمزية


بدلاً من نسخ الوحدات فعليًا ، يمكنك إضافة ارتباط رمزي إلى موقعها في ذاكرة التخزين المؤقت. يتم تطبيق هذا النهج في PNPM ، مدير حزم بديل آخر. قد يعمل النهج بشكل جيد ، ولكن مع الارتباطات الرمزية ، هناك العديد من المشاكل المرتبطة بالموقع المزدوج للملف ، والبحث عن الوحدات المجاورة ، إلخ. بالإضافة إلى ذلك ، إنشاء الروابط الرمزية هو عملية ملف أود تجنبها بطريقة مثالية للعمل.


محاولة غزل PNP


يمكنك قراءة المزيد عن هذه الميزة في الوصف الرسمي . تحتوي هذه الفقرة على روايته القصيرة.


إصدار الغزل الذي يدعم PNP موجود الآن في غزل ميزة pnp .


نقوم باستنساخ المستودع محليًا بالفرع المطلوب


 git clone git@github.com:yarnpkg/yarn.git --branch yarn-pnp 

تعليمات تجميع الخيوط هنا ، مجموعة الخطوات تافهة للغاية.


بعد اكتمال البناء ، أضف اسمًا مستعارًا إلى الإصدار المخصص من الغزل وابدأ العمل معه:


 alias yarn-local="node $PWD/lib/cli/index.js" 

تم تمكين Plug'n'play بطريقتين: إما من خلال العلامة: yarn --pnp ، أو من خلال تكوين إضافي في package.json : "installConfig": {"pnp": true} .


على سبيل المثال ، أعد مطورو الغزل بالفعل مشروعًا تجريبيًا . لديها Webpack ، بابل وأدوات أخرى نموذجية للواجهة الأمامية الحديثة. دعونا نحاول تأسيس تبعياتها بطرق مختلفة ونحصل على النتائج التالية:


  • تركيب yarn نموذجي: 19s
  • التثبيت عن طريق yarn --pnp : 3s

قبل القياس ، تم إجراء تثبيت بارد واحد بحيث كانت جميع الوحدات الضرورية موجودة بالفعل في ذاكرة التخزين المؤقت.


دعونا نرى كيف يعمل. بعد تثبيت pnp ، يتم إنشاء ملف .pnp.js إضافي في جذر المشروع الذي يحتوي على تجاوز للمنطق الأصلي في فئة الوحدة النمطية المضمنة في Node.js. عن طريق تحميل هذا الملف في الكود الخاص بنا ، نعطي وظيفة require() القدرة على الحصول على وحدات من ذاكرة التخزين المؤقت العامة وعدم النظر في node_modules . جميع أوامر الغزل المدمجة ، مثل yarn start أو yarn test ، تقوم بتحميل هذا الملف مسبقًا بشكل افتراضي ، لذلك لن تحتاج إلى إجراء أي تغييرات على الرمز الخاص بك إذا كنت قد استخدمت بالفعل الغزل من قبل.


بالإضافة إلى وحدات التعيين ، يقوم pnp.js بالتحقق من صحة التبعية الإضافية. إذا حاولت الاتصال require('test') ، بدون تبعية معلن عنها في package.json ، فستحصل على الخطأ التالي: Error: You cannot require a package ("test") that is not declared in your dependencies . يجب أن يزيد هذا التحسين من موثوقية الكود وإمكانية التنبؤ به.


من بين أوجه القصور في النهج الجديد ، تجدر الإشارة إلى أن التكامل الإضافي سيكون مطلوبًا للأدوات التي عملت مباشرة مع دليل node_modules بدون آليات العقدة المدمجة. على سبيل المثال ، سيحتاج Webpack ومنشئو الواجهة الأمامية الإضافيون إلى مكونات إضافية إضافية حتى يتمكنوا من العثور على الملفات اللازمة للتجميع.


في المشروع التجريبي ، هناك رسومات تخطيطية لمحللات Eslint و Jest و Rollup و Webpack.


في تجربتي ، لا تزال هناك مشكلات في Typescript ، والتي ترتبط ارتباطًا وثيقًا بوجود وحدات العقدة وليس هناك طريقة سهلة لتجاوز استراتيجية البحث عن الوحدة النمطية.


ستكون هناك أيضًا مشاكل في البرامج النصية postintall. نظرًا لأن الوحدة النمطية لا تزال في ذاكرة التخزين المؤقت ، يمكن أن تؤدي البرامج النصية لما بعد التثبيت التي تغير حالتها (على سبيل المثال ، تحميل ملفات إضافية) إلى تلف ذاكرة التخزين المؤقت وكسر المشاريع الأخرى التي تعتمد عليها. يوصي مطورو الخيوط بتعطيل تنفيذ البرنامج النصي باستخدام علامة --ignore-scripts . لقد جربوا بالفعل تشغيل هذا العلم افتراضيًا لجميع المشاريع داخل Facebook ولم يجدوا أي مشاكل خطيرة. على المدى الطويل ، يبدو أن التخلي عن البرامج النصية لـ postinstall خطوة جيدة في ضوء المشكلات الأمنية المعروفة.


جرب تجربة NPM


كما أعلن فريق الآلية الوقائية الوطنية عن حل بديل له. أداتهم الجديدة ، tink ، تأتي مع وحدة منفصلة منفصلة للآلية الوقائية الوطنية. يتلقى Tink ملف package-lock.json يتم إنشاؤه تلقائيًا عند npm install . استنادًا إلى ملف القفل ، يقوم tink بإنشاء ملف node_modules/.package-map.json ، الذي يخزن إسقاط الوحدات المحلية في موقعها الفعلي في ذاكرة التخزين المؤقت.


على عكس Yarn ، لا يوجد ملف ربط يمكن تحميله مسبقًا في مشروعك لإصلاحه. بدلاً من ذلك ، يُقترح استخدام الأمر tink بدلاً من node للحصول على البيئة المناسبة. هذا الأسلوب أقل راحة لأنه سيتطلب تعديلات على التعليمات البرمجية لجعلها تعمل. ومع ذلك ، كما سيفعل إثبات صحة المفهوم.


لقد حاولت مقارنة سرعة تثبيت الوحدات npm ci و tink ، ولكن تينك كان أبطأ ، لذلك لن أعطي النتائج. من الواضح أن هذا المشروع أكثر الخام مقارنة بالغزل وغير محسن على الإطلاق. حسنًا ، سننتظر الإصدارات الجديدة.


الخلاصة


يعد رفض دليل node_modules خطوة منطقية ، نظرًا لتجربة اللغات الأخرى ، حيث لم يكن هذا النهج موجودًا في البداية. سيؤثر هذا بشكل إيجابي على سرعة البناء مع أنظمة CI ، حيث يمكن حفظ ذاكرة التخزين المؤقت للحزمة بين الإصدارات. بالإضافة إلى ذلك ، إذا قمت بنقل ذاكرة التخزين المؤقت .pnp.js وملف .pnp.js من جهاز كمبيوتر إلى آخر ، يمكنك إعادة إنتاج البيئة حتى بدون بدء تشغيل Yarn. يمكن أن يكون هذا مفيدًا في أنظمة بناء الحاويات: قم .pnp.js الدليل باستخدام ذاكرة التخزين المؤقت ، ووضع ملف .pnp.js ، ويمكنك تشغيل الاختبارات على الفور.


يبدو المنهج الجديد غير عادي ويكسر بعض الممارسات الراسخة بناءً على حقيقة أن جميع الوحدات متوفرة دائمًا في وحدات العقدة. لكن ملف .pnp.js يقدم واجهة برمجة تطبيقات تسمح لك .pnp.js من الموضع الحقيقي للملفات والعمل مع الشجرة الافتراضية. بالإضافة إلى ذلك ، كملاذ أخير ، هناك أمر yarn unplug --persist يستخرج وحدة من ذاكرة التخزين المؤقت node_modules محليًا في node_modules .


على أي حال ، لم يتم الانتهاء من أي شيء حتى الآن ، حتى طلب السحب في Yarn لم يتم سكبه بعد ، يجب أن نتوقع تغييرات. ولكن كان من المثير للاهتمام بالنسبة لي تجربة الإصدار ألفا من الميزة عمليًا واختبارها في اثنين من مشاريعي الشخصية والتأكد من أن هذا النهج يعمل حقًا ، مما يجعل التثبيت أسرع.


المراجع


Source: https://habr.com/ru/post/ar423487/


All Articles