استفاده از مسیرهای مطلق در حین import ماژول‌ها در برنامه‌های مبتنی بر TypeScript
اندازه‌ی قلم متن
تخمین مدت زمان مطالعه‌ی مطلب: چهار دقیقه

در حین import ماژول‌های TypeScript ایی پس از مدتی به یک چنین کدهایی خواهیم رسید:
import { SpecialCollection } from "../../special";
import { LoginComponent } from "../login";
import { TextUtils } from ".../../utils/text";
import { Router } from "../../../core/router";
در این حالت، در یک پوشه برای import ماژولی مشخص، چنین import ایی را خواهیم داشت:
import { Data } from '../data';
و در پوشه‌ی تو در توی دیگری، این تعریف به صورت زیر تغییر می‌کند:
import { Data } from '../../../data';
و در آخر برنامه پر می‌شود از مسیرهای نسبی ‘../../../..’ مانند. به این ترتیب جابجا کردن فایل‌ها و Refactoring آن‌ها، مشکل می‌شود.
خوشبختانه کامپایلر TypeScript به همراه تنظیمات baseUrl و paths است که توسط آن‌ها می‌توان این مسیرهای نسبی را به مسیرهای مطلق تبدیل کرد و در این حالت اهمیتی ندارد که ماژول مدنظر از چه سطحی و درون چه پوشه‌ی تو در تویی فراخوانی می‌شود، این مسیر import همواره ثابت خواهد بود.


تنظیمات فایل tsconfig.json برای معرفی مسیرهای مطلق ماژول‌ها

فرض کنید می‌خواهید از یکی از سرویس‌های Core Module استفاده کنید:


بسته به عمق پوشه‌ی استفاده کننده، به یک چنین تعریفی خواهید رسید:
import { BrowserStorageService } from "./../../core/browser-storage.service";
برای بهبود این وضعیت، فایل tsconfig.json و یا همان تنظیمات کامپایلر TypeScript را به نحو ذیل تکمیل می‌کنیم:
{
  "compilerOptions": {
    "baseUrl": "src",
    "paths": {
      "@app/*": [
        "app/*"
      ],
      "@app/core/*": [
        "app/core/*"
      ],
      "@app/shared/*": [
        "app/shared/*"
      ],
      "@env/*": [
        "environments/*"
      ]
    }
  }
}
در اینجا baseUrl به پوشه‌ی src برنامه اشاره می‌کند و مسیرهای بعدی بر این اساس محاسبه می‌شوند. در ادامه در قسمت paths، ابتدا یک نام مستعار ذکر می‌شود و سپس مسیری که ارائه دهنده‌ی آن است. ذکر @ در اینجا اختیاری است؛ اما ذکر */‌ها اجباری است.
پس از این تغییرات، اکنون افزونه‌ی پیشنهاد دهنده‌ی imports، هر دو حالت استفاده‌ی از مسیر مطلق بر اساس نام مستعار تعریف شده:
 import { BrowserStorageService } from "@app/core/browser-storage.service";
و یا استفاده‌ی از مسیر نسبی را نیز پیشنهاد می‌دهد:
 import { BrowserStorageService } from "./../../core/browser-storage.service";


برای مثال اگر دقت کرده باشید، روش import اجزای خود Angular به صورت زیر است:
 import { Component } from '@angular/core';
علت اینجا است که Angular از تعریف مشابهی به صورت زیر برای نگاشت پوشه‌ی node_modules آن به angular@ استفاده می‌کند:
"paths": {
    "@angular/*": ["node_modules/@angular/*"]
},
و ذکر @ اختیاری هم از اینجا اقتباس شده‌است.


یک نکته‌ی مهم: تنظیمات فوق بدون تنظیمات معادل webpack ناقص هستند

اگر از برنامه‌ی Angular CLI استفاده می‌کنید، تنظیمات ذکر شده، تا همینجا به پایان می‌رسند؛ چون webpack جزئی از Angular CLI است و تنظیمات پیش فرض آن، قسمت baseUrl و paths فایل tsconfig.json را به صورت خودکار پردازش می‌کند. اما اگر از TypeScript در محیط‌های دیگری استفاده می‌کنید که از webpack به صورت مجزایی استفاده می‌کنند، نیاز است قسمت resolve.alias فایل webpack.config.js را نیز جهت معرفی این تغییرات، اصلاح کنید. از این جهت که کامپایلر TypeScript این مسیرهای مطلق را در حین تولید فایل‌های نهایی JavaScript ایی معادل، به مسیرهای نسبی بازنویسی نمی‌کند و در این حالت webpack نمی‌داند که چطور باید این ماژول‌ها را یافته و یکی کند.
resolve: {
  extensions: ['*', '.js', '.ts'],
  modules: [
    rootDir,
    path.join(rootDir, 'node_modules')
  ],
  alias: {
    '@app': 'src/app'
  }
},


کوتاه کردن مسیرهای مطلق با معرفی فایل ویژه‌ی index.ts

تا اینجا بجای ذکر مسیر
import { BrowserStorageService } from "./../../core/browser-storage.service";
به مسیر مطلق زیر رسیدیم (صرفنظر از محل قرارگیری ماژولی که قرار است آن‌را import کند):
import { BrowserStorageService } from "@app/core/browser-storage.service";
این را هم می‌خواهیم به صورت زیر کوتاه‌تر کنیم:
import { BrowserStorageService } from "@app/core";
یعنی فقط app/core@ را ذکر کنیم.

برای اینکار نیاز است فایل ویژه‌ای را به نام index.ts، در ریشه‌ی پوشه‌ی core ایجاد کنیم (src\app\core\index.ts)، با این محتوا:
export * from "./browser-storage.service";
export * from "./app-config.service";
export * from "./seo-service";
در اینجا تمام ماژول‌هایی که توسط Core Module ارائه می‌شوند را یکبار export می‌کنیم.
برای نمونه اگر به پوشه‌ی node_modules\@angular خود مجموعه‌ی Angular هم مراجعه کنید، هر پوشه‌ی src آن به همراه یک فایل index.d.ts شبیه تعاریف فوق نیز هست.

پس از افزودن فایل index.ts به ریشه‌ی پوشه‌ی مدنظر، اکنون در لیست پیشنهادات، ذکر app/core@ تنها نیز ظاهر شده و استفاده‌ی از آن مجاز است:

  • #
    ‫۶ سال و ۶ ماه قبل، چهارشنبه ۱۶ اسفند ۱۳۹۶، ساعت ۰۳:۰۹
    ممنون بابت این مطلب چون خیلی آدرس دهی رو راحت میکنه.
    ولی متاسفانه هنگام کامپایل برنامه توسط دستورهای ng build  یا ng serve ،کار نمیکنه و به تمامی آدرس‌های داده شده خطای Cannot find module رو میده. و جالب اینجاست این در حالیه که در حالت عادی و دولوپ، شما هیچ خطایی مشاهده نمیکنی و همه‌ی آدرس‌ها شناخته شده هستن و فقط موقع کامپایل این مشکل به وجود میاد.
    و البته در یک پروژه Angular Cli به غیر از tsconfig.json که در ریشه هست، tsconfig.app.json و همچنین tsconfig.spec.json هم در پوشه src موجود هستند که اونها هم دارای تنظیمات basePath هستند.
    • #
      ‫۶ سال و ۶ ماه قبل، چهارشنبه ۱۶ اسفند ۱۳۹۶، ساعت ۰۳:۲۹
      - به احتمال زیاد مسیرهای فایل tsconfig.json را بر اساس پوشه‌های پروژه‌ی خودتان وارد نکرده‌اید و با آن تطابقی ندارند. برای مثال تنظیم زیر در فایل tsconfig.json قرار گرفته در پوشه‌ای که فایل angular-cli.json. هست :
      {
        "compilerOptions": {
          "baseUrl": "src",
          "paths": {
            "@app/core/*": [ "app/core/*" ],
          }
        }
      }
      به معنای وجود پوشه‌ی src/app/core در پروژه‌ی شما است که به نام مستعار app/core@ نگاشت شده‌است.
      - برای نمونه نکات این مطلب به پروژه ASPNETCore2JwtAuthentication  اعمال شده‌اند و مشکلی در اجرای برنامه نیست.
      • #
        ‫۶ سال و ۶ ماه قبل، پنجشنبه ۲۴ اسفند ۱۳۹۶، ساعت ۰۴:۱۳
        خیلی ممنون فکر میکنم حق با شما بود مسیر‌ها رو تغییر دادم و چندین حالت رو امتحان کردم بالاخره کامپایل شد.
        ضمن اینکه اینجا یک سری موارد رو میگم شاید بدرد بقیه دوستان هم بخوره اگه به این مشکلات بر خوردن.

        اگر پروژه شما به جز فایل tsconfig.json اصلی که در ریشه پروژه هست، دارای فایل‌های tsconfig.app.json و tsconfig.spec.json هم هست، باید مسیرها رو به این صورت تنظیم کنید:
        مقدار baseUrl در فایل tsconfig.json برابر با src
        مقدار baseUrl در فایل‌های tsconfig.app.json و tsconfig.spec.json برابر با : /.

        مورد دیگه ای که بهش برخوردم خطای circular dependency بود که مربوط به ارجاع دادن مسیرهای مطلق به همدیگر هست.
        اگر در پروژه از فایل‌های index.ts جهت کوتاه کردن آدرس‌ها استفاده میکنید، نباید در داخل خود فایل هایی که در index.ts معرفی شدند، از مسیر مطلق استفاده کنید.
        برای مثال:
        شما یک پوشه به اسم common دارید که داخل آن یک پوشه دیگر به اسم utilities که برای مثال کلاسی به اسم DateTime را در آن تعریف کردید. و حال شما میخواهید کلاس DateTime را با آدرس مطلق app/common@ در سراسر پروژه استفاده کنید.
        به همین دلیل شما در داخل پوشه common فایل index.ts رو ایجاد میکنید و دستور زیر را قرار میدید:
         export * from './utilities/DateTime'
        حال، اگر در هر یک از فایل هایی که داخل پوشه common که فایل index.ts را قبلا در آن تعریف کردیم، بخواهید از DateTime استفاده کنید، اگر آن را با مسیر مطلق مانند:
         import { DateTime } from '@app/common'
         استفاده کنید به خطای circular dependency بر میخورید.
        به همین خاطر باید از مسیر نسبی استفاده کنید مانند:
         import { DateTime } from './utilities/DateTime'
        ولی در خارج از پوشه common میتوانید از مسیر مطلق استفاده کنید.
        امیدوارم تونسته باشم منظور رو برسونم.
  • #
    ‫۵ سال قبل، سه‌شنبه ۲۹ مرداد ۱۳۹۸، ساعت ۰۰:۴۱
    در صورتی که یک Angular workspace را با دستور زیر ایجاد کنیم :
    ng new angular-apps --create-application=false
    و سپس درون آن یک پروژه را با دستور زیر ایجاد کنیم :
    ng generate application cac-web
    در ریشه workspace   یک فایل به نام  tsconfig.json وجود دارد و در ریشه پروژه  cac-web یک فایل به نام  tsconfig.app.json وجود دارد . تنظیمات این دو فایل برای  مسیرهای مطلق در حین import ماژول‌ها  چگونه است ؟ 
    در فایل  tsconfig.app.json تنظیمات زیر اعمال شده است ولی تاثیری ندارد 

    {
      "compilerOptions": {
        "baseUrl": "src",
        "paths": {
          "@app/*": [
            "app/*"
          ],
          "@app/core/*": [
            "app/core/*"
          ],
          "@app/shared/*": [
            "app/shared/*"
          ],
          "@env/*": [
            "environments/*"
          ]
        }
      }
    }

    ساختار به صورت زیر می‌باشد :
    |node_modules
    |projects--------------cac-web|e2e-----------------|src
    |                             |                    |protractor.conf.js
    |                             |                    |tsconfig.json
    |                             |src-----------------|app-----------------|client(Module)
    |                             |                    |                    |shared(Module)
    |                             |                    |                    |core(Module)
    |                             |                    |                    |app-routing.module.ts
    |                             |                    |                    |app.component.html
    |                             |                    |                    |app.component.ts
    |                             |                    |                    |app.module.ts
    |                             |                    |assets
    |                             |                    |environments
    |                             |                    |index.html
    |                             |                    |main.ts
    |                             |                    |polyfills.ts
    |                             |                    |styles.css
    |                             |                    |test.ts
    |                             |browserslist
    |                             |karma.conf.js
    |                             |tsconfig.app.json
    |                             |tsconfig.spec.json
    |                             |tslint.json
    |.editorconfig
    |.gitignore
    |angular.json
    |package-lock.json
    |package.json
    |README.md
    |tsconfig.json
    |tslint.json
    • #
      ‫۵ سال قبل، سه‌شنبه ۲۹ مرداد ۱۳۹۸، ساعت ۱۹:۳۴
      - فایل tsconfig.app.json را تغییر ندهید.
      - فایل tsconfig.json اصلی را به این صورت تغییر دهید (به ازای هر پروژه‌ی مجزا، یک سطر به آرایه اضافه می‌شود):
      {
        "compilerOptions": {
          "baseUrl": "./",
          "paths": {
            "@app/*": [
              "projects/cac-web/src/app/*"
            ],
            "@app/core/*": [
              "projects/cac-web/src/app/core/*"
            ],
            "@app/shared/*": [
              "projects/cac-web/src/app/shared/*"
            ],
            "@env/*": [
              "projects/cac-web/src/environments/*"
            ]
          }
        }
      }

  • #
    ‫۳ سال و ۸ ماه قبل، شنبه ۱۳ دی ۱۳۹۹، ساعت ۰۳:۰۷
    با سلام و احترام
    با روش فوق در فایل index.ts درcore Module به شکل زیر :
    index.ts
    export * from './services/alertify.service';
     و تعریف :

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


    و آدرس مطلق بجای @app با .. شروع می‌شود.

    • #
      ‫۳ سال و ۸ ماه قبل، شنبه ۱۳ دی ۱۳۹۹، ساعت ۰۳:۳۱
      یا می‌توان از ابزارهای خودکاری که با یکسری از مفاهیم سازگاری ندارند، برای تعیین مسیرها استفاده کرد و یا دستی آن‌ها را وارد کرد. نتیجه‌ی نهایی، بحث کامپایل شدن یا نشدن است.