اشتراک کد TypeScript بین Next.js و Expo تو یه مونوریپو
خلاصهٔ کاملتر
Daine Mawer تو این مقاله میگه وقتی یه اپ Next.js و یه اپ Expo دارید که هر دو TypeScript هستن و یه API رو صدا میزنن، منطقیه یه پکیج مشترک مثل packages/domain تو مونوریپوی pnpm و Turborepo بسازید. به گفتهٔ نویسنده، این کار میارزه، ولی باید مرزش باریک بمونه.
چیزهایی که به نظر نویسنده ارزش اشتراک دارن:
- تایپها: شکل پاسخها و بدنهٔ درخواستهای API که موقع کامپایل پاک میشن و وابستگی پلتفرمی ندارن.
- schemaهای اعتبارسنجی با Zod یا Valibot. سود اصلی همینجاست: اگه بکاند قرارداد رو عوض کنه، هر دو اپ موقع توسعه با خطا روبهرو میشن، نه اینکه یکیشون بیصدا تو production خراب بشه.
- یه API client نازک: تابعهایی که درخواست میسازن، fetch میکنن و جواب رو از schema رد میکنن. Next.js اونو تو Server Component میپیچه و Expo تو TanStack Query.
منطق خالص مثل قوانین قیمتگذاری هم میتونه اونجا باشه، به شرطی که side effect نداشته باشه. ولی ناوبری، storage و UI نباید مشترک بشن. App Router و Expo Router فقط تو قرارداد فایلمحور شبیهان. مرورگر cookie و localStorage داره، Expo هم expo-secure-store و AsyncStorage. قانون سرانگشتی نویسنده اینه: اگه خروجی تابع به مرورگر یا دستگاه بستگی داره، تو اپ بمونه.
مشکل اصلی جای دیگهست. pnpm هر پکیج رو یه بار تو یه store مرکزی نصب میکنه و node_modules رو با symlink به اون store میسازه. Metro (یعنی bundler اپهای React Native و Expo) مدتها بهجای دنبالکردن symlinkها، مسیر واقعی فایلها رو میگشت. نتیجه این بود که یا پکیج مشترک پیدا نمیشد، یا بدتر، یه نسخهٔ اشتباه از یه وابستگی پیدا میشد که خطا هم نمیداد.
از Expo SDK 54، expo/metro-config پشتیبانی داخلی از مونوریپو برای pnpm، npm، Yarn و Bun رو با symlink داره. یعنی تنظیمات دستی مثل watchFolders و resolver.nodeModulesPaths دیگه برای بیشتر پروژهها لازم نیست. نویسنده توصیه میکنه اگه این تنظیمات از قبل مونده، پاکشون کنید و یه بار expo start --clear بزنید تا کش قدیمی Metro پاک بشه. روی SDK 53 و قبلتر، node-linker=hoisted تو .npmrc هنوز راهحل مطمئنتریه. buildهای EAS هم ممکنه مسیر نصب متفاوتی داشته باشن و جدا خراب بشن.
خود پکیج میتونه مستقیم به سورس TypeScript اشاره کنه:
{
"name": "@repo/domain",
"version": "0.0.0",
"main": "./src/index.ts",
"types": "./src/index.ts"
}برای این کار Next.js باید اسم پکیج رو تو transpilePackages داشته باشه، ولی Metro معمولاً خودش هندلش میکنه. نویسنده پیشنهاد میکنه tsc --noEmit برای پکیج مشترک تو CI جدا اجرا بشه تا خطای تایپ همونجا که مالکشه گرفته بشه.
نکات کلیدی:
- تایپها، schemaهای Zod یا Valibot و یه API client ساده رو مشترک کنید.
- navigation، storage و UI رو هیچوقت بین Next.js و Expo مشترک نکنید.
- از Expo SDK 54، expo/metro-config خودش symlinkهای pnpm رو پشتیبانی میکنه.
- روی SDK 53 و قبلتر، node-linker=hoisted تو .npmrc راهحل مطمئنتره.
- برای اشاره به سورس TypeScript، Next.js به transpilePackages تو next.config.ts نیاز داره.
- buildهای EAS ممکنه استراتژی نصب متفاوتی با سیستم شما داشته باشن.




