SN.
همه مقالات
فرانت‌اند۱۶ مرداد ۱۴۰۵۹ دقیقه

مهاجرت از CRA به Vite؛ چه زمانی ارزش دارد و چطور بدون Rewrite انجامش می‌دهم

Vite سریع‌تر بودن کافی نیست. قبل از مهاجرت CRA، هزینه تغییر Env، Alias، Asset، Test، Build و Deploy را Audit می‌کنم و فقط جایی مهاجرت می‌کنم که ارزش نگهداری داشته باشد.

لپ‌تاپ با کد در یک محیط کاری توسعه فرانت‌اند

Create React App امروز برای پروژه جدید انتخاب پیشنهادی React نیست، اما این به معنی آن نیست که هر پروژه CRA باید فوراً Rewrite شود.

من Migration را زمانی انجام می‌دهم که هزینه ادامه دادن با Toolchain فعلی از هزینه تغییر بیشتر شده باشد. سرعت Dev Server یکی از ورودی‌های تصمیم است، نه کل تصمیم.

برای یک پروژه موجود، سؤال اصلی من این نیست که «Vite سریع‌تر است؟»؛ سؤال این است: چه فرض‌هایی در Build فعلی پنهان شده‌اند و انتقال آن‌ها چقدر ریسک دارد؟

اول مشخص می‌کنم چرا اصلاً Migration لازم است

اگر پروژه پایدار است، تغییر زیادی ندارد و Build فعلی مانع توسعه نیست، مهاجرت فقط برای مدرن به‌نظر رسیدن ارزش کمی دارد.

دلایل قابل دفاع‌تر برای من این‌ها هستند:

  • Toolchain دیگر نگهداری فعال مناسبی ندارد؛
  • Upgrade React یا Dependencyها با Build قدیمی اصطکاک ایجاد می‌کند؛
  • Dev Feedback آن‌قدر کند شده که روی کار روزمره اثر می‌گذارد؛
  • نیاز به Plugin یا Configuration داریم که در CRA سخت یا غیرشفاف است؛
  • تیم باید Build Behavior را واضح‌تر ببیند و کنترل کند؛
  • Deploy یا Asset Pipeline فعلی محدودیت واقعی ایجاد کرده است.

اگر هیچ‌کدام از این مشکلات وجود ندارد، ممکن است بهترین تصمیم این باشد که Migration را فعلاً انجام ندهم.

قبل از نصب Vite، وابستگی‌های CRA را فهرست می‌کنم

بزرگ‌ترین ریسک مهاجرت معمولاً Componentهای React نیستند. مشکل در چیزهایی است که به‌صورت ضمنی توسط Toolchain فراهم شده‌اند.

Audit من شامل این موارد است:

  • Scriptهای package.json؛
  • Environment Variableها؛
  • Path Aliasها؛
  • فایل‌های public و Importهای Asset؛
  • SVG Handling؛
  • Proxy توسعه؛
  • Test Runner و Setup Fileها؛
  • Service Worker یا PWA Setup؛
  • Browser Target؛
  • Dependencyهایی که به Webpack Loader یا Node Global وابسته‌اند؛
  • Build/Deploy Scriptهایی که پوشه خروجی مشخصی را فرض کرده‌اند.

این فهرست Scope واقعی Migration را نشان می‌دهد. بدون آن، پروژه ممکن است در Dev بالا بیاید ولی Production چند روز بعد مشکل Asset یا Env داشته باشد.

هدف من تعویض Shell است، نه Rewrite Application

اگر Component Tree، Routing، State Management و CSS پروژه سالم‌اند، دلیلی ندارد به‌خاطر Build Tool دوباره نوشته شوند.

من Migration را تا جای ممکن به لایه Tooling محدود می‌کنم:

  1. Vite Config و Entry جدید را می‌سازم.
  2. Root Mount موجود React را منتقل می‌کنم.
  3. Environment و Aliasها را Mapping می‌کنم.
  4. Asset و CSS Importها را بررسی می‌کنم.
  5. Test/Dev/Build Scriptها را تطبیق می‌دهم.
  6. Production Output را در همان Deployment Target تست می‌کنم.

هر تغییر Component که برای Migration «ضروری» معرفی می‌شود باید دلیل روشن داشته باشد. این نگاه جلوی تبدیل Upgrade به Refactor بی‌انتها را می‌گیرد.

Environment Variableها یکی از مهم‌ترین تفاوت‌ها هستند

CRA معمولاً Variableهای Client را با Prefix REACT_APP_ و process.env در اختیار کد می‌گذارد. Vite Client Env را از import.meta.env می‌خواند و Variableهای دارای Prefix VITE_ را در Bundle Client قابل دسترسی می‌کند.

مثلاً:

// CRA
const apiUrl = process.env.REACT_APP_API_URL;

// Vite
const apiUrl = import.meta.env.VITE_API_URL;

این تغییر ظاهراً ساده است، اما دو نکته مهم دارد.

اول اینکه هر چیزی با Prefix Client در Bundle قابل مشاهده است؛ Secret نباید آنجا قرار بگیرد. دوم اینکه اگر Env Access در ده‌ها Component پخش شده باشد، Migration فرصت خوبی است که یک Config Module کوچک بسازیم تا Toolchain Detail در کل App تکرار نشود.

مثلاً Component لازم نیست بداند Vite از import.meta.env استفاده می‌کند؛ فقط config.apiUrl را می‌خواند.

Alias و Asset Path را جداگانه تست می‌کنم

مسیرهایی مثل @/components ممکن است در CRA با Config جانبی یا Tooling IDE کار کرده باشند. در Vite باید Alias Build و TypeScript Resolution با هم هماهنگ باشند.

Assetها نیز دو مدل مهم دارند: فایل‌هایی که از Source Import می‌شوند و فایل‌هایی که از Public Directory با URL ثابت مصرف می‌شوند. من این دو را تصادفی با هم جایگزین نمی‌کنم.

برای هر Asset مهم بررسی می‌کنم:

  • در Dev Resolve می‌شود؛
  • در Production Build URL درست دارد؛
  • Base Path محیط Deploy را رعایت می‌کند؛
  • Cache-busting برای Assetهای Bundled حفظ می‌شود؛
  • فایل Public واقعاً نیاز به نام ثابت دارد یا بهتر است Import شود.

Bugهای این بخش معمولاً در npm run dev پنهان می‌مانند و بعد از Deploy دیده می‌شوند.

Dependencyهایی که Webpack را فرض کرده‌اند، Risk واقعی هستند

بعضی Packageها بدون اینکه واضح باشد به Loader، Macro، process, Buffer یا Polyfillهایی تکیه دارند که Toolchain قبلی فراهم می‌کرد.

من قبل از Migration فقط Importهای خود پروژه را نمی‌بینم؛ Dependencyهای حساس را هم بررسی می‌کنم. اگر یک Package سال‌ها Update نشده و فقط با workaround کار می‌کند، شاید خود Dependency باید قبل یا بعد از Migration جایگزین شود.

اما این جایگزینی را ترجیح می‌دهم جدا از Cutover اصلی انجام دهم. هرچه متغیرهای هم‌زمان کمتر باشند، Debug آسان‌تر است.

Test Setup را «بعداً درست می‌کنیم» نمی‌گذارم

اگر پروژه Test دارد، Migration بدون Test Runner معادل «موفق» نیست.

باید مشخص شود Testهای فعلی به چه چیزهایی وابسته‌اند:

  • Jest-specific API؛
  • Setup File؛
  • DOM Environment؛
  • Asset Mock؛
  • Alias؛
  • Environment Variable؛
  • Coverage Script.

ممکن است تیم Vitest را انتخاب کند یا Test Setup فعلی را موقتاً نگه دارد. انتخاب ابزار مهم است، اما مهم‌تر این است که Test Coverage در Migration گم نشود.

Production Build را مثل Dev Server نمی‌سنجم

سرعت HMR خوب است، ولی محصول با Development Server Deploy نمی‌شود.

بعد از Migration مواردی مثل این‌ها را جدا بررسی می‌کنم:

  • vite build بدون Warning مهم تمام می‌شود؛
  • خروجی و Asset Path با Hosting هماهنگ‌اند؛
  • SPA Routeها روی Refresh از Server 404 نمی‌گیرند؛
  • Base Path اگر App زیر Subdirectory است درست تعریف شده؛
  • Source Map و Error Tracking طبق نیاز پروژه‌اند؛
  • Browser Support با کاربران واقعی محصول سازگار است؛
  • Cache Headerهای HTML و Assetها با Deployment Strategy تضاد ندارند.

Vite برای Production Browser Target مشخصی دارد و Legacy Support باید آگاهانه تصمیم‌گیری شود. من Browser Compatibility را بعد از Migration کشف نمی‌کنم؛ قبل از آن Requirement را ثبت می‌کنم.

Deploy بخشی از Migration است

اگر Pipeline فعلی دنبال build/ می‌گردد و خروجی جدید dist/ است، Application ممکن است کاملاً سالم باشد ولی Deployment شکست بخورد.

همین موضوع برای Dockerfile، CI، CDN Path، Environment Injection و Rewrite Ruleهای SPA صدق می‌کند.

برای من Done زمانی است که Artifact جدید در Environment واقعی یا Staging بالا بیاید، Route مستقیم Refresh شود و Assetها از مسیر درست Load شوند؛ نه زمانی که فقط صفحه Home روی localhost باز شده است.

چه زمانی به‌جای Vite، Next.js را بررسی می‌کنم؟

اگر مسئله پروژه فقط Build Tool نیست و Requirements شامل Routing عمیق، Data Fetching یکپارچه، Server Rendering، Metadata/SEO، Server Component یا Server-side Capability می‌شود، شاید مهاجرت CRA به Vite فقط یک مرحله میانی غیرضروری باشد.

در این حالت Framework را جداگانه ارزیابی می‌کنم. مهاجرت به Next.js Scope بزرگ‌تری دارد و نباید با «تغییر Build Tool» اشتباه گرفته شود، اما اگر Product Requirement واقعاً Framework می‌خواهد، صرفاً نگه داشتن SPA Architecture برای کم کردن Diff هم تصمیم خوبی نیست.

از طرف دیگر، یک Dashboard داخلی Client-rendered یا Toolی با Hosting استاتیک ممکن است با Vite دقیقاً همان چیزی باشد که نیاز دارد.

چه زمانی اصلاً Migration نمی‌کنم؟

  • پروژه نزدیک پایان عمر است و تغییرات بسیار محدود دارد؛
  • Toolchain فعلی مشکلی برای Build و Security ایجاد نکرده و تیم زمان Regression Test ندارد؛
  • یک Rewrite بزرگ محصول در آینده نزدیک برنامه‌ریزی شده؛
  • Dependency حیاتی با Vite سازگار نیست و هزینه جایگزینی از ارزش Migration بیشتر است؛
  • دلیل اصلی فقط «Vite جدیدتر است» است.

تصمیم نگرفتن برای Migration هم می‌تواند تصمیم فنی درست باشد، اگر هزینه‌ها ثبت و آگاهانه پذیرفته شوند.

Checklist Cutover من

قبل از تغییر

  • دلیل Migration و معیار Done مشخص است.
  • Script، Env، Alias، Asset، Test و Deploy Audit شده‌اند.
  • Browser Support ثبت شده است.
  • Baseline UI و Flowهای اصلی موجود است.

هنگام Migration

  • Component Architecture بی‌دلیل Rewrite نمی‌شود.
  • Env Mapping و Secret Boundary بررسی می‌شود.
  • Aliasهای TypeScript و Vite هماهنگ‌اند.
  • Assetهای Public و Imported جدا بررسی می‌شوند.
  • Dependencyهای Webpack-specific شناسایی می‌شوند.

قبل از Release

  • Dev و Production Build هر دو موفق‌اند.
  • Testها اجرا می‌شوند.
  • Direct Route Refresh در Hosting واقعی کار می‌کند.
  • Asset/Font Path 404 ندارد.
  • Console Warning جدید بررسی شده است.
  • Rollback Plan وجود دارد.

جمع‌بندی

من CRA را به Vite مهاجرت نمی‌دهم چون یک Benchmark می‌گوید Dev Server سریع‌تر است. Migration زمانی ارزش دارد که Toolchain ساده‌تر، قابل فهم‌تر و مناسب‌تر برای ادامه عمر پروژه شود.

روش کم‌ریسک برای من این است: اول Audit، بعد تعویض Tooling Shell، حفظ Architecture سالم Application و در نهایت تست Production/Deploy. اگر مسیر نیازمند Rewrite گسترده شد، دوباره می‌پرسم آیا مسئله واقعاً Build Tool است یا پروژه به Framework متفاوتی نیاز دارد.