استفاده از absolute import در پروژه‌های CRA

آدرس‌دهی برای دسترسی به فایل‌های مختلف پروژه موضوع جدانشدنی در همه زبان‌های برنامه‌نویسیه که همه ما همه روزه داریم ازش استفاده می‌کنیم. در این مقاله میخوایم راجع به روش‌های مختلف آدرس‌دهی در پروژه‌های CRA و نحوه استفاده از اون‌ها صحبت کنیم. برای اینکار از یک پروژه خام که با create-react-app ساخته شده و یک صفحه، چند کامپوننت و چند تابع کاربردی به اون اضافه شده استفاده میکنیم. (گیتهاب پروژه)
ساختار پوشه src پروژه نهایی رو میتونید در عکس زیر مشاهده کنید:

ساختار پوشه src
ساختار پوشه src

relative import و معایب آن

پروژه‌های CRA به صورت پیش‌فرض برای آدرس‌دهی از relative import استفاده می‌کنند. در این روش باید آدرس فایل مدنظر رو نسبت به جایی که هستیم بنویسیم. برای مثال فرض کنید که صفحه Home نیاز به کامپوننت Content داره و با توجه به ساختار فعلی پروژه، برای استفاده از این کامپوننت ما باید از جایی که پوشه صفحه Home قرار داره دو مرحله در درخت فایل‌هامون به عقب برگردیم و از اونجا آدرس این فایل‌ رو بنویسیم.
در این روش کد ما به این شکل درمیاد:

استفاده از relative import
استفاده از relative import

اما مشکلات این روش چیه و چرا بهتره ازش استفاده نکنیم:
۱- اگه ساختار فایل‌های ما خیلی تودرتو یا به اصطلاح nested باشه آدرس فایل‌ها خیلی طولانی میشه و مجبور میشیم چند مرحله در درخت فایل‌ها به عقب برگردیم و بعد از اون مجددا چندین مرحله به جلو بریم تا به فایلی که مد نظرمونه برسیم.
۲- همونطور که گفته شد آدرس‌ها نسبت به فایلی که در اون هستیم نوشته میشه و زمانی که قصد جابه‌جایی فایلی رو داشته باشیم، این وابستگی مشکل‌ساز میشه. به عنوان مثال اگر در آینده تصمیم بگیریم فایل صفحه Home رو جابه‌جا کنیم، باید همه آدرس‌هایی که در اون نوشته شده رو به‌روزرسانی کنیم.

absolute import، روش جایگزین

اینجاست که absolute import به ما کمک میکنه تا این مشکلات رو برطرف کنیم. برای استفاده از این روش یک پوشه از پروژه رو به عنوان مرجع آدرس‌دهی‌ تعریف میکنیم و همه آدرس‌ها رو نسبت به این پوشه می‌نویسیم. در واقع همچنان داریم از روش قبلی استفاده میکنیم با این تفاوت که آدرس فایل‌هارو نسبت به پوشه مرجع می‌نویسیم. این روش به ما کمک میکنه که از برگشت‌های زیاد در درخت فایل‌ها جلوگیری کنیم و با توجه به این که پوشه مرجع ما ثابته با جا‌به‌جا کردن یک فایل نیازی به به‌روزرسانی آدرس‌های داخل فایل درحال جابه‌جایی نداریم.
دقت کنید که همچنان نیاز هست که آدرس‌هایی که به فایل در حال جابه‌جا شدن در پروژه اشاره می‌کنند رو به‌روزرسانی کنیم و این امر اجتناب ناپذیره. اما با توجه به این که در این روش آدرس هر فایل هنگام استفاده در هرجایی از پروژه یکسانه، با استفاده از روش جستجو و جایگزینی می‌توان همه آدرس‌ها رو همزمان به‌روزرسانی کرد.
فرض کنید پوشه src رو به عنوان پوشه مرجع در پروژه تعریف کنیم، در این صورت آدرس‌‌دهی‌های تکه کد بالا به شکل پایین تغییر پیدا میکنه:

استفاده از absolute import
استفاده از absolute import

با توجه به ساختار پروژه فعلی، در نگاه اول تفاوت چندانی بین این دو روش دیده نمیشه اما با بزرگ‌تر شدن پروژه به کدهایی مثل کد زیر برمیخوریم و اینجاست که برتری‌های absolute import رو بیشتر حس میکنیم:

Ewwww
Ewwww
Tadaaa
Tadaaa

تعریف پوشه مرجع در پروژه‌های CRA

همون طور که قبل‌تر اشاره شد پروژه‌های CRA به صورت پیش‌فرض از relative import استفاده می‌کنند. برای تعیین کردن پوشه مرجع فقط کافیه به فایل jsconfig.json یا tsconfig.json که داخل روت پروژه قراره داره این تکه کد رو اضافه کنید. در صورتی که برای ساختن پروژه از قالب تایپ‌اسکریپ CRA استفاده کرده باشید، فایل tsconfig.json از قبل موجود است و فقط نیاز به اضافه کردن baseUrl دارید در غیر این صورت اگر هیچکدام از این دو فایل از قبل وجود نداشتند فایل jsconfig.json رو در روت پروژه ایجاد کنید و تکه کد پایین رو به اون اضافه کنید.

بعد از اضافه کردن baseUrl می‌توانید از روش absolute import که در بالا بهش اشاره شد استفاده کنید.

نکته: تا قبل از نسخه چهارم CRA این کار رو میشد با مقداردهی NODE_PATH داخل فایل env. هم انجام داد که این روش از نسخه ۴ به بعد منسوخ شد:
نحوه تعریف پوشه مرجع قبل از CRA نسخه 4
نحوه تعریف پوشه مرجع قبل از CRA نسخه 4

کامیت مرتبط با این تغییرات

alias و نحوه استفاده از آن

به طور کلی در دنیای برنامه‌نویسی ما اکثرا با دستورات پرتکرار و گاها طولانی درگیر هستیم. در این شرایط می‌توان برای راحتی استفاده به جای این دستورات اسم‌های کوتاه‌تری تعریف کرد. به این اسم‌ها معمولا alias گفته می‌شود. این موضوع در رابطه با آدرس‌های پرتکرار و بعضا طولانی هم صدق میکنه و ما می‌توانیم با استفاده از alias برای این آدرس‌ها اسم‌های کوتاه‌تر و ساده‌تری تعریف کنیم. برای مثال:

برای تعریف alias در پروژه‌های CRA ما نیاز داریم که کمی تغییرات روی تنظیمات webpack اعمال کنیم. با توجه به این که CRA به صورت پیش‌فرض اجازه دستکاری تنظیمات webpack رو نمیده، باید از پکیج‌هایی مثل craco یا پکیج‌های مشابه استفاده کنیم.

نکته: روش دیگه دستکاری کردن تنظیمات webpack هم eject کردن پروژه هست که پیشنهاد نمیشه و باید به عنوان آخرین گزینه در نظر گرفته بشه.

برای استفاده از craco باید ابتدا به وسیله دستور زیر اون رو به پروژه اضافه کنیم:

نصب craco
نصب craco

بعد از این مرحله باید اسکریپت‌های فایل package.json پروژه رو به صورت زیر به‌روزرسانی کنیم که پروژه از تنظیمات craco استفاده کنه:

به‌روزرسانی دستورات package.json
به‌روزرسانی دستورات package.json

برای اضافه شدن alias‌ها به تنظیمات webpack باید یک فایل در روت پروژه به اسم craco.config.js بسازیم و کد زیر رو بهش اضافه کنیم:

اضافه کردن تنظیمات craco
اضافه کردن تنظیمات craco

با استفاده از تغییراتی که گفته شد می‌توان از alias‌ها در پروژه استفاده کرد اما ادیتورها و IDE‌ها این alias‌هارو شناسایی نمی‌کنند و مسیرهای درست رو به ما پیشنهاد نمی‌دهند. برای حل این مشکل باید تکه کد زیر رو به فایل‌های jsconfig.json یا tsconfig.json اضافه کنیم:

اضافه کردن مسیرها به jsconfig.json
اضافه کردن مسیرها به jsconfig.json

با استفاده از این روش می‌تونیم آدرس هامون رو به صورت زیر بنویسیم:

آدرس‌دهی با استفاده از alias
آدرس‌دهی با استفاده از alias

این روش در مقایسه با absolute import نیاز به تنظیمات بیشتری داره اما برتری آن قابلیت اضافه کردن alias های مختلف به پروژه است. به عنوان مثال این روش به ما اجازه تعریف یک alias دیگه در کنار @ به اسم components@ رو میده که به src/components اشاره میکنه.

دقت کنید که هر alias جدید باید به هر دو فایل craco.config.js و jsconfig.json اضافه بشه.
برای استفاده همزمان از alias و eslint، باید alias به تنظیمات eslint هم اضافه بشه تا به خطاهای مربوط به آدرس‌دهی برنخوریم.

کامیت مرتبط با این تغییرات

سخن آخر

در این مقاله به معایب relative import اشاره شد و دو روش جایگزین برای حل این مشکلات رو معرفی کردیم. درنهایت با توجه به این که absolute import نیاز به نصب پکیج جدید و یا تنظیمات اضافه نداره پیشنهاد شخصی من استفاده از روش اوله. پروژه CRA هم برای کوتاه کردن و تمیزتر شدن آدرس‌دهی ها استفاده از absolute import رو پیشنهاد کرده.
ممنونم از اینکه زمان گذاشتید و این مقاله رو تا انتها خوندید. خوشحال میشم برای بهبود این نوشته و نوشته‌های بعدی پیشنهادات و نظرات خودتون رو در بخش نظرات و یا از طریق ایمیل engineering@snapp.cab به دست من برسونید.

منابع

https://github.com/mrastiak/cra-absolute-import
https://create-react-app.dev/docs/importing-a-component/#absolute-imports
https://github.com/facebook/create-react-app/blob/main/CHANGELOG.md#removed-typescript-flag-and-node_path-support
https://github.com/gsoft-inc/craco

عکس‌های این مقاله با استفاده از این محصول زیبا ساخته شده:

https://ray.so/