React Compiler با Rust: سرعت بیلد، محدودیتهای جدی و راه فعالسازی در Next.js و Vite
نویسنده: آرش لطیفی
کامپایلر Rust ریکات در آگوست ۲۰۲۶ رسمی شد؛ در یک کدبیس ۱۰۳۶ فایلی، بخش کامپایلر بیلد حدود ۱۷.۶ برابر سریعتر شد. اما هنوز الگوهایی هستن که کامپایلر را رد میکنن — اینها را باید بشناسی.
TL;DR — تیم oxc پشتیبانی رسمی از React Compiler با Rust را منتشر کرده؛ در یک کیس واقعی، زمان کامپایلر بیلد از ۱۴.۳ ثانیه با Babel به ۰.۸۱ ثانیه رسید (حدود ۱۷.۶× سریعتر، تکنخی). ولی محدودیتهای زبانی هنوز سرجاشونن:
throwداخلtryو عملگرهای logical assignment هنوز باعث bail-out میشن.
اگر با useMemo و useCallback دستوپنجه نرم میکنی، خبر خوب اینه که کامپایلر React این کار را خودش میکند — و حالا نسخه Rust آن رسمی شده و بهمراتب سریعتر است. خبر «باشه ولی»: بعضی الگوهای رایج کد هنوز باعث میشوند کامپایلر از بهینهکردن کامپوننت صرفنظر کند. بیا هر دو طرف را ببینیم.
چه خبر شده؟
تیم oxc (همان تیمی که پشت Oxlint و ابزارهای Rust برای جاوااسکریپت است) در ۴ آگوست ۲۰۲۶ پشتیبانی رسمی از React Compiler را با موتور Rust منتشر کرد. خود پروژه React Compiler کامپوننتها را خودکار memoize میکند تا نیازی به useMemo دستی نباشد؛ نسخه Babel آن کند بود و به همین دلیل خیلیها رغبت نکردند.
اعداد کیس واقعی (وبلاگ Master.dev، مهاجرت کدبیس ۱۰۳۶ فایلی Outlyne):
- کامپایلر بخش بیلد: ۱۴.۳ ثانیه با Babel → ۰.۸۱ ثانیه با Rust، تکنخی — حدود ۱۷.۶× سریعتر
- کل بیلد: از ۲۲.۱ ثانیه → ۹.۳ ثانیه (حدود ۲.۴×) — چون بیلد فقط کامپایلر نیست
- نقلقول بنچمارک اولیه پروژه oxc: «بیش از ۱۰ برابر سریعتر از Babel»
نکته مهم این اعداد: فقط بخش کامپایلر بیلد اینقدر سریع شده. اگر بیلد تو شامل Tailwind، باندلینگ، SVG و غیره است، بهبود کلی کوچکتر خواهد بود — همانطور که در این کیس از ۱۷× افت کرد به ۲.۴×.
چرا فقط سرعت نیست؛ پشتیبانی زبانی هم بهتر شده
نسخه Babel-based v1.0 کامپایلر چند محدودیت آزاردهنده داشت که حالا در نسخه Rust رفع شدهاند:
- منطق شرطی داخل بلوکهای
try/catch— در v1.0 بلاکر بود، حالا پشتیبانی میشود - reassign کردن prop destructured که بعد در closure تودرتو استفاده میشود — قبلاً کامپوننت skip میشد، حالا کاملاً پشتیبانی میشود
- کلیدهای computed در آبجکت (مثل
{ [`items-${count}`]: true }) — قبلاً باعث bail-out بود
در کیس Master.dev این رفعها بهتنهایی ۷ کامپوننت دیگر را وارد بهینهسازی کرد. ولی هنوز دو الگو bail-out میشوند: throw از داخل بلوک try، و عملگرهای logical assignment (??=، &&=، ||=). اگر اینها را دارید، کامپوننت skip میشود — بدون خطا، بیصدا.
یک مزیت پنهان: همنسخه شدن linter و build
نکتهای که در وبلاگ Master.dev مطرح شد و کمتر کسی بهش فکر میکند: اگر Oxlint (که پشتیبانی React Compiler دارد) با نسخهای متفاوت از کامپایلرِ بیلد کار کند، ممکن است کامپوننتی در بیلد بهینه نشود ولی lint هم خطا ندهد — دقیقاً همان باگهایی که پیش میآید و فکر میکنی ابزار خراب است. با یکدست شدن toolchain روی کامپایلر Rust، linter و بیلد همان رفتار و همان محدودیتها را دارند و این ناهماهنگی از بین میرود. (در کیس ذکرشده، اختلاف فقط بین نسخههای v0.145.0 و v0.144.0 بسته oxc-transform-react بود و باعث یک issue اشتباه شد.)
فعالسازی
در Vite (هر پروژهای)
انتشار v6.1.0 پلاگین @vitejs/plugin-react پشتیبانی «experimental native React Compiler support» را اضافه کرد:
اگر مثل کیس Master.dev از React Router در framework mode استفاده میکنی و نمیتوانی پلاگین Vite React را بگذاری، پلاگین مینیمال @acusti/vite-plugin-react-compiler مستقل از بقیه pipeline کار میکند.
در Next.js (نسخه ۱۶.۴)
Next.js نسخه Rust کامپایلر را داخل Turbopack دارد (از ۱۶.۳ experimental). در پست رسمی ۱۶.۴ اعلام شده که تیم Turbopack تغییراتی در تخصیص حافظه داده که مصرف حافظه React Compiler را حدود ۳۰٪ و زمان کامپایل را ۱۵٪ کاهش داده، بهعلاوه یک «fast check» که فایلهای نیازمند بهینهسازی را سریع تشخیص میدهد:
مقایسه گزینهها
| گزینه | کجا کار میکند | نکته |
|---|---|---|
| @vitejs/plugin-react با { compiler: true } | پروژههای Vite استاندارد | سادهترین مسیر؛ از نسخه ۶.۱.۰ |
| @acusti/vite-plugin-react-compiler | هر pipeline ای، مستقل از پلاگین React | برای React Router framework mode |
| Next.js + turbopackRustReactCompiler | پروژههای Next.js 16.3+ | بدون Babel، داخل Turbopack؛ fast check در ۱۶.۴ |
چکلیست قبل از فعالسازی
- [ ] نسخه React و پلاگینها را به آخرین آپدیت برسان تا رفعهای try/catch و computed keys را داشته باشی
- [ ] جستجو کن:
throwداخلtryو??=/&&=/||=در کامپوننتهای حساس — اینها هنوز bail-out میشوند - [ ] اگر Oxlint یا ابزار مشابه داری، مطمئن شو نسخه کامپایلر linter و build یکی است
- [ ] بعد از فعالسازی، بیلد را قبل/بعد تایم بگیر — بهبود واقعی روی کل بیلد، نه فقط کامپایلر
- [ ] به جای حذف دستی همه
useMemoها، یکبار رفتار runtime را تست کن؛ کامپایلر جایگزین memoization است، نه تست
جمعبندی
نسخه Rust کامپایلر React در نهایت این ابزار را از «جالب ولی سنگین» به «پیشفرض منطقی» تبدیل میکند: بیلد سریعتر، CI ارزانتر (نویسنده کیس اشاره میکند دقیقههای GitHub Actions برایشان هزینه واقعی شده)، و پشتیبانی زبانی که با هر انتشار بهتر میشود. اگر کدبیسات الگوهای bail-out کمی دارد، همین هفته امتحانش کمهزینهترین بهینهسازی ممکن است.
سوالات پرتکرار
Q: بعد از فعالسازی React Compiler باید همه useMemo ها را حذف کنم؟
نه بهصورت یکجا. کامپایلر خودش memoize میکند و useMemo دستی دیگر ضروری نیست، ولی حذف انبوهش ریسک رفتاری ندارد به این شرط که semantic ها یکی باشد. پیشنهاد عملی: فعالسازی را اول روی یک شاخه تست کن، snapshot/تستها را بگذار رد شود، بعد بهتدریج کدهای دستی را پاک کن.
Q: اگر کامپایلر یک کامپوننت را skip کند، خطا میدهد؟
نه. bail-out بیصداست — کامپوننت فقط بهینه نمیشود، همانطور که بدون کامپایلر کار میکرد. برای همین مهم است الگوهای bail-out (مثل throw داخل try و عملگرهای ||= و مشابه) را بشناسی و در کد حساس به رندر اجتناب کنی، یا از lint انتظار هشدار داشته باشی.
Q: با نسخه Rust، کل بیلد هم ۱۷ برابر سریعتر میشود؟
نه. ۱۷× فقط روی بخش کامپایلر بود (تکنخی، در کیس ذکرشده). کل بیلد شامل باندلینگ، CSS، تایپچک و بقیه stages است؛ در همان کیس کل بیلد حدود ۲.۴× سریعتر شد. انتظارت را بر اساس سهم کامپایلر از بیلد خودت تنظیم کن.