ما در اسپاتی (Spatie) برنامههای SaaS را با لاراول در بکاند و اینرشیا به همراه ریاکت در فرانتاند میسازیم. این جداسازی به این معنی است که دو سیستم تایپ (type system) باید روی تکتک دادههایی (payload) که بین آنها ردوبدل میشود توافق داشته باشند؛ دادههای لاراول خارج میشوند و تایپاسکریپت آنها را دریافت میکند.
سامانه پشتیبانی There There که در حال توسعه آن هستیم، دقیقاً به همین شکل ساخته شده است. تیکتها، پیامها، اعضا و بخشهای سفارشی نوار کناری، همگی از این پل عبور میکنند. نگهداری دستی این تایپها ما را دیوانه میکرد؛ بنابراین این کار را دستی انجام نمیدهیم. سرویس There There در حال حاضر در مرحله بتای خصوصی قرار دارد و میتوانید برای دسترسی زودهنگام در there-there.app ثبتنام کنید.
دو پکیج اسپاتی این فرآیند را کاملاً بیدردسر میکنند: پکیج spatie/laravel-data دادههای خروجی را به کلاسهای تایپشده PHP تبدیل میکند و پکیج spatie/laravel-typescript-transformer این کلاسها را هنگام بیلد به تعاریف تایپاسکریپت تبدیل مینماید. اجازه دهید در عمل نشان دهم این روند چگونه کار میکند.
همگام نگهداشتن تایپها
یک payload چرخه حیات خود را به عنوان یک کلاس Data آغاز میکند. در ادامه کلاس MemberData ما آمده است که آن را هر بار هنگام رندر صفحه جزئیات عضو ارسال میکنیم.
use Spatie\LaravelData\Data;
use Spatie\TypeScriptTransformer\Attributes\TypeScript;
#[TypeScript]
class MemberData extends Data
{
public function __construct(
public int $id,
public string $ulid,
public string $name,
public string $email,
public ?string $avatar_url,
public WorkspaceMemberRole $role,
public string $joined_at,
public bool $restricted_channel_access = false,
) {}
public static function fromPivotUser(User $user): self
{
return new self(
id: $user->id,
ulid: $user->ulid,
name: $user->name,
email: $user->email,
avatar_url: $user->getAvatarUrlWithFallback(),
role: WorkspaceMemberRole::from($user->pivot->role),
joined_at: $user->pivot->created_at->toIso8601String(),
restricted_channel_access: (bool) $user->pivot->restricted_channel_access,
);
}
}اتریبیوت #[TypeScript] به عنوان مجوز ورود عمل میکند. هر کلاس PHP که این اتریبیوت را داشته باشد، توسط ترنسفورمر شناسایی میشود. ویژگیهای متد سازنده (constructor) به تایپهای تایپاسکریپتی تبدیل میشوند، از جمله انام WorkspaceMemberRole، رشته با قابلیت نال شدن (nullable string) و مقادیر بولین دارای مقدار پیشفرض.
خود ترنسفورمر یک پکیج معمولی لاراول به همراه یک فایل تنظیمات (config) است. در ادامه بخش مربوطه از فایل تنظیمات ما را مشاهده میکنید.
return [
'auto_discover_types' => [
app_path(),
],
'transformers' => [
SpatieStateTransformer::class,
EnumTransformer::class,
DataTypeScriptTransformer::class,
DtoTransformer::class,
],
'default_type_replacements' => [
Carbon\Carbon::class => 'string',
],
'output_file' => resource_path('js/types/generated.d.ts'),
];سه نکته ارزش دانستن دارد: بخش auto_discover_types مسیر app/ را برای یافتن هر کلاس انوتیشنگذاریشده اسکن میکند؛ بخش transformers وظیفه پردازش کلاسهای data، DTOها، انامها و استیت ماشینهای اسپاتی را بر عهده دارد؛ و بخش default_type_replacements به شما اجازه میدهد تایپهای PHP را با معادل تایپاسکریپتی آنها جایگزین کنید، همانطور که تمام تاریخهای Carbon در فرانتاند به یک string معمولی تبدیل میشوند.
وقتی ترنسفورمر اجرا میشود، فایل resources/js/types/generated.d.ts را مینویسد. برای کلاس MemberData ما، خروجی به این صورت خواهد بود:
declare namespace App.Domain.Settings.Data {
export type MemberData = {
id: number;
ulid: string;
name: string;
email: string;
avatar_url: string | null;
role: App.Domain.Workspace.Enums.WorkspaceMemberRole;
joined_at: string;
restricted_channel_access: boolean;
};
}فضای نام (namespace) ساختار فضای نام PHP را منعکس میکند. ساختار ویژگیها کاملاً با متد سازنده هماهنگ است. انامها به تایپهای تولیدشده خود ارجاع متقابل داده میشوند، بنابراین تغییر نام یک کیْس انام در PHP به تمام فراخوانهای تایپاسکریپت منتقل میشود.
شما میتوانید این فایل را به صورت دستی با دستور php artisan typescript:transform بازتولید کنید، اما ما آن را به Vite متصل کردهایم تا هر زمان که یک کلاس data یا enum تغییر کرد، این کار به صورت خودکار انجام شود.
handleHotUpdate({ file }) {
if (isServe && file.endsWith('.php') && (file.includes('/Data/') || file.includes('/Enums/'))) {
generate();
}
},این قطعه کد درون یک پلاگین سفارشی و کوچک Vite قرار میگیرد. زمانی که سرور توسعه (dev server) در حال اجراست و یک فایل PHP در مسیر Data/ یا Enums/ تغییر میکند، ما دستور php artisan typescript:transform را اجرا میکنیم و تایپهای فرانتاند در لحظه بهروزرسانی میشوند. بدون نیاز به مرحله دستی و بدون تعاریف قدیمی و کهنه.
گزینه سادهتری نیز در نسخه ۳ پکیج spatie/laravel-typescript-transformer وجود دارد: این پکیج شامل یک حالت watch داخلی است. پس از نصب chokidar، کافی است دستور php artisan typescript:transform --watch را اجرا کنید. ما از نسخه ۲.۶ استفاده میکنیم که دستور typescript:transform آن دارای گزینه --watch نیست، بنابراین پلاگین Vite بالا تغییرات را برای ما مدیریت میکند.
در ادامه ظاهر این قابلیت در ویرایشگر کد آورده شده است. فیلدهای کلاس MemberData به عنوان پیشنهادات خودکار تایپاسکریپت ظاهر میشوند:

سخن پایانی
این پیکربندی دستهای از مشکلات کوچک و روی اعصاب را کاملاً برطرف کرده است. وقتی نام یک ویژگی PHP را تغییر میدهیم، کامپایلر تایپاسکریپت تمام بخشهای فرانتاند که از آن استفاده میکنند را برجسته میکند. وقتی فیلدی اضافه میکنیم، ظرف چند ثانیه در autocomplete ویرایشگر آماده استفاده است. در نتیجه، هر دو طرف همیشه یکپارچه و هماهنگ باقی میمانند.
میتوانید پکیجها را در گیتهاب پیدا کنید: laravel-data و laravel-typescript-transformer. و اگر دوست دارید خودتان سرویس There There را امتحان کنید، ما در حال حاضر در مرحله بتای خصوصی هستیم و میتوانید برای دسترسی زودهنگام در there-there.app درخواست دهید.
دیدگاهها و نقدها
دیدگاه خود را درباره این تحلیل با دیگر خوانندگان به اشتراک بگذارید.
ارسال دیدگاه جدید
هنوز دیدگاهی برای این مقاله ثبت نشده است.
نخستین نفری باشید که دیدگاه یا نقد خود را درباره این موضوع مینویسد.