حاوية حقن التبعيات لجافا سكريبت (Node.js) — Awilix

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

حاوية حقن التبعيات لجافا سكريبت (Node.js) — Awilix



في التطوير الحديث على Node.js، أصبحت نقاء البنية وقابلية اختبار الكود في المقدمة. إحدى الأدوات الرئيسية لتحقيق هذه الأهداف هي حقن التبعيات (Dependency Injection, DI). توفر مكتبة Awilix حاوية DI قوية وعالية الأداء ومرنة لجافا سكريبت و TypeScript، وهي مثالية لتطبيقات الخادم على Node.js. في هذه المقالة، سنشرح بالتفصيل كيفية استخدام Awilix لإدارة التبعيات، وتحسين النمطية، وتبسيط الاختبار.



ما هو حقن التبعيات ولماذا نحتاج إلى حاوية؟



حقن التبعيات هو نمط تصميم حيث يتلقى الكائن تبعياته من الخارج بدلاً من إنشائها بنفسه. وهذا يحقق مبدأ عكس التحكم (Inversion of Control - IoC). الحاوية هي أداة تعمل على أتمتة عملية إنشاء وتوفير هذه التبعيات. بدلاً من إنشاء مثيلات الفئات يدويًا وتمريرها لبعضها البعض، تقوم بوصف قواعد البناء في الحاوية، وتقوم هي بحل جميع سلاسل التبعيات بنفسها.



المزايا الرئيسية لاستخدام حاوية DI:

  • تقليل الترابط في الكود: تعتمد الوحدات على التجريدات بدلاً من التطبيقات الملموسة.
  • تبسيط الاختبار: سهولة استبدال الخدمات الحقيقية بنماذج وهمية (mock) أثناء اختبارات الوحدة.
  • إدارة مركزية: جميع تكوينات التبعيات موجودة في مكان واحد، مما يسهل إعادة الهيكلة.
  • إدارة دورة الحياة: يمكن للحاوية التحكم في مدة بقاء الكائن — مثيل واحد للتطبيق بأكمله (singleton) أو جديد لكل طلب.


تثبيت Awilix



للبدء، قم بتثبيت المكتبة عبر npm:

npm install awilix


لا تحتوي Awilix على تبعيات خارجية وتعمل مع كل من وحدات CommonJS و ESM.



المفاهيم الأساسية لـ Awilix



تُبنى Awilix حول عدة مفاهيم رئيسية:

  • الحاوية (Container): الكائن الرئيسي الذي يخزن ويوفر التبعيات.
  • التسجيل (Registration): عملية ربط اسم (رمز) بمصنع أو فئة أو قيمة.
  • الحلال (Resolver): الكائن الذي يحدد كيفية إنشاء أو الحصول على التبعية. على سبيل المثال، asClass()، asFunction()، asValue().
  • وقت الحياة (Lifetime): يحدد عدد المرات التي سيتم فيها إنشاء الكائن: ScopedLifeTime (مرة واحدة لكل نطاق)، SingletonLifeTime (مرة واحدة طوال الوقت)، أو TransientLifeTime (جديد في كل مرة).


مثال على الاستخدام: خدمة للعمل مع المستخدمين



لننظر إلى مثال بسيط. لنفترض أن لدينا قاعدة بيانات، ومستودع للمستخدمين، وخدمة لمنطق الأعمال.



1. تعريف الفئات

// database.jsclass Database {    constructor() {        this.connection = 'Connected to DB';    }    query(sql) {        return `Result for: ${sql}`;    }}

// userRepository.jsclass UserRepository { constructor({ database }) { this.db = database; } findById(id) { return this.db.query(`SELECT * FROM users WHERE id = ${id}`); }}

// userService.jsclass UserService { constructor({ userRepository }) { this.repo = userRepository; } getUser(id) { return this.repo.findById(id); }}


لاحظ البنائين: فهم يقبلون كائنًا بالتبعيات. هذه ممارسة قياسية لـ Awilix.



2. إعداد الحاوية

const { createContainer, asClass, asValue, Lifetime } = require('awilix');

const container = createContainer();

// نقوم بتسجيل

توصيات