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

أهم شيء باختصار
تكون ملفات القفل مفيدة للغاية عند تطوير تطبيقات Node.js مثل خوادم الويب. ومع ذلك ، إذا كنت تتحدث عن إنشاء مكتبة أو أداة سطر أوامر بهدف النشر في npm ، فأنت بحاجة إلى معرفة أن ملفات التأمين في npm لا يتم نشرها. هذا يعني أنه إذا تم استخدام هذه الملفات أثناء التطوير ، فسيستخدم مُنشئ حزمة npm وأولئك الذين يستخدمون هذه الحزمة إصدارات مختلفة من التبعيات.
ما هو ملف القفل؟
يصف ملف القفل شجرة التبعية الكاملة في النموذج الذي حصلت عليه أثناء العمل في المشروع. يتضمن هذا الوصف أيضًا التبعيات المتداخلة. يحتوي الملف على معلومات حول إصدارات محددة من الحزم المستخدمة. في مدير حزمة npm ، تسمى هذه الملفات
package-lock.json
، في الغزل -
yarn.lock
. في كلا المديرين ، توجد هذه الملفات في نفس المجلد مثل
package.json
.
إليك ما قد تبدو عليه
package-lock.json
.
{ "name": "lockfile-demo", "version": "1.0.0", "lockfileVersion": 1, "requires": true, "dependencies": { "ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "requires": { "color-convert": "^1.9.0" } }, "chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" } } } }
هنا مثال على ملف
yarn.lock
. لم يتم تصميمه مثل
package-lock.json
، ولكنه يحتوي على بيانات مماثلة.
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. # yarn lockfile v1 ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== dependencies: color-convert "^1.9.0" chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== dependencies: ansi-styles "^3.2.1" escape-string-regexp "^1.0.5" supports-color "^5.3.0"
يحتوي كلا الملفين على بعض معلومات التبعية الحرجة:
- الإصدار الدقيق من كل التبعية المثبتة.
- معلومات التبعية لكل تبعية.
- معلومات حول الحزمة التي تم تنزيلها ، بما في ذلك المجموع الاختباري المستخدم للتحقق من سلامة الحزمة.
إذا كانت جميع التبعيات مدرجة في ملف القفل ، فلماذا إذن يضيفون معلومات عنها إلى
package.json
؟ لماذا هناك حاجة إلى ملفين؟
مقارنة بين package.json وقفل الملفات
الغرض من حقل
dependencies
في ملف
package.json
هو إظهار تبعيات المشروع التي يجب تثبيتها حتى تعمل بشكل صحيح. لكن هذا لا يشمل معلومات حول تبعيات هذه التبعيات. قد تتضمن معلومات التبعية إصدارات الحزمة بالضبط أو مجموعة معينة من الإصدارات المحددة وفقًا لقواعد
الإصدار الدلالية . عند استخدام npm أو نطاق الغزل ، يتم تحديد الإصدار الأنسب من الحزمة.
افترض أن الأمر
npm install
قد تم تشغيله لتثبيت تبعيات مشروع معين. أثناء عملية التثبيت ، التقطت npm الحزم المناسبة. إذا قمت بتشغيل هذا الأمر مرة أخرى ، بعد فترة ، وإذا تم إصدار إصدارات جديدة من التبعيات خلال هذا الوقت ، فقد يحدث أن يتم تحميل إصدارات أخرى من الحزم المستخدمة في المشروع في المرة الثانية. على سبيل المثال ، إذا قمت بتثبيت تبعية ، مثل
twilio
، باستخدام الأمر
npm install twilio
، فقد يظهر الإدخال التالي في قسم
dependencies
من ملف
package.json
:
{ "dependencies": { "twilio": "^3.30.3" } }
إذا نظرت إلى
وثائق الإصدار الدلالي npm ، يمكنك أن ترى أن علامة
^
تشير إلى أن أي إصدار من الحزمة مناسب ، وعدده أكبر من أو يساوي 3.30.3 وأقل من 4.0.0. نتيجة لذلك ، إذا لم يكن هناك ملف قفل في المشروع وتم إصدار إصدار جديد من الحزمة ، فإن
npm install
أو
yarn install
سوف يقوم تلقائيًا بتثبيت هذا الإصدار الجديد من الحزمة. لن يتم تحديث المعلومات الموجودة في
package.json
. عند استخدام ملفات القفل ، يبدو كل شيء مختلفًا.
إذا عثر npm أو الغزل على ملف القفل المقابل ، فسوف يقومون بتثبيت الحزم بناءً على هذا الملف ، وليس على
package.json
. هذا مفيد بشكل خاص ، على سبيل المثال ، عند استخدام أنظمة التكامل المستمر (CI) على الأنظمة الأساسية التي تحتاج إليها لضمان التشغيل الموحد للكود والاختبارات في بيئة معروفة خصائصها مقدمًا. في مثل هذه الحالات ، يمكنك استخدام أوامر أو علامات خاصة عند استدعاء مديري الحزم المناسبين:
npm ci # , package-lock.json yarn install --frozen-lock-file # , yarn.lock,
يعد هذا مفيدًا للغاية إذا كنت تقوم بتطوير مشروع مثل تطبيق ويب أو خادم ، لأنه في بيئة CI تحتاج إلى محاكاة سلوك المستخدم. نتيجة لذلك ، إذا قمنا بتضمين ملف تأمين في مستودع المشروع (على سبيل المثال ، تم إنشاؤه باستخدام أدوات git) ، فيمكننا أن نتأكد من أن كل مطور وكل خادم وكل نظام بناء كود وكل بيئة CI تستخدم نفس الإصدارات تبعيات.
لماذا لا تفعل الشيء نفسه عند نشر المكتبات أو غيرها من أدوات البرمجيات في سجل npm؟ قبل الإجابة على هذا السؤال ، نحتاج إلى التحدث عن كيفية عمل عملية نشر الحزم.
حزمة عملية النشر
يعتقد بعض المطورين أن ما يتم نشره في npm هو بالضبط ما يتم تخزينه في مستودع git ، أو ما يتحول إليه المشروع بعد الانتهاء من العمل عليه. هذا في الواقع ليس هو الحال. عند نشر حزمة ، تكتشف npm الملفات التي يجب نشرها عن طريق الوصول إلى مفتاح
files
في ملف
package.json
وملف
.npmignore
. إذا لم يكن بالإمكان اكتشاف أي من ذلك ، فسيتم استخدام ملف
.gitignore
. بالإضافة إلى ذلك ، يتم نشر بعض الملفات دائمًا ، وبعضها لا يتم نشره أبدًا. يمكنك معرفة ما هي هذه الملفات
هنا . على سبيل المثال ، يتجاهل npm دائمًا مجلد .git.
بعد ذلك ، يأخذ npm جميع الملفات المناسبة
npm pack
في ملف
tarball
باستخدام الأمر
npm pack
. إذا كنت تريد إلقاء نظرة على ما يتم
npm pack --dry-run
بالضبط في مثل هذا الملف ، يمكنك تشغيل الأمر
npm pack --dry-run
في مجلد المشروع وإلقاء نظرة على قائمة المواد في وحدة التحكم.
حزمة Npm - إخراج الأمر الجافثم يتم تحميل ملف
tarball
الناتج إلى سجل npm. عند تشغيل الأمر
npm pack --dry-run
يمكنك الانتباه إلى حقيقة أنه إذا كان هناك ملف
package-lock.json
في المشروع ، فلن يتم تضمينه في ملف tarball. هذا يرجع إلى حقيقة أن هذا الملف ، وفقًا
لقواعد npm ، يتم تجاهله دائمًا.
والنتيجة هي أنه إذا قام شخص ما بتثبيت حزمة شخص آخر ، فلن يتم
package-lock.json
ملف
package-lock.json
. ما في هذا الملف أن مطور الحزمة لن يؤخذ في الاعتبار عند تثبيت الحزمة من قبل شخص آخر.
يمكن أن يؤدي هذا ، عن طريق الصدفة السيئ ، إلى المشكلة التي تحدثنا عنها في البداية. في نظام المطور ، تعمل الشفرة بشكل جيد ، وفي الأنظمة الأخرى تنتج أخطاء. ولكن الحقيقة هي أن مطور المشروع وأولئك الذين يستخدمون المشروع يستخدمون إصدارات مختلفة من الحزم. كيفية اصلاحها؟
رفض قفل الملفات واستخدام التكنولوجيا shrinkwrap
تحتاج أولاً إلى منع إدراج ملفات القفل في مستودع المشروع. عند استخدام git ، يلزمك تضمين ما يلي في ملف
.gitignore
الخاص
.gitignore
:
yarn.lock package-lock.json
تشير وثائق الغزل إلى أنه يجب إضافة
yarn.lock
إلى المستودع حتى لو كان الأمر يتعلق بتطوير المكتبة التي تنوي نشرها. ولكن إذا كنت تريد أن تعمل أنت ومستخدمو مكتبتك بنفس الكود ، فإنني أوصي بإدراج
yarn.lock
في ملف
yarn.lock
.
يمكنك تعطيل الإنشاء التلقائي لملف
package-lock.json
عن طريق
.npmrc
ملف
.npmrc
بالمحتويات التالية إلى مجلد المشروع:
package-lock=false
عند العمل مع الغزل ، يمكنك استخدام أمر
yarn install --no-lockfile
، والذي يسمح لك بتعطيل قراءة ملف
yarn.lock
.
ومع ذلك ، لا يعني حقيقة أننا تخلصنا من ملف
package-lock.json
أننا لا نستطيع التقاط معلومات حول التبعيات والتبعيات المتداخلة. يوجد
ملف آخر يسمى
npm-shrinkwrap.json
.
بشكل عام ، هذا
هو نفس ملف package-lock.json
، يتم إنشاؤه بواسطة
npm shrinkwrap
. يحصل هذا الملف على سجل npm عند نشر الحزمة.
من أجل أتمتة هذه العملية ، يمكن إضافة
npm shrinkwrap
إلى قسم وصف البرنامج النصي لملف
package.json
كبرنامج نصي prepack. يمكنك تحقيق نفس التأثير باستخدام ربط ربط git. نتيجة لذلك ، يمكنك التأكد من أنه في بيئة التطوير الخاصة بك ، في نظام CI الخاص بك ، وأن مستخدمي مشروعك يستخدمون نفس التبعيات.
تجدر الإشارة إلى أنه يوصى باستخدام هذه التقنية بطريقة مسؤولة. بإنشاء ملفات shrinkwrap ، فإنك تلتزم بإصدارات محددة من التبعيات. من ناحية ، يعد هذا مفيدًا لضمان التشغيل المستقر للمشروع ، من ناحية أخرى ، فإنه يمكن أن يمنع المستخدمين من تثبيت التصحيحات المهمة ، والتي ، وإلا ، سيتم تنفيذها تلقائيًا. في الواقع ، توصي npm بشدة بعدم استخدام ملفات shrinkwrap عند تطوير المكتبات ، مع قصر استخدامها على أنظمة CI.
العثور على حزمة ومعلومات التبعية
لسوء الحظ ، مع وجود مجموعة كبيرة من المعلومات حول إدارة التبعية في
وثائق npm ، يصعب أحيانًا التنقل في هذه المعلومات. إذا كنت تريد أن تعرف بالضبط ما تم تثبيته أثناء تثبيت التبعيات أو تم حزمه قبل إرسال الحزمة إلى npm ، يمكنك ، باستخدام أوامر مختلفة ، استخدام
--dry-run
. يؤدي استخدام هذه العلامة إلى حقيقة أن الفريق لا يؤثر على النظام. على سبيل المثال ، لا
npm install --dry-run
الأمر
npm install --dry-run
فعلياً التبعيات ، ولا
npm publish --dry-run
الأمر
npm publish --dry-run
عملية نشر الحزمة.
فيما يلي بعض الأوامر المشابهة:
npm ci --dry-run # , package-lock.json npm-shrinkwrap.json npm pack --dry-run # , npm install <dep> --verbose --dry-run #
النتائج
يعتمد الكثير مما تحدثنا عنه هنا على تفاصيل أداء العمليات المختلفة باستخدام npm. نحن نتحدث عن التغليف ، النشر ، تثبيت الحزم ، العمل مع التبعيات. وبالنظر إلى حقيقة أن npm تتطور باستمرار ، يمكننا القول أن كل هذا يمكن أن يتغير في المستقبل. بالإضافة إلى ذلك ، تعتمد إمكانية التطبيق العملي للتوصيات الواردة هنا على كيفية إدراك مطور الحزمة لمشكلة استخدام إصدارات مختلفة من التبعيات في بيئات مختلفة.
نأمل أن تكون هذه المادة قد ساعدت في فهم كيفية عمل النظام الإيكولوجي للاعتماد على npm. إذا كنت تريد الخوض في هذا السؤال بشكل أعمق -
هنا يمكنك قراءة الاختلافات بين أوامر
npm install
npm ci
و
npm install
.
هنا يمكنك معرفة ما يحصل بالضبط في ملفات
package-lock.json
و
npm-shrinkwrap.json
.
فيما يلي صفحة وثائق npm حيث يمكنك معرفة ملفات المشروع التي يتم تضمينها ولا يتم تضمينها في الحزم.
أعزائي القراء! هل تستخدم ملف npm-shrinkwrap.json في مشاريعك؟
