npm هي أداة لإدارة الحزم تستخدم على نطاق واسع من قبل مطوري الواجهة الأمامية في المشروع، ويتم استخدام package.json لإدارة تكوين حزم npm التي يعتمد عليها المشروع. package.json هو ملف json، بالإضافة إلى وصف تبعيات حزمة المشروع، فهو يسمح لنا أيضًا باستخدام "قواعد الإصدار الدلالي" للإشارة إلى إصدارات الحزم التابعة لمشروعك، مما يسمح بمشاركة إصداراتك بشكل أفضل مع المطورين الآخرين بسهولة. إعادة الاستخدام. تبدأ هذه المقالة أساسًا من الممارسات الحديثة، جنبًا إلى جنب مع أحدث إصدارات npm والعقدة، لتقديم بعض التكوينات الشائعة في package.json وكيفية كتابة package.json موحدة
في مشروع Nodejs، package.json هو ملف تكوين يدير تبعياته عادةً عندما نقوم بتهيئة مشروع Nodejs، سنمرر:
npm init
ثم سيتم إنشاء 3 الدليل الخاص بك/الملفات، وnode_modules، وpackage.json، وpackage.lock.json. محتوى package.json هو:
{ "الاسم": "اسم مشروعك"، "الإصدار": "1.0.0"، "description": "وصف مشروعك"، "الرئيسي": "app.js"، "البرامج النصية": { "test": "صدى "خطأ: لم يتم تحديد اختبار" && خروج 1"، }, "المؤلف": "اسم المؤلف"، "الترخيص": "مركز الدراسات الدولي"، "التبعيات": { "التبعية1": "^1.4.0"، "التبعية2": "^1.5.2" } }
كما يتبين مما سبق، يحتوي package.json على البيانات الوصفية للمشروع نفسه، بالإضافة إلى معلومات التبعية الفرعية للمشروع (مثل التبعيات، وما إلى ذلك).
وجدنا أنه أثناء npm init، لم يتم إنشاء ملف package.json فحسب، بل تم إنشاء ملف package-lock.json أيضًا. فلماذا لا نزال بحاجة إلى إنشاء ملف package-lock.json عند مسح package.json؟ بشكل أساسي، ملف package-lock.json مخصص لقفل الإصدار. الحزمة الفرعية npm المحددة في package.json هي مثل: رد فعل: "^16.0.0". في التثبيت الفعلي، طالما أن الإصدار أعلى من الرد، package.json مستوفي للمتطلبات. هذا يعني أنه وفقًا لنفس ملف package.json، لا يمكن ضمان اتساق إصدارات التبعية الفرعية التي تم تثبيتها مرتين.
ملف قفل الحزمة كما هو موضح أدناه، وتحدد تبعية التبعية الفرعية 1 نسخته بالتفصيل. يلعب دور إصدار القفل.
{ "الاسم": "اسم مشروعك"، "الإصدار": "1.0.0"، "إصدار القفل": 1، "يتطلب": صحيح، "التبعيات": { "التبعية 1": { "الإصدار": "1.4.0"، "تم الحل": "https://registry.npmjs.org/dependency1/-/dependency1-1.4.0.tgz"، "نزاهة": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==" }, "التبعية 2": { "الإصدار": "1.5.2"، "تم الحل": "https://registry.npmjs.org/dependency2/-/dependency2-1.5.2.tgz"، "نزاهة": "sha512-WOn21V8AhyE1QqVfPIVxe3tupJacq1xGkPTB4iagT6o+P2cAgEOOwIxMftr4+ZCTI6d551ij9j61DFr0nsP2uQ==" } } }
سيتحدث هذا الفصل عن سمات التكوين شائعة الاستخدام في package.json. السمات مثل الاسم والإصدار وما إلى ذلك بسيطة للغاية ولن يتم تقديمها واحدة تلو الأخرى. يقدم هذا الفصل بشكل أساسي خصائص البرنامج النصي والصندوق ومساحات العمل.
يستخدمعلامة البرنامج النصي في npm لتحديد البرنامج النصي، عندما يتم تحديد تشغيل npm، سيتم إنشاء برنامج نصي للصدفة تلقائيًا. ما يجب ملاحظته هنا هو أن الصدفة الجديدة التي تم إنشاؤها بواسطة تشغيل npm ستخزن العقدة/.bin في ملف الدليل المحلي إضافة الدلائل الفرعية إلى متغير PATH.
هذا يعني أنه يمكن استدعاء جميع البرامج النصية الموجودة في الدليل الفرعي Node_modules/.bin للدليل الحالي مباشرةً باستخدام اسم البرنامج النصي دون إضافة مسار. على سبيل المثال، إذا كانت تبعيات المشروع الحالي تتضمن esbuild، فما عليك سوى كتابة esbuild xxx مباشرة.
{ // ... "البرامج النصية": { "build": "esbuild Index.js", } }
{ // ... "البرامج النصية": { "إنشاء": "./node_modules/.bin/esbuild Index.js" } }
الطريقتان المذكورتان أعلاه للكتابة متكافئتان.
يتم استخدام سمة bin لتحميل الملفات القابلة للتنفيذ في البيئة العالمية بمجرد تحديد حزمة npm مع حقل bin، سيتم تحميلها في البيئة العالمية ويمكن تنفيذ الملف من خلال اسم مستعار.
على سبيل المثال، حزمة npm الخاصة بـ @bytepack/cli:
"bin": { "bytepack": "./bin/index.js" }،
بمجرد تثبيت @bytepack/cli عالميًا، يمكنك تنفيذ الأمر المقابل مباشرة من خلال bytepack، مثل
bytepack -v //عرض 1.11.0.
إذا لم يتم تثبيته عالميًا، فسيتم توصيله تلقائيًا بدليل Node_module/.bin الخاص بالمشروع. بما يتوافق مع ما قيل في علامة البرنامج النصي التي تم تقديمها مسبقًا، يمكن استخدامها مباشرة مع الأسماء المستعارة.
عندما يكون المشروع كبيرًا جدًا، أصبح monorepo أكثر شيوعًا مؤخرًا. عندما يتعلق الأمر بـ monorepo، فإننا لا ننظر إلى مساحات العمل في الأيام الأولى، كنا نستخدم مساحات عمل الغزل، والآن تدعم مساحات العمل رسميًا مشكلة كيفية إدارة الحزم الفرعية المتعددة ضمن حزمة جذر ذات مستوى أعلى في نظام الملفات المحلي. في دليل إعلان مساحات العمل، سيتم ربط الحزمة بوحدات العقدة الخاصة بحزمة الجذر ذات المستوى الأعلى.
دعنا نوضح ذلك مباشرة بمثال من الموقع الرسمي:
{ "الاسم": "مشروعي"، "مساحات العمل": [ "الحزم/أ" ] }
في حزمة npm المسماة my-project، يوجد دليل تم تكوينه بواسطة مساحات العمل.
. +--package.json +--index.js `--الحزم +-- أ |. `--
تحتوي الحزمة.json وحزمة الجذر ذات المستوى الأعلى المسماة my-project على حزم/حزمة فرعية. في هذا الوقت، إذا قمنا بتثبيت npm، فإن حزمة npm a المثبتة في العقدة_modules في الحزمة الجذرية تشير إلى الحزمة المحلية/a
. +--node_modules |.`-- الحزم/أ -> ../الحزم/أ +--package-lock.json +--package.json `--الحزم +-- أ |. `-- package.json
أعلاه--
packages/a -> ../packages/a
يشير إلى الرابط الناعم من node_modules إلى حزمة npm المحلية
البيئات الشائعة ذات السمات المرتبطة ببيئة package.json، بشكل أساسي أعلاه مقسم إلى فئتين: المتصفح وبيئة العقدة. بعد ذلك، دعونا نلقي نظرة على خصائص التكوين المتعلقة بالبيئة في package.json. يمكن فهم تعريف البيئة ببساطة على النحو التالي:
js وحدات commonjs وCMD وUMD وAMD وES. في البداية، تم دعم حقل commonjs فقط في العقدة يمكن استخدام الحقل في package.json للإعلان عن المواصفات المعيارية التي تتبعها حزمة npm.
//package.json { الاسم: "حزمة ما"، النوع: "الوحدة النمطية"||"commonjs" }
تجدر الإشارة إلى أنه
عندما لا يتم تحديد النوع، فإن القيمة الافتراضية للنوع هي commonjs، ومع ذلك، فمن المستحسن أن تحدد جميع حزم npm النوع
عندما يحدد حقل النوع القيمة كوحدة نمطية، يتم استخدام مواصفات
ESModule يتم تحديد حقل النوع، وسيتم استخدام جميع ملفات .js في الدليل. تتبع الملفات التي تنتهي باللاحقة مواصفات النمطية المحددة حسب النوع.
بالإضافة إلى النوع، الذي يمكنه تحديد مواصفات النمطية، يتم تحديد مواصفات النمطية التي يتبعها الملف من خلال لاحقة الملف. الملفات التي تنتهي بـ .mjs هي مواصفات ESModule المستخدمة. تتبع نهاية .cjs مواصفات commonjs
بالإضافة إلى النوع، يحتوي package.json أيضًا على ثلاثة حقول: الرئيسي والوحدة النمطية والمتصفح لتحديد ملف الإدخال لحزمة npm.
نلقي نظرة على سيناريوهات استخدام هذه الحقول الثلاثة والأولويات عندما تكون هذه الحقول الثلاثة موجودة في نفس الوقت. لنفترض أن هناك حزمة npm تسمى demo1،
----- dist |--index.browser.js |--index.browser.mjs |--index.js |--
تحدد package.json الحقول الثلاثة الرئيسية والوحدة النمطية والمتصفح في نفس الوقت،
"main": "dist/index.js"، // main "module": "dist/index.mjs", //module // يمكن تعريف المتصفح على أنه كائن تعيين يتوافق مع الحقل الرئيسي/الوحدة النمطية، أو يمكن تعريفه مباشرة على أنه سلسلة "المتصفح": { "./dist/index.js": "./dist/index.browser.js"، // browser+cjs "./dist/index.mjs": "./dist/index.browser.mjs" // browser+mjs }, // "browser": "./dist/index.browser.js" // يتم إنشاء المتصفح
واستخدامه افتراضيًا، على سبيل المثال، إذا أشرنا إلى حزمة npm هذه في المشروع:
قم باستيراد العرض التوضيحي من "demo"
بعد إنشاء ما سبق الكود من خلال أداة الإنشاء، تسلسل التحميل للوحدة هو:
browser+mjs > Module > browser+cjs > main.
تسلسل التحميل هذا هو تسلسل التحميل الافتراضي لمعظم أدوات الإنشاء، مثل webapck وesbuild وما إلى ذلك. يمكن تعديل ترتيب التحميل هذا من خلال التكوين المقابل، ولكن في معظم السيناريوهات، سنستمر في اتباع ترتيب التحميل الافتراضي.
إذا تم تعريف حقل التصدير في package.json، فإن المحتوى المحدد في هذا الحقل هو التصدير الحقيقي والكامل لحزمة npm، وستكون الأولوية أعلى من الحقول الرئيسية وحقول الملف.
على سبيل المثال:
{ "الاسم": "حزمة"، "الصادرات": { ".": "./main.mjs"، "./foo": "./foo.js" } }
استيراد { شيء } من "pkg"; // من "pkg/main.mjs"
const { Something } = require("pkg/foo"); // require("pkg/foo.js")
من المثال أعلاه يبدو أن الصادرات يمكن أن تحدد الصادرات بمسارات مختلفة. في حالة وجود عمليات تصدير، سيكون دليل الملف الصالح سابقًا غير صالح في كل مكان، مثل require('pkg/package.json')، لأنه لم يتم تحديده في عمليات التصدير، وسيتم الإبلاغ عن خطأ.
ميزة أخرى كبيرة للصادرات هي المرجع الشرطي، على سبيل المثال، يمكننا تحديد حزم npm للإشارة إلى ملفات إدخال مختلفة بناءً على طرق مرجعية مختلفة أو أنواع معيارية.
// package.json { "الاسم": "pkg"، "الرئيسي": "./main-require.cjs"، "الصادرات": { "استيراد": "./main-module.js"، "تتطلب": "./main-require.cjs" }, "النوع": "الوحدة النمطية" }
في المثال أعلاه، إذا أشرنا
إلى "./main-require.cjs"
من خلالconst p = require('pkg').
إذا نجحت في:
استيراد p من 'pkg'، فإن
المرجع هو "./main-module.js"
آخر شيء يجب ملاحظته هو: إذا كانت سمة الصادرات موجودة، فلن تكون لسمة الصادرات أولوية أعلى فقط من السمة الرئيسية، ولكن أيضًا أعلى من حقول الوحدة والمتصفح.
تتضمن خصائص التكوين المرتبطة بالتبعية في package.json التبعيات، وdevDependeency، وpeerDependeency، وpeerDependeencyMeta، وما إلى ذلك.
التبعيات هي تبعيات المشروع، وتبعيات التطوير هي وحدات مطلوبة للتطوير، حتى نتمكن من تثبيتها حسب الحاجة أثناء عملية التطوير لتحسين كفاءة التطوير لدينا. ما يجب ملاحظته هنا هو محاولة استخدامها بشكل قياسي قدر الإمكان في مشاريعك الخاصة، على سبيل المثال، webpack وbabel وما إلى ذلك هي تبعيات تطوير، وليست تبعيات للمشروع نفسه.
التبعيات بالإضافة إلى التبعيات وتبعيات التطوير، تركز هذه المقالة على التبعيات النظيرة والتبعيات النظيرة.
التبعيات هي تبعيات في package.json، والتي يمكنها حل مشكلة تنزيل المكتبة الأساسية عدة مرات وتوحيد إصدار المكتبة الأساسية.
//حزمة/حزمة -----node_modules |-- npm-a -> يعتمد على رد الفعل، رد فعل دوم |-- npm-b -> يعتمد على رد الفعل، رد فعل دوم |-- Index.js
على سبيل المثال، في المثال أعلاه، إذا كانت الحزمتان الفرعيتان npm a وb تأتيان من React وreact-dom، فإذا أعلنا عن PeerDependicies في package.json من الحزمتين الفرعيتين npm a و ب، لن يتم إعادة تثبيت التبعيات المقابلة.
هناك نقطتان يجب ملاحظتهما:
"peerDependeency": {. "رد": "^16.8.3 || ^17 || ^18" }, "peerDependeencyMeta": { "رد الفعل": { «اختياري»: صحيح }, "رد الفعل الأصلي": { «اختياري»: صحيح } }
تم تحديد "react-dom" و"react-native" هنا في PeerDependeencyMeta وهما اختياريان، لذلك إذا لم يتم تثبيت "react-dom" و"react-native" في المشروع، فلن يتم الإبلاغ عن أي خطأ.
تجدر الإشارة إلى أننا قمنا بالفعل برفع القيد من خلال PeerDependeencyMeta، ولكن غالبًا ما تكون هناك سيناريوهات حيث يكون إما A أو B. على سبيل المثال، في المثال أعلاه، ما نحتاجه هو "react-dom" و"react-native" ونحن بحاجة إلى تثبيت واحد، ولكن في الواقع، لا يمكننا تحقيق هذه المطالبة من خلال البيان أعلاه.
هناك أيضًا العديد من سمات الأطراف الثلاثة في package.json، مثل الأنواع المستخدمة في tsc، والتأثيرات الجانبية المستخدمة في أدوات البناء، وhusky المستخدمة في git، وeslintIgnore المستخدمة في eslint الإضافات المخصصة لأدوات تطوير محددة ذات معنى ولن أعطي أمثلة هنا.