در حال حاضر 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 محدود می کنم:
- Vite Config و Entry جدید را می سازم.
- Root Mount موجود React را منتقل می کنم.
- Environment و Aliasها را Mapping می کنم.
- Asset و CSS Importها را بررسی می کنم.
- Test/Dev/Build Scriptها را تطبیق می دهم.
- 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 دیده می شوند.
وابستگی هایی که 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 متفاوتی نیاز دارد.
