برنامه نویسی

راه اندازی Subpath Import Aliases در پروژه TypeScript

Summarize this content to 400 words in Persian Lang TL; DR استفاده از شرایط سفارشی

یک روز تصمیم گرفتم نام مستعار مسیر مدرن را در پروژه TypeScript خود بگنجانم. من انتظار نداشتم که چنین سفر چالش برانگیزی باشد! شما می توانید جزئیات را بخوانید ⏬

محتوا

مقدمه
پروژه نمونه
تلاش شماره 1: Node.js Docs را دنبال کنید
تلاش شماره 2: استفاده کنید dist به جای src

تلاش شماره 3: تنظیم کنید rootDir و outDir

تلاش شماره 4: اشاره به dist/src

تلاش شماره 5: شرایط سفارشی برای نجات

پیکربندی TypeScript را به روز کنید
پیکربندی Vitest را به روز کنید
ابزارهای دیگر

خلاصه

مقدمه

وارد کردن مسیرهای فرعی یک ویژگی بومی در Node.js است که امکان تعریف نام مستعار برای مسیرهای داخلی در یک پایگاه کد را فراهم می کند.

مثلا به جای نوشتن:

import { foo } from ‘../../../utils.js’;

شما می توانید یک وارد کردن مسیر فرعی را برای ساده کردن این کار به صورت زیر تنظیم کنید:

import { foo } from ‘#utils.js’;

دو فایده اصلی:

خواندن راحت تر
پس از جابجایی فایل ها هیچ تفاوت اضافی وجود ندارد

در تایپ اسکریپت، روش قدیمی تری برای تنظیم نام مستعار از طریق گزینه مسیرها وجود دارد. اگرچه برای خود TypeScript خوب کار می کند، اما مشکل اینجاست که Node.js از این پیکربندی آگاه نیست. برای اجرای کدهای کامپایل شده (tsconfig-paths، tsc-alias) باید از بسته های شخص ثالث استفاده کنید.

خبر خوب این است که از نسخه 4.8 TypeScript پشتیبانی برای واردات subpath اضافه شده است. در حالی که مفهوم ساده به نظر می رسد، ادغام واردات subpath در پروژه آزمایشی من مشکل بود. من تمام مسائل را مرحله به مرحله مرور می کنم و راه حل نهایی را به اشتراک می گذارم. بیایید شروع کنیم.

پروژه نمونه

ساختار پروژه زیر را تصور کنید:

my-project
├── src
│ ├── index.ts
│ └── utils.ts
├── test
│ └── index.spec.ts
├── package.json
├── tsconfig.build.json
├── tsconfig.json
└── vitest.config.mts

این یک تنظیم نسبتا معمولی است:

src و test به ترتیب شامل کد منبع و تست واحد است

tsconfig.json برای بررسی نوع کل پروژه

tsconfig.build.json برای کامپایل کد منبع از src به dist دایرکتوری

vitest.config.mts برای اجرای تست های واحد با vitest

در ابتدا، این پروژه از واردات فرعی استفاده نمی کند. src/index.ts از مسیر نسبی برای وارد کردن ثابت از Utils استفاده می کند:

// src/index.ts
import { foo } from ‘./utils.js’;

console.log(foo);

// src/utils.ts
export const foo = 42;

در test دایرکتوری همچنین وارد کردن utils توسط مسیر نسبی وجود دارد:

// test/index.spec.ts
import { foo } from ‘../src/utils.js’;

test(‘foo is 42’, () => {
expect(foo).toBe(42);
});

چند اسکریپت npm وجود دارد package.json، که در حالت اولیه پروژه با موفقیت اجرا شد:

“scripts”: {
“tsc”: “tsc”,
“test”: “vitest run”,
“build”: “tsc -p tsconfig.build.json”,
“start”: “node dist/index.js”
}

npm run tsc – کل پروژه را تایپ کنید

npm run test – تست ها را با کد واقعی در داخل اجرا کنید src

npm run build – کامپایل کد از src به dist دایرکتوری

npm start – اجرای پروژه از dist دایرکتوری

من از این دستورات به عنوان یک چک لیست استفاده خواهم کرد تا مطمئن شوم همه چیز بعد از راه اندازی imports subpath کار می کند.

همچنین، من در VSCode آن را بررسی خواهم کرد CMD / CTRL + click در utils import به محتویات فایل هدایت می شود.

تلاش شماره 1: Node.js Docs را دنبال کنید

اولین قدم من دنبال کردن نمونه‌های مستندات Node.js بود. من اضافه کردم imports میدان به package.json و نام مستعار را برای src دایرکتوری

// package.json
{
“name”: “subpath-imports-typescript”,
+ “imports”: {
+ “#*”: “./src/*”
+ },
}

و از آن نام مستعار در استفاده کرد src/index.ts و test/index.spec.ts:

// src/index.ts
– import { foo } from ‘./utils’;
+ import { foo } from ‘#utils.js’;

// test/index.spec.ts
– import { foo } from ‘../src/utils.js’;
+ import { foo } from ‘#utils.js’;

پس از انجام این تغییرات، تمام دستورات به جز دستور کار کردند npm start، که با خطای زیر ناموفق بود:

> node dist/index.js

node:internal/modules/cjs/loader:1110
throw e;
^

Error: Cannot find module ‘/projects/subpath-imports-typescript/src/utils.js’

مشکل به این دلیل رخ داد که Node.js به دنبال آن بود utils.js در src دایرکتوری به جای dist دایرکتوری از آنجایی که پروژه قرار است از dist دایرکتوری، Node.js نتوانست فایل مورد نیاز را پیدا کند.

تلاش شماره 2: استفاده کنید dist به جای src

برای رفع این مشکل، من را تنظیم کردم imports میدان در package.json برای اشاره به dist دایرکتوری به جای src:

{
“name”: “subpath-imports-typescript”,
“imports”: {
– “#*”: “./src/*”
+ “#*”: “./dist/*”
},
}

در ابتدا، به نظر می رسید که این تغییر موثر باشد. با این حال، یک بار من آن را حذف کردم dist دایرکتوری، همه چیز خراب شد! VSCode دیگر نمی تواند آن را پیدا کند #utils.js ماژول و TypeScript یک خطا نشان داد:

Cannot find module ‘#utils.js’ or its corresponding type declarations.

علت اصلی این بود که TypeScript و VSCode نمی‌توانستند نام مستعار را حل کنند زیرا فایل‌های موجود در dist دایرکتوری وجود ندارد

مشکل مرغ و تخم مرغ – فایل های منبع به فایل های کامپایل شده برای دریافت فایل های کامپایل شده ارجاع می دهند

برای رسیدگی به این مشکل، اسناد TypeScript توصیه می کند که تنظیم کنید rootDir و outDir گزینه ها در tsconfig.json.

تلاش شماره 3: تنظیم کنید rootDir و outDir

من اضافه کردم rootDir و outDir گزینه ها:

// tsconfig.json
{
“compilerOptions”: {
“target”: “es2021”,
“module”: “NodeNext”,
+ “rootDir”: “src”,
+ “outDir”: “dist”,
“noEmit”: true,
“skipLibCheck”: true
},
“include”: [“**/*.ts”] }

ایده در اینجا به این صورت است: زمانی که TypeScript دایرکتوری های مبدا و مقصد فایل های کامپایل شده را می داند، می تواند نام مستعار وارداتی را مجدداً به محل مبدا نقشه برداری کند.

در مورد من، #utils.js ابتدا حل خواهد شد ./dist/utils.js و سپس دوباره به نقشه برداری می شود ./src/utils.ts.

با این حال، وقتی دویدم tsc، TypeScript خطای زیر را ایجاد کرد:

File ‘/xxx/subpath-imports-typescript/test/index.spec.ts’ is not under ‘rootDir’
‘/xxx/subpath-imports-typescript/src’. ‘rootDir’ is expected to contain all source files.

برای حل این مشکل، مجبور شدم آن را محدود کنم include گزینه ای به src/**/*.ts:

{
“compilerOptions”: {
“target”: “es2021”,
“module”: “NodeNext”,
“rootDir”: “src”,
“outDir”: “dist”,
“noEmit”: true,
“skipLibCheck”: true
},
– “include”: [“**/*.ts”] + “include”: [“src/**/*.ts”] }

این تغییر ایجاد شد tsc کار کردن

جنبه منفی – اکنون پیکربندی TypeScript فقط برای اعمال می شود src دایرکتوری و فایل ها در test مستثنی هستند. VSCode دیگر نمی تواند کلیک روی آن را حل کند #utils.js واردات در test دایرکتوری، و vitest یک خطا می زند:

Error: Failed to load url #utils.js (resolved id: #utils.js) in /xxx/subpath-imports-typescript/test/index.spec.ts. Does the file exist?

اولین راه حل بالقوه اشاره بود rootDir به “.” به جای src برای پوشش کل پروژه:

{
“compilerOptions”: {
“target”: “es2021”,
“module”: “NodeNext”,
– “rootDir”: “src”,
+ “rootDir”: “.”,
“outDir”: “dist”,
“noEmit”: true,
“skipLibCheck”: true
},
– “include”: [“src/**/*.ts”] + “include”: [“**/*.ts”] }

با این حال، این نیز کمکی نکرد. وقتی دویدم tsc، TypeScript هنوز شکایت می کند:

Cannot find module ‘#utils.js’ or its corresponding type declarations.

حالا دلیلش فرق می کرد. چه زمانی rootDir تنظیم شد “.”، TypeScript کل ساختار پروژه را در داخل تکرار کرد dist دایرکتوری، در نتیجه:

├── dist
│ ├── src
│ │ ├── index.js
│ │ └── utils.js
│ └── test
│ └── index.spec.js

اما imports میدان در package.json اشاره کرد dist/utils.js، نه dist/src/utils.js.

تلاش شماره 4: اشاره به dist/src

باشه من تنظیم کردم imports میدانی برای اشاره dist/src:

{
“imports”: {
– “#*”: “./dist/*”
+ “#*”: “./dist/src/*”
}
}

این تغییر اجازه داد tsc به درستی کار کند، و VSCode اکنون می تواند به آن پیمایش کند utils.js در src.

با این حال، زمانی که من سعی کردم پروژه را با npm run build، من یک خطا دارم:

Cannot find module ‘#utils.js’ or its corresponding type declarations.

موضوع این بود که tsconfig.build.json هنوز داشت rootDir اشاره کرد src. من آپدیت کردم rootDir به “.” در tsconfig.build.ts همچنین:

// tsconfig.build.ts
{
“extends”: “./tsconfig.json”,
“compilerOptions”: {
– “rootDir”: “src”,
+ “rootDir”: “.”,
“outDir”: “dist”,
“noEmit”: false,
},
“include”: [“src”] }

اکنون TypeScript خوشحال است و من می توانم پروژه را کامپایل و بسازم! 🎉
بله، تودرتوی اضافی را در داخل معرفی کرد dist دایرکتوری قبلا، dist دایرکتوری به شکل زیر بود:

├── dist
│ ├── index.js
│ └── utils.js

و حالا با تو در تو src:

├── dist
│ ├── src
│ │ ├── index.js
│ │ └── utils.js

چیز مهمی نیست، من حاضرم آن را بپذیرم!

اما.. تست ها هنوز اجرا نمی شوند 🤯

npm run test یک خطا ایجاد می کند:

Failed to load url #utils.js (resolved id: #utils.js) in /xxx/subpath-imports-typescript/test/index.spec.ts. Does the file exist?

به این دلیل است که فقط TypeScript از آن آگاه است rootDir و outDir نقشه برداری مجدد همه ابزارهای دیگر، مانند Vitest، نقشه برداری را تشخیص ندادند، که منجر به خطاهای زمان اجرا در هنگام تلاش برای حل کردن #utils.js از test دایرکتوری

گیر کرده بودم. من قصد داشتم از واردات مرموز زیرمسیر صرف نظر کنم و به نام مستعار مسیر TypeScript برگردم. اما پس از مطالعه مستندات بیشتر و مشکلات GitHub، راه حلی پیدا کردم!

تلاش شماره 5: شرایط سفارشی برای نجات

طبق اسناد Node.js، می‌توانید از طریق شیء، نام مستعار وارداتی را به چندین مکان نگاشت کنید:

“imports”: {
“#*”: {
“condition-a”: “./location-a/*”,
“condition-b”: “./location-b/*”
}
}

کلیدهای آن شیء را شرایط می گویند. شرایط داخلی مانند وجود دارد default، require یا import، اما همچنین می تواند هر رشته سفارشی که توسط کاربر تعریف شده باشد وجود داشته باشد.

من اصلاح کردم imports میدان در package.json برای گنجاندن یک شرط سفارشی my-package-dev با اشاره به src و نگهداری کرد default شرط اشاره به dist:

“imports”: {
– “#*”: “./dist/src/*”
+ “#*”: {
+ “my-package-dev”: “./src/*”,
+ “default”: “./dist/*”
+ }
}

بنابراین، دو راه برای حل وجود دارد # واردات:

my-package-dev – به Node.js می گوید که مسیرها را از src دایرکتوری زمانی که شرط فعال است (در طول توسعه)

default – گزینه بازگشتی برای حل مسیرها از dist دایرکتوری زمانی که شرایط خاصی ارائه نشده باشد

توجه: من عمداً وضعیتم را نام بردم my-package-dev، نه فقط dev. این برای نویسندگان کتابخانه مهم است. اگر مصرف کنندگان شما پروژه خود را با dev شرایط، بسته شما در node_modules آن شرط را نیز در نظر می گیرد و سعی می کند فایل ها را از src! اگر برنامه کاربران نهایی را توسعه می دهید، می توانید استفاده کنید dev یا development به عنوان نام شرط

پیکربندی TypeScript را به روز کنید

اکنون باید به TypeScript در مورد شرایط سفارشی خود اطلاع دهم. خوشبختانه، tsconfig.json یک گزینه customConditions برای آن فراهم می کند. تمام تغییرات انجام شده در مراحل قبلی را برگردانده و اضافه کرده ام customConditions زمینه:

// tsconfig.json
“compilerOptions”: {
“target”: “es2021”,
“module”: “NodeNext”,
+ “customConditions”: [“my-package-dev”],
“noEmit”: true,
“skipLibCheck”: true,
}

با این تنظیمات، TypeScript به درستی وارد کردن مسیرهای فرعی را از مسیر حل می کند src دایرکتوری حتی بدون rootDir و outDir گزینه ها VSCode نیز به درستی پیمایش می کند utils.ts مکان

پیکربندی Vitest را به روز کنید

Vitest همچنین از ارائه شرایط سفارشی پشتیبانی می کند. من تنظیم کرده ام resolve.conditions در vitest.config.mts:

import { defineConfig } from ‘vitest/config’;

export default defineConfig({
+ resolve: {
+ conditions: [‘my-package-dev’],
+ },
});

پس از این تغییر، vitest در حال حل و فصل فایل‌ها بود src دایرکتوری که از بررسی کد واقعی در طول آزمایش اطمینان حاصل می کند:

ابزارهای دیگر

برای سایر ابزارها، باید اسناد آنها را در مورد پشتیبانی از شرایط سفارشی بررسی کنید. من سعی کردم پروژه ام را با tsx اجرا کنم. از آنجایی که از تمام پرچم‌های Node.js پشتیبانی می‌کند، من به تازگی شرایط سفارشی را از طریق آن ارائه کرده‌ام -C پرچم:

$ npx tsx -C my-package-dev src/index.ts
42

کار می کند.

من می توانم یک مرور کلی از پشتیبانی واردات subpath در ابزارها و IDE های مختلف را توصیه کنم.

خلاصه

این یک سفر چالش برانگیز برای راه اندازی واردات فرعی بود. به خصوص هنگام اطمینان از سازگاری در جریان توسعه، ابزارهای آزمایش، پشتیبانی IDE و اجرای تولید.

با این حال، نتیجه موفقیت آمیز است و راه اندازی نهایی چیز خیلی پیچیده ای نیست. من مطمئن هستم که وارد کردن مسیرهای فرعی در نهایت به یک روش پیش‌فرض برای نام مستعار در پروژه‌های Node.js تبدیل خواهد شد. امیدوارم این مقاله در وقت شما صرفه جویی کند!

من یک نمونه کار نهایی را در GitHub منتشر کرده ام، شما می توانید آن را بررسی کنید. با تشکر برای خواندن و کد نویسی خوشحال! ❤️

TL; DR استفاده از شرایط سفارشی

یک روز تصمیم گرفتم نام مستعار مسیر مدرن را در پروژه TypeScript خود بگنجانم. من انتظار نداشتم که چنین سفر چالش برانگیزی باشد! شما می توانید جزئیات را بخوانید

محتوا

  • مقدمه
  • پروژه نمونه
  • تلاش شماره 1: Node.js Docs را دنبال کنید
  • تلاش شماره 2: استفاده کنید dist به جای src
  • تلاش شماره 3: تنظیم کنید rootDir و outDir
  • تلاش شماره 4: اشاره به dist/src
  • تلاش شماره 5: شرایط سفارشی برای نجات

    • پیکربندی TypeScript را به روز کنید
    • پیکربندی Vitest را به روز کنید
    • ابزارهای دیگر
  • خلاصه

مقدمه

وارد کردن مسیرهای فرعی یک ویژگی بومی در Node.js است که امکان تعریف نام مستعار برای مسیرهای داخلی در یک پایگاه کد را فراهم می کند.

مثلا به جای نوشتن:

import { foo } from '../../../utils.js';

شما می توانید یک وارد کردن مسیر فرعی را برای ساده کردن این کار به صورت زیر تنظیم کنید:

import { foo } from '#utils.js';

دو فایده اصلی:

  1. خواندن راحت تر
  2. پس از جابجایی فایل ها هیچ تفاوت اضافی وجود ندارد

در تایپ اسکریپت، روش قدیمی تری برای تنظیم نام مستعار از طریق گزینه مسیرها وجود دارد. اگرچه برای خود TypeScript خوب کار می کند، اما مشکل اینجاست که Node.js از این پیکربندی آگاه نیست. برای اجرای کدهای کامپایل شده (tsconfig-paths، tsc-alias) باید از بسته های شخص ثالث استفاده کنید.

خبر خوب این است که از نسخه 4.8 TypeScript پشتیبانی برای واردات subpath اضافه شده است. در حالی که مفهوم ساده به نظر می رسد، ادغام واردات subpath در پروژه آزمایشی من مشکل بود. من تمام مسائل را مرحله به مرحله مرور می کنم و راه حل نهایی را به اشتراک می گذارم. بیایید شروع کنیم.

پروژه نمونه

ساختار پروژه زیر را تصور کنید:

my-project
├── src
│   ├── index.ts
│   └── utils.ts
├── test
│   └── index.spec.ts
├── package.json
├── tsconfig.build.json
├── tsconfig.json
└── vitest.config.mts

این یک تنظیم نسبتا معمولی است:

  • src و test به ترتیب شامل کد منبع و تست واحد است
  • tsconfig.json برای بررسی نوع کل پروژه
  • tsconfig.build.json برای کامپایل کد منبع از src به dist دایرکتوری
  • vitest.config.mts برای اجرای تست های واحد با vitest

در ابتدا، این پروژه از واردات فرعی استفاده نمی کند. src/index.ts از مسیر نسبی برای وارد کردن ثابت از Utils استفاده می کند:

// src/index.ts
import { foo } from './utils.js';

console.log(foo);

// src/utils.ts
export const foo = 42;

در test دایرکتوری همچنین وارد کردن utils توسط مسیر نسبی وجود دارد:

// test/index.spec.ts
import { foo } from '../src/utils.js';

test('foo is 42', () => {
  expect(foo).toBe(42);
});

چند اسکریپت npm وجود دارد package.json، که در حالت اولیه پروژه با موفقیت اجرا شد:

  "scripts": {
    "tsc": "tsc",
    "test": "vitest run",
    "build": "tsc -p tsconfig.build.json",
    "start": "node dist/index.js"
  }
  1. npm run tsc – کل پروژه را تایپ کنید
  2. npm run test – تست ها را با کد واقعی در داخل اجرا کنید src
  3. npm run build – کامپایل کد از src به dist دایرکتوری
  4. npm start – اجرای پروژه از dist دایرکتوری

من از این دستورات به عنوان یک چک لیست استفاده خواهم کرد تا مطمئن شوم همه چیز بعد از راه اندازی imports subpath کار می کند.

همچنین، من در VSCode آن را بررسی خواهم کرد CMD / CTRL + click در utils import به محتویات فایل هدایت می شود.

تلاش شماره 1: Node.js Docs را دنبال کنید

اولین قدم من دنبال کردن نمونه‌های مستندات Node.js بود. من اضافه کردم imports میدان به package.json و نام مستعار را برای src دایرکتوری

// package.json
{
  "name": "subpath-imports-typescript",
+  "imports": {
+    "#*": "./src/*"
+  },
}

و از آن نام مستعار در استفاده کرد src/index.ts و test/index.spec.ts:

// src/index.ts
- import { foo } from './utils';
+ import { foo } from '#utils.js';

// test/index.spec.ts
- import { foo } from '../src/utils.js';
+ import { foo } from '#utils.js';

پس از انجام این تغییرات، تمام دستورات به جز دستور کار کردند npm start، که با خطای زیر ناموفق بود:

> node dist/index.js

node:internal/modules/cjs/loader:1110
        throw e;
        ^

Error: Cannot find module '/projects/subpath-imports-typescript/src/utils.js'

مشکل به این دلیل رخ داد که Node.js به دنبال آن بود utils.js در src دایرکتوری به جای dist دایرکتوری از آنجایی که پروژه قرار است از dist دایرکتوری، Node.js نتوانست فایل مورد نیاز را پیدا کند.

تلاش شماره 2: استفاده کنید dist به جای src

برای رفع این مشکل، من را تنظیم کردم imports میدان در package.json برای اشاره به dist دایرکتوری به جای src:

{
  "name": "subpath-imports-typescript",
  "imports": {
-    "#*": "./src/*"
+    "#*": "./dist/*"
  },
}

در ابتدا، به نظر می رسید که این تغییر موثر باشد. با این حال، یک بار من آن را حذف کردم dist دایرکتوری، همه چیز خراب شد! VSCode دیگر نمی تواند آن را پیدا کند #utils.js ماژول و TypeScript یک خطا نشان داد:

Cannot find module '#utils.js' or its corresponding type declarations.

علت اصلی این بود که TypeScript و VSCode نمی‌توانستند نام مستعار را حل کنند زیرا فایل‌های موجود در dist دایرکتوری وجود ندارد

مشکل مرغ و تخم مرغ – فایل های منبع به فایل های کامپایل شده برای دریافت فایل های کامپایل شده ارجاع می دهند

برای رسیدگی به این مشکل، اسناد TypeScript توصیه می کند که تنظیم کنید rootDir و outDir گزینه ها در tsconfig.json.

تلاش شماره 3: تنظیم کنید rootDir و outDir

من اضافه کردم rootDir و outDir گزینه ها:

// tsconfig.json
{
  "compilerOptions": {
    "target": "es2021",
    "module": "NodeNext",
+    "rootDir": "src",
+    "outDir": "dist",
    "noEmit": true,
    "skipLibCheck": true
  },
  "include": ["**/*.ts"]
}

ایده در اینجا به این صورت است: زمانی که TypeScript دایرکتوری های مبدا و مقصد فایل های کامپایل شده را می داند، می تواند نام مستعار وارداتی را مجدداً به محل مبدا نقشه برداری کند.

در مورد من، #utils.js ابتدا حل خواهد شد ./dist/utils.js و سپس دوباره به نقشه برداری می شود ./src/utils.ts.

با این حال، وقتی دویدم tsc، TypeScript خطای زیر را ایجاد کرد:

File '/xxx/subpath-imports-typescript/test/index.spec.ts' is not under 'rootDir' 
'/xxx/subpath-imports-typescript/src'. 'rootDir' is expected to contain all source files.

برای حل این مشکل، مجبور شدم آن را محدود کنم include گزینه ای به src/**/*.ts:

{
  "compilerOptions": {
    "target": "es2021",
    "module": "NodeNext",
    "rootDir": "src",
    "outDir": "dist",
    "noEmit": true,
    "skipLibCheck": true
  },
-  "include": ["**/*.ts"]
+  "include": ["src/**/*.ts"]
}

این تغییر ایجاد شد tsc کار کردن

جنبه منفی – اکنون پیکربندی TypeScript فقط برای اعمال می شود src دایرکتوری و فایل ها در test مستثنی هستند. VSCode دیگر نمی تواند کلیک روی آن را حل کند #utils.js واردات در test دایرکتوری، و vitest یک خطا می زند:

Error: Failed to load url #utils.js (resolved id: #utils.js) in /xxx/subpath-imports-typescript/test/index.spec.ts. Does the file exist?

اولین راه حل بالقوه اشاره بود rootDir به "." به جای src برای پوشش کل پروژه:

{
  "compilerOptions": {
    "target": "es2021",
    "module": "NodeNext",
-   "rootDir": "src",
+   "rootDir": ".",
    "outDir": "dist",
    "noEmit": true,
    "skipLibCheck": true
  },
-  "include": ["src/**/*.ts"]
+  "include": ["**/*.ts"]
}

با این حال، این نیز کمکی نکرد. وقتی دویدم tsc، TypeScript هنوز شکایت می کند:

Cannot find module '#utils.js' or its corresponding type declarations.

حالا دلیلش فرق می کرد. چه زمانی rootDir تنظیم شد "."، TypeScript کل ساختار پروژه را در داخل تکرار کرد dist دایرکتوری، در نتیجه:

├── dist
│   ├── src
│   │   ├── index.js
│   │   └── utils.js
│   └── test
│       └── index.spec.js

اما imports میدان در package.json اشاره کرد dist/utils.js، نه dist/src/utils.js.

تلاش شماره 4: اشاره به dist/src

باشه من تنظیم کردم imports میدانی برای اشاره dist/src:

{
  "imports": {
-    "#*": "./dist/*"
+    "#*": "./dist/src/*"
  }
}

این تغییر اجازه داد tsc به درستی کار کند، و VSCode اکنون می تواند به آن پیمایش کند utils.js در src.

با این حال، زمانی که من سعی کردم پروژه را با npm run build، من یک خطا دارم:

Cannot find module '#utils.js' or its corresponding type declarations.

موضوع این بود که tsconfig.build.json هنوز داشت rootDir اشاره کرد src. من آپدیت کردم rootDir به "." در tsconfig.build.ts همچنین:

// tsconfig.build.ts
{
  "extends": "./tsconfig.json",
  "compilerOptions": {
-    "rootDir": "src",
+    "rootDir": ".",
    "outDir": "dist",
    "noEmit": false,
  },
  "include": ["src"]
}

اکنون TypeScript خوشحال است و من می توانم پروژه را کامپایل و بسازم! 🎉
بله، تودرتوی اضافی را در داخل معرفی کرد dist دایرکتوری قبلا، dist دایرکتوری به شکل زیر بود:

├── dist
│   ├── index.js
│   └── utils.js

و حالا با تو در تو src:

├── dist
│   ├── src
│   │   ├── index.js
│   │   └── utils.js

چیز مهمی نیست، من حاضرم آن را بپذیرم!

اما.. تست ها هنوز اجرا نمی شوند 🤯

npm run test یک خطا ایجاد می کند:

Failed to load url #utils.js (resolved id: #utils.js) in /xxx/subpath-imports-typescript/test/index.spec.ts. Does the file exist?

به این دلیل است که فقط TypeScript از آن آگاه است rootDir و outDir نقشه برداری مجدد همه ابزارهای دیگر، مانند Vitest، نقشه برداری را تشخیص ندادند، که منجر به خطاهای زمان اجرا در هنگام تلاش برای حل کردن #utils.js از test دایرکتوری

گیر کرده بودم. من قصد داشتم از واردات مرموز زیرمسیر صرف نظر کنم و به نام مستعار مسیر TypeScript برگردم. اما پس از مطالعه مستندات بیشتر و مشکلات GitHub، راه حلی پیدا کردم!

تلاش شماره 5: شرایط سفارشی برای نجات

طبق اسناد Node.js، می‌توانید از طریق شیء، نام مستعار وارداتی را به چندین مکان نگاشت کنید:

"imports": {
  "#*": {
    "condition-a": "./location-a/*",
    "condition-b": "./location-b/*"
  }
}

کلیدهای آن شیء را شرایط می گویند. شرایط داخلی مانند وجود دارد default، require یا import، اما همچنین می تواند هر رشته سفارشی که توسط کاربر تعریف شده باشد وجود داشته باشد.

من اصلاح کردم imports میدان در package.json برای گنجاندن یک شرط سفارشی my-package-dev با اشاره به src و نگهداری کرد default شرط اشاره به dist:

"imports": {
-  "#*": "./dist/src/*"
+  "#*": {
+    "my-package-dev": "./src/*",
+    "default": "./dist/*"
+  }
}

بنابراین، دو راه برای حل وجود دارد # واردات:

  • my-package-dev – به Node.js می گوید که مسیرها را از src دایرکتوری زمانی که شرط فعال است (در طول توسعه)
  • default – گزینه بازگشتی برای حل مسیرها از dist دایرکتوری زمانی که شرایط خاصی ارائه نشده باشد

توجه: من عمداً وضعیتم را نام بردم my-package-dev، نه فقط dev. این برای نویسندگان کتابخانه مهم است. اگر مصرف کنندگان شما پروژه خود را با dev شرایط، بسته شما در node_modules آن شرط را نیز در نظر می گیرد و سعی می کند فایل ها را از src! اگر برنامه کاربران نهایی را توسعه می دهید، می توانید استفاده کنید dev یا development به عنوان نام شرط

پیکربندی TypeScript را به روز کنید

اکنون باید به TypeScript در مورد شرایط سفارشی خود اطلاع دهم. خوشبختانه، tsconfig.json یک گزینه customConditions برای آن فراهم می کند. تمام تغییرات انجام شده در مراحل قبلی را برگردانده و اضافه کرده ام customConditions زمینه:

// tsconfig.json
"compilerOptions": {
  "target": "es2021",
  "module": "NodeNext",
+  "customConditions": ["my-package-dev"],
  "noEmit": true,
  "skipLibCheck": true,
}

با این تنظیمات، TypeScript به درستی وارد کردن مسیرهای فرعی را از مسیر حل می کند src دایرکتوری حتی بدون rootDir و outDir گزینه ها VSCode نیز به درستی پیمایش می کند utils.ts مکان

پیکربندی Vitest را به روز کنید

Vitest همچنین از ارائه شرایط سفارشی پشتیبانی می کند. من تنظیم کرده ام resolve.conditions در vitest.config.mts:

import { defineConfig } from 'vitest/config';

export default defineConfig({
+  resolve: {
+    conditions: ['my-package-dev'],
+  },
});

پس از این تغییر، vitest در حال حل و فصل فایل‌ها بود src دایرکتوری که از بررسی کد واقعی در طول آزمایش اطمینان حاصل می کند:

آزمون ها قبول می شوند

ابزارهای دیگر

برای سایر ابزارها، باید اسناد آنها را در مورد پشتیبانی از شرایط سفارشی بررسی کنید. من سعی کردم پروژه ام را با tsx اجرا کنم. از آنجایی که از تمام پرچم‌های Node.js پشتیبانی می‌کند، من به تازگی شرایط سفارشی را از طریق آن ارائه کرده‌ام -C پرچم:

$ npx tsx -C my-package-dev src/index.ts
42

کار می کند.

من می توانم یک مرور کلی از پشتیبانی واردات subpath در ابزارها و IDE های مختلف را توصیه کنم.

خلاصه

این یک سفر چالش برانگیز برای راه اندازی واردات فرعی بود. به خصوص هنگام اطمینان از سازگاری در جریان توسعه، ابزارهای آزمایش، پشتیبانی IDE و اجرای تولید.

با این حال، نتیجه موفقیت آمیز است و راه اندازی نهایی چیز خیلی پیچیده ای نیست. من مطمئن هستم که وارد کردن مسیرهای فرعی در نهایت به یک روش پیش‌فرض برای نام مستعار در پروژه‌های Node.js تبدیل خواهد شد. امیدوارم این مقاله در وقت شما صرفه جویی کند!

من یک نمونه کار نهایی را در GitHub منتشر کرده ام، شما می توانید آن را بررسی کنید. با تشکر برای خواندن و کد نویسی خوشحال! ❤️

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا