العربية

دليل شامل لحل الوحدات في TypeScript، يغطي استراتيجيات الحل الكلاسيكي والعقدة، وbaseUrl، وpaths، وأفضل الممارسات لإدارة مسارات الاستيراد في المشاريع المعقدة.

حل الوحدات في TypeScript: فك غموض استراتيجيات مسار الاستيراد

يُعد نظام حل الوحدات في TypeScript جانبًا حاسمًا في بناء تطبيقات قابلة للتطوير والصيانة. إن فهم كيفية تحديد TypeScript لموقع الوحدات بناءً على مسارات الاستيراد أمر ضروري لتنظيم قاعدة التعليمات البرمجية الخاصة بك وتجنب الأخطاء الشائعة. سيتناول هذا الدليل الشامل تفاصيل حل الوحدات في TypeScript، ويغطي استراتيجيات حل الوحدات الكلاسيكية والعقدة، ودور baseUrl و paths في tsconfig.json، وأفضل الممارسات لإدارة مسارات الاستيراد بفعالية.

ما هو حل الوحدات؟

حل الوحدات هو العملية التي يحدد من خلالها مترجم TypeScript موقع الوحدة بناءً على عبارة الاستيراد في التعليمات البرمجية الخاصة بك. عندما تكتب import { SomeComponent } from './components/SomeComponent';، يحتاج TypeScript إلى معرفة مكان وجود الوحدة SomeComponent فعليًا على نظام الملفات الخاص بك. تحكم هذه العملية مجموعة من القواعد والتكوينات التي تحدد كيفية بحث TypeScript عن الوحدات.

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

استراتيجيات حل الوحدات

يوفر TypeScript استراتيجيتين أساسيتين لحل الوحدات، يتم تكوينهما عبر خيار المترجم moduleResolution في tsconfig.json:

حل الوحدات الكلاسيكي

تُعد استراتيجية حل الوحدات classic الأبسط بين الاثنتين. فهي تبحث عن الوحدات بطريقة مباشرة، متتبعة شجرة الدليل صعودًا من الملف المستورد.

كيف يعمل:

  1. يبدأ من الدليل الذي يحتوي على الملف المستورد.
  2. يبحث TypeScript عن ملف بالاسم والامتدادات المحددة (.ts، .tsx، .d.ts).
  3. إذا لم يتم العثور عليه، ينتقل إلى الدليل الأصل ويكرر البحث.
  4. تستمر هذه العملية حتى يتم العثور على الوحدة أو الوصول إلى جذر نظام الملفات.

مثال:

لنتأمل بنية المشروع التالية:


project/
├── src/
│   ├── components/
│   │   ├── SomeComponent.ts
│   │   └── index.ts
│   └── app.ts
├── tsconfig.json

إذا كان app.ts يحتوي على عبارة الاستيراد import { SomeComponent } from './components/SomeComponent';، فإن استراتيجية حل الوحدات classic ستقوم بما يلي:

  1. تبحث عن ./components/SomeComponent.ts، أو ./components/SomeComponent.tsx، أو ./components/SomeComponent.d.ts في دليل src.
  2. إذا لم يتم العثور عليها، فستنتقل إلى الدليل الأصل (جذر المشروع) وتكرر البحث، وهو أمر غير مرجح أن ينجح في هذه الحالة لأن المكون يقع داخل مجلد src.

القيود:

متى تستخدم:

تُعد استراتيجية حل الوحدات classic مناسبة بشكل عام فقط للمشاريع الصغيرة جدًا ذات البنية البسيطة للدلائل وبدون تبعيات خارجية. يجب أن تستخدم مشاريع TypeScript الحديثة دائمًا تقريبًا استراتيجية حل الوحدات node.

حل وحدات Node

تحاكي استراتيجية حل الوحدات node خوارزمية حل الوحدات المستخدمة بواسطة Node.js. وهذا يجعلها الخيار المفضل للمشاريع التي تستهدف Node.js أو تستخدم حزم npm، حيث توفر سلوك حل وحدات متسقًا ويمكن التنبؤ به.

كيف يعمل:

تتبع استراتيجية حل الوحدات node مجموعة أكثر تعقيدًا من القواعد، مع إعطاء الأولوية للبحث داخل node_modules والتعامل مع امتدادات الملفات المختلفة:

  1. الاستيرادات غير النسبية: إذا لم يبدأ مسار الاستيراد بـ ./، أو ../، أو /، يفترض TypeScript أنه يشير إلى وحدة موجودة في node_modules. سيبحث عن الوحدة في المواقع التالية:
    • node_modules في الدليل الحالي.
    • node_modules في الدليل الأصل.
    • ... وهكذا، حتى جذر نظام الملفات.
  2. الاستيرادات النسبية: إذا بدأ مسار الاستيراد بـ ./، أو ../، أو /، يتعامل TypeScript معه كمسار نسبي ويبحث عن الوحدة في الموقع المحدد، مع مراعاة ما يلي:
    • يبحث أولاً عن ملف بالاسم والامتدادات المحددة (.ts، .tsx، أو .d.ts).
    • إذا لم يتم العثور عليه، فإنه يبحث عن دليل بالاسم المحدد وملف باسم index.ts، أو index.tsx، أو index.d.ts داخل هذا الدليل (على سبيل المثال، ./components/index.ts إذا كان الاستيراد هو ./components).

مثال:

لنتأمل بنية المشروع التالية مع اعتماد على مكتبة lodash:


project/
├── src/
│   ├── utils/
│   │   └── helpers.ts
│   └── app.ts
├── node_modules/
│   └── lodash/
│       └── lodash.js
├── tsconfig.json

إذا كان app.ts يحتوي على عبارة الاستيراد import * as _ from 'lodash';، فإن استراتيجية حل الوحدات node ستقوم بما يلي:

  1. تتعرف على أن lodash هو استيراد غير نسبي.
  2. تبحث عن lodash في دليل node_modules ضمن جذر المشروع.
  3. تجد الوحدة lodash في node_modules/lodash/lodash.js.

إذا كان helpers.ts يحتوي على عبارة الاستيراد import { SomeHelper } from './SomeHelper';، فإن استراتيجية حل الوحدات node ستقوم بما يلي:

  1. تتعرف على أن ./SomeHelper هو استيراد نسبي.
  2. تبحث عن ./SomeHelper.ts، أو ./SomeHelper.tsx، أو ./SomeHelper.d.ts في دليل src/utils.
  3. إذا لم يكن أي من هذه الملفات موجودًا، فستبحث عن دليل باسم SomeHelper ثم تبحث عن index.ts، أو index.tsx، أو index.d.ts داخل هذا الدليل.

المزايا:

متى تستخدم:

تُعد استراتيجية حل الوحدات node الخيار الموصى به لمعظم مشاريع TypeScript، خاصة تلك التي تستهدف Node.js أو تستخدم حزم npm. إنها توفر نظامًا أكثر مرونة وقوة لحل الوحدات مقارنةً باستراتيجية classic.

تكوين حل الوحدات في tsconfig.json

ملف tsconfig.json هو ملف التكوين المركزي لمشروع TypeScript الخاص بك. يتيح لك تحديد خيارات المترجم، بما في ذلك استراتيجية حل الوحدات، وتخصيص كيفية تعامل TypeScript مع التعليمات البرمجية الخاصة بك.

إليك ملف tsconfig.json أساسي مع استراتيجية حل الوحدات node:


{
  "compilerOptions": {
    "moduleResolution": "node",
    "target": "es5",
    "module": "commonjs",
    "esModuleInterop": true,
    "strict": true,
    "outDir": "dist",
    "sourceMap": true
  },
  "include": [
    "src/**/*"
  ],
  "exclude": [
    "node_modules"
  ]
}

خيارات compilerOptions الرئيسية المتعلقة بحل الوحدات:

baseUrl و paths: التحكم في مسارات الاستيراد

توفر خيارات المترجم baseUrl و paths آليات قوية للتحكم في كيفية حل TypeScript لمسارات الاستيراد. يمكنها تحسين قابلية قراءة التعليمات البرمجية وصيانتها بشكل كبير من خلال السماح لك باستخدام الاستيرادات المطلقة وإنشاء تعيينات مسار مخصصة.

baseUrl

يحدد الخيار baseUrl الدليل الأساسي لحل أسماء الوحدات غير النسبية. عندما يتم تعيين baseUrl، سيقوم TypeScript بحل مسارات الاستيراد غير النسبية بالنسبة إلى الدليل الأساسي المحدد بدلاً من دليل العمل الحالي.

مثال:

لنتأمل بنية المشروع التالية:


project/
├── src/
│   ├── components/
│   │   ├── SomeComponent.ts
│   │   └── index.ts
│   └── app.ts
├── tsconfig.json

إذا كان tsconfig.json يحتوي على ما يلي:


{
  "compilerOptions": {
    "moduleResolution": "node",
    "baseUrl": "./src"
  }
}

بعد ذلك، في app.ts، يمكنك استخدام عبارة الاستيراد التالية:


import { SomeComponent } from 'components/SomeComponent';

بدلاً من:


import { SomeComponent } from './components/SomeComponent';

سيقوم TypeScript بحل components/SomeComponent بالنسبة لدليل ./src المحدد بواسطة baseUrl.

فوائد استخدام baseUrl:

paths

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

الخيار paths هو كائن حيث يمثل كل مفتاح نمط مسار، وكل قيمة هي مصفوفة من بدائل المسار. سيحاول TypeScript مطابقة مسار الاستيراد بأنماط المسار، وإذا تم العثور على تطابق، فسيستبدل مسار الاستيراد بمسارات الاستبدال المحددة.

مثال:

لنتأمل بنية المشروع التالية:


project/
├── src/
│   ├── components/
│   │   ├── SomeComponent.ts
│   │   └── index.ts
│   └── app.ts
├── libs/
│   └── my-library.ts
├── tsconfig.json

إذا كان tsconfig.json يحتوي على ما يلي:


{
  "compilerOptions": {
    "moduleResolution": "node",
    "baseUrl": "./src",
    "paths": {
      "@components/*": ["components/*"],
      "@mylib": ["../libs/my-library.ts"]
    }
  }
}

بعد ذلك، في app.ts، يمكنك استخدام عبارات الاستيراد التالية:


import { SomeComponent } from '@components/SomeComponent';
import { MyLibraryFunction } from '@mylib';

سيقوم TypeScript بحل @components/SomeComponent إلى components/SomeComponent بناءً على تعيين المسار @components/*، و @mylib إلى ../libs/my-library.ts بناءً على تعيين المسار @mylib.

فوائد استخدام paths:

حالات الاستخدام الشائعة لـ paths:

أفضل الممارسات لإدارة مسارات الاستيراد

تُعد الإدارة الفعالة لمسارات الاستيراد أمرًا بالغ الأهمية لبناء تطبيقات TypeScript قابلة للتطوير والصيانة. إليك بعض أفضل الممارسات التي يجب اتباعها:

استكشاف أخطاء حل الوحدات وإصلاحها

قد يكون استكشاف أخطاء حل الوحدات وإصلاحها أمرًا محبطًا. إليك بعض المشكلات والحلول الشائعة:

أمثلة واقعية عبر أطر عمل مختلفة

تنطبق مبادئ حل الوحدات في TypeScript عبر أطر عمل JavaScript المختلفة. إليك كيفية استخدامها بشكل شائع:

الخاتمة

يُعد نظام حل الوحدات في TypeScript أداة قوية لتنظيم قاعدة التعليمات البرمجية الخاصة بك وإدارة التبعيات بفعالية. من خلال فهم استراتيجيات حل الوحدات المختلفة، ودور baseUrl و paths، وأفضل الممارسات لإدارة مسارات الاستيراد، يمكنك بناء تطبيقات TypeScript قابلة للتطوير والصيانة وقابلة للقراءة. يمكن أن يؤدي التكوين الصحيح لحل الوحدات في tsconfig.json إلى تحسين سير عمل التطوير الخاص بك بشكل كبير وتقليل مخاطر الأخطاء. جرب تكوينات مختلفة وابحث عن النهج الذي يناسب احتياجات مشروعك على أفضل وجه.