--- url: /changes/this-environment-in-hooks.md --- # `this.environment` در هوک‌ها ::: tip بازخورد به ما در [Environment API feedback discussion](https://github.com/vitejs/vite/discussions/16358) بازخورد دهید ::: پیش از Vite 6، فقط دو محیط موجود بود: `client` و `ssr`. یک آرگومان هوک پلاگین `options.ssr` در `resolveId`، `load` و `transform` به نویسندگان پلاگین این امکان را می‌داد که هنگام پردازش ماژول‌ها در هوک‌های پلاگین، این دو محیط را از هم تمایز دهند. در Vite 6، یک برنامه Vite می‌تواند هر تعداد محیط نام‌گذاری‌شده را طبق نیاز تعریف کند. ما `this.environment` را در زمینه پلاگین معرفی می‌کنیم تا با محیط ماژول جاری در هوک‌ها تعامل داشته باشیم. دامنه تاثیر: `نویسندگان پلاگین Vite` ::: warning منسوخ‌شدن در آینده `this.environment` در نسخه `v6.0` معرفی‌شد. منسوخ شدن `options.ssr` برای یکی از نسخه‌های اصلی (major) آینده برنامه‌ریزی شده است. در آن زمان، شروع به توصیه به مهاجرت پلاگین‌ها به استفاده از API جدید خواهیم کرد. برای شناسایی استفاده از این ویژگی، می‌توانید `future.removePluginHookSsrArgument` را در تنظیمات Vite خود به مقدار `"warn"` تنظیم کنید. ::: ## انگیزه `this.environment` نه تنها به پیاده‌سازی هوک پلاگین اجازه می‌دهد که نام محیط جاری را بداند، بلکه دسترسی به گزینه‌های پیکربندی محیط، اطلاعات گراف ماژول، و خط لوله تبدیل (transform pipeline) را نیز فراهم می‌کند (`environment.config`، `environment.moduleGraph`، `environment.transformRequest `). در دسترس بودن نمونه محیط در زمینه پلاگین به نویسندگان پلاگین این امکان را می‌دهد که از وابستگی به سرور توسعه کامل (که معمولاً از طریق هوک `configureServer` در ابتدای راه‌اندازی کش می‌شود) جلوگیری کنند. ## راهنمای مهاجرت برای انجام یک مهاجرت سریع در پلاگین‌های موجود، آرگومان `options.ssr` را با `this.environment.config.consumer === 'server'` در هوک‌های `resolveId`، `load` و `transform` جایگزین کنید: ```ts import { Plugin } from 'vite' export function myPlugin(): Plugin { return { name: 'my-plugin', resolveId(id, importer, options) { const isSSR = options.ssr // [!code --] const isSSR = this.environment.config.consumer === 'server' // [!code ++] if (isSSR) { // منطق خاص SSR } else { // منطق خاص Client } }, } } ``` برای یک پیاده‌سازی پایدارتر در بلندمدت، هوک پلاگین باید به جای تکیه بر نام محیط، به‌طور دقیق برای [چندین محیط](/guide/api-environment-plugins.html#accessing-the-current-environment-in-hooks) از گزینه‌های محیطی ریزدانه استفاده کند. --- --- url: /guide/api-hmr.md --- # API HMR :::tip نکته این API مربوط به سمت کلاینت برای HMR است. برای مدیریت به‌روزرسانی‌های HMR در پلاگین‌ها، [handleHotUpdate](./api-plugin#handlehotupdate) را ببینید. API دستی HMR عمدتاً برای توسعه‌دهندگان فریمورک‌ها و ابزارها طراحی شده است. به عنوان کاربر نهایی، احتمالاً HMR از قبل در قالب‌های اولیه خاص فریمورک‌ها برای شما مدیریت شده است. ::: Vite سپس API دستی HMR خود را از طریق آبجکت ویژه `import.meta.hot` در دسترس قرار می‌دهد: ```ts import type { ModuleNamespace } from 'vite/types/hot.d.ts' import type { CustomEventName, InferCustomEventPayload, } from 'vite/types/customEvent.d.ts' // ---cut--- interface ImportMeta { readonly hot?: ViteHotContext } interface ViteHotContext { readonly data: any accept(): void accept(cb: (mod: ModuleNamespace | undefined) => void): void accept(dep: string, cb: (mod: ModuleNamespace | undefined) => void): void accept( deps: readonly string[], cb: (mods: Array) => void, ): void dispose(cb: (data: any) => void): void prune(cb: (data: any) => void): void invalidate(message?: string): void on( event: T, cb: (payload: InferCustomEventPayload) => void, ): void off( event: T, cb: (payload: InferCustomEventPayload) => void, ): void send( event: T, data?: InferCustomEventPayload, ): void } ``` ## شرط لازم برای حفاظت (Conditional Guard) اول از همه، مطمئن شوید تمام استفاده‌های API HMR را درون یک بلوک شرطی قرار داده‌اید تا کد در محیط تولید (production) حذف شود (tree-shaken): ```js if (import.meta.hot) { // کد مربوط به HMR } ``` ## پشتیبانی از IntelliSense برای TypeScript Vite تعاریف نوع (type definitions) را برای `import.meta.hot` در [`vite/client.d.ts`](https://github.com/vitejs/vite/blob/main/packages/vite/client.d.ts) ارائه می‌دهد. می‌توانید یک فایل `vite-env.d.ts` در دایرکتوری `src` ایجاد کنید تا TypeScript این تعاریف نوع را تشخیص دهد: ```ts [vite-env.d.ts] /// ``` ## `hot.accept(cb)` برای اینکه یک ماژول به صورت خودکار تغییرات را بپذیرد (self-accept)، از `import.meta.hot.accept` با یک تابع بازگشتی (callback) استفاده کنید که ماژول به‌روزشده را دریافت می‌کند: ```js twoslash import 'vite/client' // ---cut--- export const count = 1 if (import.meta.hot) { import.meta.hot.accept((newModule) => { if (newModule) { // وقتی خطای نحوی رخ دهد newModule undefined خواهد بود console.log('updated: count is now ', newModule.count) } }) } ``` یک ماژول که تغییرات داغ را می‌پذیرد به عنوان **مرز HMR** (HMR boundary) در نظر گرفته می‌شود. HMR در Vite در واقع ماژول واردشده اصلی را جایگزین نمی‌کند: اگر یک ماژول مرز HMR، واردات (imports) را از یک وابستگی (dependency) مجدداً صادر (re-export) کند، مسئول به‌روزرسانی آن صادرات مجدد است (و این صادرات باید با استفاده از `let` تعریف شوند). علاوه بر این، واردکننده‌های (importers) بالادست در زنجیره از ماژول مرز، از تغییر مطلع نخواهند شد. این پیاده‌سازی ساده‌شده HMR برای بیشتر موارد استفاده در محیط توسعه کافی است، در حالی که از کار پرهزینه تولید ماژول‌های پراکسی (proxy) اجتناب می‌کند. Vite نیاز دارد که فراخوانی این تابع به صورت `import.meta.hot.accept(` (با حساسیت به فاصله‌ها) در کد منبع ظاهر شود تا ماژول بتواند به‌روزرسانی را بپذیرد. این یک نیاز برای تحلیل استاتیکی است که Vite برای فعال کردن پشتیبانی HMR برای یک ماژول انجام می‌دهد. ## `hot.accept(deps, cb)` یک ماژول همچنین می‌تواند به‌روزرسانی‌ها از وابستگی‌های مستقیم را بدون بارگذاری مجدد خود بپذیرد: ```js twoslash // @filename: /foo.d.ts export declare const foo: () => void // @filename: /example.js import 'vite/client' // ---cut--- import { foo } from './foo.js' foo() if (import.meta.hot) { import.meta.hot.accept('./foo.js', (newFoo) => { // تابع بازگشتی ماژول به‌روزشده './foo.js' را دریافت می‌کند newFoo?.foo() }) // همچنین می‌تواند آرایه‌ای از ماژول‌های وابستگی را بپذیرد: import.meta.hot.accept( ['./foo.js', './bar.js'], ([newFooModule, newBarModule]) => { // تابع بازگشتی آرایه‌ای دریافت می‌کند که فقط ماژول به‌روزشده // غیر null است. اگر به‌روزرسانی موفقیت‌آمیز نباشد (مثلاً خطای نحوی)، // آرایه خالی خواهد بود }, ) } ``` ## `hot.dispose(cb)` یک ماژول self-accepting یا ماژولی که انتظار دارد توسط دیگران پذیرفته شود، می‌تواند از `hot.dispose` برای پاکسازی اثرات جانبی پایدار ایجادشده توسط نسخه به‌روزشده استفاده کند: ```js twoslash import 'vite/client' // ---cut--- function setupSideEffect() {} setupSideEffect() if (import.meta.hot) { import.meta.hot.dispose((data) => { // پاکسازی اثر جانبی }) } ``` ## `hot.prune(cb)` یک تابع بازگشتی ثبت کنید که وقتی ماژول دیگر در صفحه import نشود فراخوانی می‌شود. در مقایسه با `hot.dispose`، اگر کد منبع اثرات جانبی را خودش در به‌روزرسانی‌ها پاکسازی می‌کند و فقط نیاز دارید هنگام حذف از صفحه پاکسازی شود، می‌توان از این استفاده کرد. Vite در حال حاضر از این برای واردات `.css` استفاده می‌کند. ```js twoslash import 'vite/client' // ---cut--- function setupOrReuseSideEffect() {} setupOrReuseSideEffect() if (import.meta.hot) { import.meta.hot.prune((data) => { // پاکسازی اثر جانبی }) } ``` ## `hot.data` شیء `import.meta.hot.data` بین نمونه‌های مختلف یک ماژول به‌روزشده حفظ می‌شود. می‌توان از آن برای انتقال اطلاعات از نسخه قبلی ماژول به نسخه بعدی استفاده کرد. توجه کنید که انتساب مجدد (re-assignment) خود `data` پشتیبانی نمی‌شود. در عوض، باید خصوصیت‌های شیء `data` را تغییر دهید تا اطلاعات اضافه‌شده از سایر هندلرها حفظ شوند. ```js twoslash import 'vite/client' // ---cut--- // صحیح import.meta.hot.data.someValue = 'hello' // پشتیبانی نمی‌شود import.meta.hot.data = { someValue: 'hello' } ``` ## `hot.decline()` این در حال حاضر یک noop است و برای سازگاری با نسخه‌های قبلی وجود دارد. اگر در آینده استفاده جدیدی برای آن ایجاد شود، ممکن است تغییر کند. برای نشان دادن اینکه ماژول قابلیت به‌روزرسانی داغ را ندارد، از `hot.invalidate()` استفاده کنید. ## `hot.invalidate(message?: string)` یک ماژول self-accepting ممکن است در زمان اجرا متوجه شود که نمی‌تواند یک به‌روزرسانی HMR را مدیریت کند، بنابراین باید به‌روزرسانی به صورت اجباری به واردکننده‌ها (importers) منتقل شود. با فراخوانی `import.meta.hot.invalidate()`، سرور HMR واردکننده‌های فراخواننده را باطل می‌کند، گویی فراخواننده self-accepting نبوده است. این یک پیام هم در کنسول مرورگر و هم در ترمینال ثبت می‌کند. می‌توانید یک پیام برای ارائه زمینه درباره دلیل باطل‌سازی ارسال کنید. توجه کنید که همیشه باید `import.meta.hot.accept` را فراخوانی کنید حتی اگر قصد دارید بلافاصله `invalidate` را فراخوانی کنید، در غیر این صورت کلاینت HMR به تغییرات آینده ماژول self-accepting گوش نخواهد داد. برای انتقال واضح هدف خود، توصیه می‌کنیم `invalidate` را درون تابع بازگشتی `accept` مانند زیر فراخوانی کنید: ```js twoslash import 'vite/client' // ---cut--- import.meta.hot.accept((module) => { // می‌توانید از نمونه جدید ماژول برای تصمیم‌گیری درباره باطل‌سازی استفاده کنید. if (cannotHandleUpdate(module)) { import.meta.hot.invalidate() } }) ``` ## `hot.on(event, cb)` به یک رویداد HMR گوش دهد. رویدادهای HMR زیر به صورت خودکار توسط Vite ارسال می‌شوند: * `'vite:beforeUpdate'` وقتی یک به‌روزرسانی در حال اعمال است (مثلاً یک ماژول جایگزین می‌شود) * `'vite:afterUpdate'` وقتی یک به‌روزرسانی اعمال شده است (مثلاً یک ماژول جایگزین شده است) * `'vite:beforeFullReload'` وقتی یک بارگذاری کامل در حال رخ دادن است * `'vite:beforePrune'` وقتی ماژول‌هایی که دیگر نیاز نیستند در حال حذف هستند * `'vite:invalidate'` وقتی یک ماژول با `import.meta.hot.invalidate()` باطل می‌شود * `'vite:error'` وقتی خطایی رخ می‌دهد (مثلاً خطای نحوی) * `'vite:ws:disconnect'` وقتی اتصال WebSocket قطع می‌شود * `'vite:ws:connect'` وقتی اتصال WebSocket (دوباره) برقرار می‌شود رویدادهای سفارشی HMR نیز می‌توانند از طریق پلاگین‌ها ارسال شوند. برای جزئیات بیشتر [handleHotUpdate](./api-plugin#handlehotupdate) را ببینید. ## `hot.off(event, cb)` حذف تابع بازگشتی از شنودگرهای رویداد. ## `hot.send(event, data)` ارسال رویدادهای سفارشی به سرور توسعه Vite. اگر قبل از اتصال فراخوانی شود، داده‌ها بافر شده و پس از برقراری اتصال ارسال می‌شوند. برای اطلاعات بیشتر، [ارتباط کلاینت-سرور](/guide/api-plugin.html#client-server-communication) را ببینید، شامل بخشی درباره [تایپ رویدادهای سفارشی](/guide/api-plugin.html#typescript-for-custom-events). ## مطالعه بیشتر اگر می‌خواهید بیشتر درباره نحوه استفاده از API HMR و نحوه کار آن در عمق یاد بگیرید، این منابع را بررسی کنید: * [Hot Module Replacement is Easy](https://bjornlu.com/blog/hot-module-replacement-is-easy) --- --- url: /guide/api-plugin.md --- # API پلاگین پلاگین‌های Vite بر پایه‌ی رابط پلاگین‌های Rollup ساخته شده‌اند و چند گزینه‌ی اضافی مخصوص Vite را ارائه می‌کنند. به همین دلیل، می‌توانید یک پلاگین Vite بنویسید که هم در محیط توسعه و هم در زمان Build قابل استفاده باشد. **پیشنهاد می‌شود قبل از مطالعه این بخش به مستندات [RollUp's plugin](https://rollupjs.org/plugin-development/) مراجعه کنید.** ## ساخت یک پلاگین Vite الگوهای از پیش تعریف‌ شده‌ای را ارائه می‌دهد، پس قبل از ساخت یک پلاگین جدید، حتماً [راهنمای ویژگی‌ها](https://vite.dev/guide/features) را بررسی کنید تا ببینید آیا نیاز شما قبلاً پوشش داده شده است یا خیر. همچنین، پلاگین‌هایی موجود در جامعه‌ی توسعه‌دهندگان را بررسی کنید؛ [پلاگین‌های سازگار با Rollup](https://github.com/rollup/awesome) و [پلاگین‌های مخصوص Vite](https://github.com/vitejs/awesome-vite#plugins). هنگام ایجاد یک پلاگین، می‌توانید آن را مستقیماً در فایل `vite.config.js` خود تعریف کنید. نیازی به ایجاد یک پکیج جداگانه نیست. اما اگر می‌خواهید که از پلاگین خود در پروژه‌های مختلف استفاده شود، می‌توانید آن را به اشتراک بگذارید تا به [دیگر توسعه‌دهندگان](https://chat.vite.dev) کمک کنید. ::: tip نکته هنگام یادگیری، دیباگ کردن یا ساخت پلاگین‌ها، توصیه می‌کنیم از [vite-plugin-inspect](https://github.com/antfu/vite-plugin-inspect) در پروژه‌ی خود استفاده کنید. این پلاگین به شما امکان مشاهده وضعیت پلاگین‌های Vite را می‌دهد. پس از نصب، می‌توانید با مراجعه به `localhost:5173/__inspect/‎` ماژول‌ها و فرآیند تغییرات پروژه‌ی خود را بررسی کنید. برای اطلاعات بیشتر، به [مستندات vite-plugin-inspect](https://github.com/antfu/vite-plugin-inspect) مراجعه کنید. ![vite-plugin-inspect](/assets/vite-plugin-inspect.y9xM77K_.png) ::: ## قراردادها اگر پلاگین شما از هوک‌های اختصاصی Vite استفاده نمی‌کند می‌تواند به‌عنوان یک [پلاگین سازگار با Rollup](#سازگاری-با-پلاگینهای-rollup) پیاده‌ سازی شود، توصیه می‌شود از [قراردادهای نام‌گذاری پلاگین‌های Rollup](https://rollupjs.org/plugin-development/#conventions) پیروی کنید. * نام پلاگین باید واضح باشد و با پیشوند `-rollup-plugin` شروع شود. * در فایل `package.json`، کلمات کلیدی `rollup-plugin` و `vite-plugin` را اضافه کنید. این کار باعث می‌شود پلاگین شما نه‌تنها در Vite، بلکه در Rollup خالص یا پروژه‌های مبتنی بر WMR نیز قابل استفاده باشد. برای پلاگین‌های اختصاصی Vite: * نام پلاگین باید واضح باشد و با پیشوند `-vite-plugin` شروع شود. * در فایل package.json، کلیدواژه‌ی `vite-plugin` را اضافه کنید. * در مستندات پلاگین توضیح دهید که چرا این پلاگین فقط مخصوص Vite است (مثلاً اگر از هوک‌های مخصوص Vite استفاده می‌کند). اگر پلاگین شما فقط برای یک فریمورک خاص طراحی شده است، نام آن باید شامل نام فریمورک باشد: * `-vite-plugin-vue` برای پلاگین‌های Vue * `-vite-plugin-react` برای پلاگین‌های React * `-vite-plugin-svelte` برای پلاگین‌های Svelte برای اطلاعات بیشتر، به بخش [قراردادهای ماژول‌های مجازی](#قرارداد-ماژولهای-مجازی) مراجعه کنید. ## تنظیمات پلاگین‌ها پلاگین‌ها به `devDependencies` پروژه اضافه می‌شود و از طریق آرایه‌ی `plugins` پیکربندی می‌شود. ```js [vite.config.js] import vitePlugin from 'vite-plugin-feature' import rollupPlugin from 'rollup-plugin-feature' export default defineConfig({ plugins: [vitePlugin(), rollupPlugin()], }) ``` پلاگین‌های Falsy نادیده گرفته می‌شوند، بنابراین می‌توان از این ویژگی برای فعال یا غیرفعال کردن پلاگین‌ها استفاده کرد. آرایه‌ی `plugins` از پیش‌تنظیم‌ها پشتیبانی می‌کند که شامل چندین پلاگین در یک عنصر واحد هستند. این ویژگی برای قابلیت‌های پیچیده (مانند یکپارچه‌سازی با فریمورک‌ها) که از چند پلاگین تشکیل شده‌اند، مفید است. این آرایه به‌صورت داخلی تبدیل به یک لیست مسطح (Flattened) خواهد شد. ```js // framework-plugin import frameworkRefresh from 'vite-plugin-framework-refresh' import frameworkDevtools from 'vite-plugin-framework-devtools' export default function framework(config) { return [frameworkRefresh(config), frameworkDevTools(config)] } ``` ```js [vite.config.js] import { defineConfig } from 'vite' import framework from 'vite-plugin-framework' export default defineConfig({ plugins: [framework()], }) ``` ## مثال های ساده :::tip نکته طبق یک قرارداد رایج، پلاگین‌های Vite/Rollup به‌صورت تابع کارخانه‌ای (Factory Function) نوشته می‌شوند که پلاگین را به صورت یک آبجکت بازمی‌گرداند. این تابع می‌تواند گزینه‌هایی (Options) را بپذیرد که به کاربران اجازه می‌دهد پلاگین را سفارشی‌سازی کنند. ::: ### تبدیل انواع فایل‌های سفارشی ```js const fileRegex = /\.(my-file-ext)$/ export default function myPlugin() { return { name: 'transform-file', transform(src, id) { if (fileRegex.test(id)) { return { code: compileFileToJS(src), map: null, // provide source map if available } } }, } } ``` ### استفاده از یک فایل مجازی مثال‌ها را در [بخش بعدی](#قرارداد-ماژولهای-مجازی) ببینید. ## قرارداد ماژول‌های مجازی ماژول‌های مجازی یک روش کاربردی هستند که به شما امکان می‌دهند اطلاعات مربوط به زمان ساخت (build time) را با استفاده از سینتکس معمولی ایمپورت ESM به فایل‌های سورس منتقل کنید. ```js export default function myPlugin() { const virtualModuleId = 'virtual:my-module' const resolvedVirtualModuleId = '\0' + virtualModuleId return { name: 'my-plugin', // required, will show up in warnings and errors resolveId(id) { if (id === virtualModuleId) { return resolvedVirtualModuleId } }, load(id) { if (id === resolvedVirtualModuleId) { return `export const msg = "from virtual module"` } }, } } ``` که این امکان را فراهم می‌کند تا ماژول را در جاوااسکریپت ایمپورت کنید: ```js import { msg } from 'virtual:my-module' console.log(msg) ``` ماژول‌های مجازی در Vite (و Rollup) به‌طور قراردادی با پیشوند `virtual` شروع می‌شوند: برای مسیرهای قابل مشاهده توسط کاربر آغاز می‌شوند. اگر ممکن باشد، باید از نام پلاگین به‌عنوان یک فضای نام برای جلوگیری از تداخل با پلاگین‌های دیگر در اکوسیستم استفاده کرد. به‌عنوان مثال، یک `vite-plugin-posts` ممکن است از کاربران بخواهد که `virtual:posts` یا `virtual:posts/helpers` را به‌عنوان ماژول‌های مجازی وارد کنند تا اطلاعات زمان ساخت را دریافت کنند. از نظر داخلی، پلاگین‌هایی که از ماژول‌های مجازی استفاده می‌کنند باید شناسه ماژول را هنگام حل کردن، با پیشوند `‎\0` علامت‌گذاری کنند. این یک قرارداد از اکوسیستم Rollup است که از پردازش شناسه توسط سایر پلاگین‌ها (مانند Node resolution) جلوگیری می‌کند. همچنین ویژگی‌های اصلی مانند sourcemaps می‌توانند از این اطلاعات برای تمایز میان ماژول‌های مجازی و فایل‌های معمولی استفاده کنند. `‎\0`به‌عنوان یک کاراکتر مجاز در آدرس‌های ایمپورت شناخته نمی‌شود، بنابراین هنگام تجزیه و تحلیل ایمپورت باید آن را جایگزین کنیم. شناسه ماژول مجازی با `‎\0{id}` در نهایت در توسعه در مرورگر به صورت `‎/@id/__x00__{id}` کدگذاری می‌شود. این شناسه قبل از وارد شدن به پایپ‌لاین پلاگین‌ها مجدداً رمزگشایی می‌شود، بنابراین این مورد توسط کدهای هوک پلاگین‌ها دیده نمی‌شود. توجه داشته باشید که ماژول‌هایی که به‌طور مستقیم از یک فایل واقعی مشتق شده‌اند، مانند ماژول اسکریپت در یک کامپوننت تک‌ فایلی (مانند فایل‌های ‎.vue یا ‎.svelte)، نیازی به پیروی از این قرارداد ندارند. کامپوننت‌های تک‌فایلی معمولاً مجموعه‌ای از زیرماژول‌ها را هنگام پردازش تولید می‌کنند، اما کد در این ماژول‌ها می‌تواند به سیستم فایل بازگردانده شود. استفاده از `‎\0` برای این زیرماژول‌ها باعث می‌شود که sourcemaps به‌درستی کار نکند. ## هوک‌های عمومی در زمان توسعه، سرور توسعه Vite یک کانتینر پلاگین ایجاد می‌کند که [هوک‌های ساخت Rollup](https://rollupjs.org/plugin-development/#build-hooks) را به همان شیوه‌ای که Rollup انجام می‌دهد، فراخوانی می‌کند. هوک‌های زیر یک‌بار در زمان شروع سرور فراخوانی می‌شوند: * [`options`](https://rollupjs.org/plugin-development/#options) * [`buildStart`](https://rollupjs.org/plugin-development/#buildstart) هوک‌های زیر برای هر درخواست ماژول فراخوانی می‌شوند: * [`resolveId`](https://rollupjs.org/plugin-development/#resolveid) * [`load`](https://rollupjs.org/plugin-development/#load) * [`transform`](https://rollupjs.org/plugin-development/#transform) این هوک‌ها همچنین دارای پارامتر `options` گسترش‌یافته‌ای هستند که شامل ویژگی‌های خاص Vite می‌شود. برای اطلاعات بیشتر می‌توانید به [مستندات SSR](/guide/ssr#ssr-specific-plugin-logic) مراجعه کنید. برخی از فراخوانی‌های `resolveId` ممکن است مقدار `importer` را به‌صورت یک مسیر مطلق برای یک فایل کلی `index.html` در ریشه دریافت کنند. این به این دلیل است که به دلیل الگوی سرور توسعه بدون باندل Vite، همیشه امکان تعیین دقیق ایمپورت‌‌کننده (importer) وجود ندارد. با این حال، برای ایمپورت‌هایی که در مسیر حل وابستگی‌های Vite پردازش می‌شوند، ایمپورت‌‌کننده را می‌توان در مرحله‌ی تحلیل ایمپورت‌ها ردیابی کرد و مقدار صحیح `importer` را ارائه داد. هوک‌های زیر هنگامی که سرور بسته می‌شود، فراخوانی می‌شوند: * [`buildEnd`](https://rollupjs.org/plugin-development/#buildend) * [`closeBundle`](https://rollupjs.org/plugin-development/#closebundle) توجه داشته باشید که هوک [`moduleParsed`](https://rollupjs.org/plugin-development/#moduleparsed) در زمان توسعه **فراخوانی نمی‌شود**، زیرا Vite برای بهبود عملکرد از تجزیه کامل AST اجتناب می‌کند. هوک‌های تولید خروجی [Output Generation Hooks](https://rollupjs.org/plugin-development/#output-generation-hooks) (به‌جز `closeBundle`) در زمان توسعه **فراخوانی نمی‌شوند**. شما می‌توانید سرور توسعه Vite را به‌عنوان فراخوانی فقط `rollup.rollup()‎` بدون فراخوانی `bundle.generate()‎` در نظر بگیرید. ## هوک های مخصوص Vite پلاگین‌های Vite می‌توانند هوک‌هایی ارائه دهند که مخصوص Vite هستند. این هوک‌ها توسط Rollup نادیده گرفته می‌شوند. ### `config` * **تایپ:** `‎(config: UserConfig, env: { mode: string, command: string }) => UserConfig | null | void` * **نوع اجرا:** `async`, `sequential` این هوک به شما امکان می‌دهد قبل از اینکه پیکربندی Vite نهایی شود، آن را تغییر دهید. این هوک پیکربندی اولیه کاربر (ترکیب گزینه‌های خط فرمان و فایل پیکربندی) و همچنین محیط جاری پیکربندی را دریافت می‌کند که شامل `mode` و `command` است. می‌تواند یک آبجکت پیکربندی جزئی را بازگرداند که در پیکربندی موجود ادغام می‌شود، یا می‌تواند مستقیماً پیکربندی را تغییر دهد (اگر ادغام پیش‌فرض نتیجه مطلوب را ارائه ندهد). **مثال:** ```js // return partial config (recommended) const partialConfigPlugin = () => ({ name: 'return-partial', config: () => ({ resolve: { alias: { foo: 'bar', }, }, }), }) // mutate the config directly (use only when merging doesn't work) const mutateConfigPlugin = () => ({ name: 'mutate-config', config(config, { command }) { if (command === 'build') { config.root = 'foo' } }, }) ``` ::: warning نکته پلاگین‌های کاربر قبل از اجرای این هوک پردازش می‌شوند، بنابراین اضافه کردن پلاگین‌های دیگر داخل هوک `config` تأثیری نخواهد داشت. ::: ### `configResolved` * **تایپ:** `‎(config: ResolvedConfig) => void | Promise‎` * **نوع اجرا:** `async`, `parallel` این هوک بعد از نهایی شدن تنظیمات Vite اجرا می‌شود. از این هوک برای خواندن و ذخیره تنظیمات نهایی استفاده کنید. همچنین زمانی مفید است که پلاگین نیاز دارد بر اساس دستوری که اجرا شده رفتار متفاوتی داشته باشد. **مثال:** ```js const examplePlugin = () => { let config return { name: 'read-config', configResolved(resolvedConfig) { // store the resolved config config = resolvedConfig }, // use stored config in other hooks transform(code, id) { if (config.command === 'serve') { // dev: plugin invoked by dev server } else { // build: plugin invoked by Rollup } }, } } ``` در نظر داشته باشید که مقدار `command` در حالت توسعه (dev) معادل `serve` است (در cli، دستورات `vite`، `vite dev` و `vite serve` معادل هم هستند). ### `configureServer` * **تایپ:** `‎(server: ViteDevServer) => (() => void) | void | Promise<(() => void) | void>‎` * **نوع اجرا:** `async`, `sequential` * **همچنین ببینید:** [ViteDevServer](./api-javascript#vitedevserver) این هوک برای پیکربندی سرور توسعه استفاده می‌شود. رایج‌ترین کاربرد آن افزودن میان‌افزارهای (middlewares) سفارشی به برنامه داخلی [connect](https://github.com/senchalabs/connect) است: ```js const myPlugin = () => ({ name: 'configure-server', configureServer(server) { server.middlewares.use((req, res, next) => { // custom handle request... }) }, }) ``` **افزودن میان‌افزار** هوک `configureServer` قبل از نصب میان‌افزارهای داخلی اجرا می‌شود، بنابراین میان‌افزارهای سفارشی به‌صورت پیش‌فرض قبل از میان‌افزارهای داخلی اجرا خواهند شد. اگر بخواهید یک میان‌افزار را **بعد از** میان‌افزارهای داخلی اضافه کنید، می‌توانید یک تابع از `configureServer` بازگردانید. این تابع پس از نصب میان‌افزارهای داخلی فراخوانی خواهد شد: ```js const myPlugin = () => ({ name: 'configure-server', configureServer(server) { // return a post hook that is called after internal middlewares are // installed return () => { server.middlewares.use((req, res, next) => { // custom handle request... }) } }, }) ``` **ذخیره دسترسی به سرور** در برخی موارد، سایر هوک‌های پلاگین ممکن است به نمونه سرور توسعه دسترسی داشته باشند (مثلاً برای دسترسی به سرور web socket، پایشگر سیستم فایل، یا گراف ماژول‌ها). این هوک می‌تواند برای ذخیره نمونه سرور و استفاده از آن در سایر هوک‌ها نیز استفاده شود: ```js const myPlugin = () => { let server return { name: 'configure-server', configureServer(_server) { server = _server }, transform(code, id) { if (server) { // use server... } }, } } ``` توجه داشته باشید که `configureServer` هنگام اجرای نسخه نهایی فراخوانی نمی‌شود، بنابراین سایر هوک‌های شما باید مراقب نبود آن باشند. ### `configurePreviewServer` * **تایپ:** `‎(server: PreviewServer) => (() => void) | void | Promise<(() => void) | void>‎` * **نوع اجرا:** `async`, `sequential` * **همچنین ببینید:** [PreviewServer](./api-javascript#previewserver) این هوک مشابه [`configureServer`](/guide/api-plugin.html#configureserver) است اما برای سرور پیش‌نمایش (preview server) استفاده می‌شود. درست مانند `configureServer`، این هوک قبل از نصب سایر میان‌افزارها اجرا می‌شود. اگر می‌خواهید یک میان‌افزار را بعد از سایر میان‌افزارها اضافه کنید، می‌توانید یک تابع از `configurePreviewServer` برگردانید که بعد از نصب میان‌افزارهای داخلی فراخوانی خواهد شد: ```js const myPlugin = () => ({ name: 'configure-preview-server', configurePreviewServer(server) { // return a post hook that is called after other middlewares are // installed return () => { server.middlewares.use((req, res, next) => { // custom handle request... }) } }, }) ``` ### `transformIndexHtml` * **تایپ:** `IndexHtmlTransformHook | { order?: 'pre' | 'post', handler: IndexHtmlTransformHook }‎` * **نوع اجرا:** `async`, `sequential` این هوک برای تغییر و پردازش فایل‌های HTML مانند `index.html` در نظر گرفته شده است. این هوک مقدار HTML فعلی و یک context transform را دریافت می‌کند. Context transform در حالت dev شامل نمونه‌ای از [`ViteDevServer`](./api-javascript#vitedevserver) است و در حالت build شامل بسته خروجی Rollup می‌شود. این هوک می‌تواند async باشد و یکی از موارد زیر را برگرداند: * رشته HTML تغییر یافته * یک آرایه از اشیای توصیف‌کننده (`{tag, attr, children}`) که به HTML موجود اضافه شوند. (هر تگ می‌تواند مشخص کند که در کجای صفحه قرار بگیرد، پیش‌فرض: ابتدای `` قرار می‌گیرد.) * یک آبجکت شامل هر دو مورد فوق به صورت `{ html, tags }` به‌طور پیش‌فرض مقدار `order` روی `undefined` تنظیم شده است، به این معنا که این هوک بعد از پردازش HTML اجرا می‌شود.اگر بخواهید یک اسکریپت را به HTML اضافه کنید و این اسکریپت از پردازش پلاگین‌های Vite عبور کند، باید `order: 'pre'‎` را تنظیم کنید. و اگر بخواهید هوک شما بعد از همه‌ی هوک‌هایی که مقدار `order` آن‌ها undefined است اجرا شود، `order: 'post'‎` را تنظیم کنید. **مثال:** ```js const htmlPlugin = () => { return { name: 'html-transform', transformIndexHtml(html) { return html.replace( /(.*?)<\/title>/, `<title>Title replaced!`, ) }, } } ``` **امضاء کامل هوک:** ```ts type IndexHtmlTransformHook = ( html: string, ctx: { path: string filename: string server?: ViteDevServer bundle?: import('rollup').OutputBundle chunk?: import('rollup').OutputChunk }, ) => | IndexHtmlTransformResult | void | Promise type IndexHtmlTransformResult = | string | HtmlTagDescriptor[] | { html: string tags: HtmlTagDescriptor[] } interface HtmlTagDescriptor { tag: string attrs?: Record children?: string | HtmlTagDescriptor[] /** * default: 'head-prepend' */ injectTo?: 'head' | 'body' | 'head-prepend' | 'body-prepend' } ``` ::: warning نکته این هوک در صورتی فراخوانی نخواهد شد که از فریم‌ورکی استفاده کنید که مدیریت سفارشی فایل‌های ورودی را انجام می‌دهد (برای مثال [SvelteKit](https://github.com/sveltejs/kit/discussions/8269#discussioncomment-4509145)). ::: ### `handleHotUpdate` * **تایپ:** `‎(ctx: HmrContext) => Array | void | Promise | void>‎` * **همچنین ببینید:** [HMR API](./api-hmr) این هوک برای انجام مدیریت سفارشی بروزرسانی HMR (Hot Module Replacement) استفاده می‌شود. این هوک یک آبجکت کانتکست دریافت می‌کند که دارای امضای زیر است: ```ts interface HmrContext { file: string timestamp: number modules: Array read: () => string | Promise server: ViteDevServer } ``` * `modules`: آرایه‌ای از ماژول‌ها است که تحت تأثیر فایل تغییر یافته قرار گرفته‌اند. آرایه است زیرا یک فایل ممکن است به چندین ماژول سرو شده مربوط باشد (مثل SFC‌های Vue). * `read`: یک تابع خواندن غیرهمزمان است که محتوای فایل را باز می‌گرداند. این تابع فراهم شده است زیرا در برخی سیستم‌ها، callback تغییر فایل ممکن است خیلی سریع اجرا شود پیش از اینکه ویرایشگر فایل را به‌طور کامل به‌روزرسانی کند و فراخوانی مستقیم `fs.readFile` ممکن است محتوای خالی برگرداند. تابع read این رفتار را نرمال می‌کند. هوک می‌تواند تصمیم بگیرد که: * لیست ماژول‌های تحت تأثیر را فیلتر کرده و دقیق‌تر کند تا HMR (Hot Module Replacement) دقیق‌تر باشد. * یک آرایه خالی برگرداند و یک بار بارگذاری کامل انجام دهد: ```js handleHotUpdate({ server, modules, timestamp }) { // Invalidate modules manually const invalidatedModules = new Set() for (const mod of modules) { server.moduleGraph.invalidateModule( mod, invalidatedModules, timestamp, true ) } server.ws.send({ type: 'full-reload' }) return [] } ``` * یک آرایه خالی برگرداند و انجام مدیریت کامل HMR سفارشی را با ارسال رویدادهای سفارشی به کلاینت انجام دهد: ```js handleHotUpdate({ server }) { server.ws.send({ type: 'custom', event: 'special-update', data: {} }) return [] } ``` کد کلاینت باید هندلر مربوطه را با استفاده از [API HMR](./api-hmr) ثبت کند (این می‌تواند از طریق هوک transform همان پلاگین اضافه شود): ```js if (import.meta.hot) { import.meta.hot.on('special-update', (data) => { // perform custom update }) } ``` ## ترتیب اجرای پلاگین‌ها در Vite یک پلاگین در Vite می‌تواند ویژگی `enforce` را مشخص کند (مشابه لودرهای Webpack) تا ترتیب اجرای آن را تنظیم کند. مقدار `enforce` می‌تواند `"pre"` یا `"post"`باشد. ترتیب اجرای پلاگین‌ها پس از پردازش به شکل زیر خواهد بود: * Alias * پلاگین‌های کاربر با `enforce: 'pre'‎` * پلاگین‌های هسته‌ای Vite * پلاگین‌های کاربر بدون مقدار `enforce` * پلاگین‌های مربوط به ساخت (build) در Vite * پلاگین‌های کاربر با `enforce: 'post'‎` * پلاگین‌های پس از ساخت Vite (مانند minify، manifest، گزارش‌گیری) توجه داشته باشید که این ترتیب جدا از ترتیب اجرای هوک‌ها است، زیرا هوک‌ها همچنان مطابق با مقدار `order` خود در [Rollup](https://rollupjs.org/plugin-development/#build-hooks) پردازش می‌شوند. ## برنامه های شرطی به‌طور پیش‌فرض، پلاگین‌ها هم در حالت توسعه (serve) و هم در حالت بیلد (build) اجرا می‌شوند. اما اگر پلاگین‌ای فقط در یکی از این دو حالت موردنیاز باشد، می‌توان از ویژگی `apply` برای مشخص کردن اینکه پلاگین فقط در `'build'` یا `'serve'` اجرا شود: ```js function myPlugin() { return { name: 'build-only', apply: 'build', // or 'serve' } } ``` همچنین می‌توان از یک تابع برای کنترل دقیق‌تر استفاده کرد: ```js apply(config, { command }) { // apply only on build but not for SSR return command === 'build' && !config.build.ssr } ``` ## سازگاری با پلاگین‌های Rollup تعداد قابل توجهی از پلاگین‌های Rollup مستقیماً به عنوان پلاگین Vite کار می‌کنند (مثلاً `‎@rollup/plugin-alias` یا `‎@rollup/plugin-json`) اما نه همه آن‌ها، زیرا برخی از هوک‌های پلاگین در یک سرور توسعه بدون باندل معنایی ندارند. به طور کلی، اگر یک پلاگین Rollup دارای شرایط زیر باشد، باید بدون مشکل به عنوان پلاگین Vite کار کند: * از هوک [`moduleParsed`](https://rollupjs.org/plugin-development/#moduleparsed) استفاده نمی‌کند. * وابستگی زیاد بین هوک‌های مربوط به فاز باندل و فاز خروجی ندارد. اگر یک پلاگین Rollup فقط برای مرحله ساخت (build) مناسب باشد، می‌توان آن را در `build.rollupOptions.plugins` مشخص کرد. این کار همان عملکردی را خواهد داشت که یک پلاگین Vite با `enforce: 'post'‎` و `apply: 'build'‎` دارد. همچنین می‌توان یک پلاگین Rollup موجود را با ویژگی‌های مخصوص Vite تقویت کرد: ```js [vite.config.js] import example from 'rollup-plugin-example' import { defineConfig } from 'vite' export default defineConfig({ plugins: [ { ...example(), enforce: 'post', apply: 'build', }, ], }) ``` ## نرمال‌سازی مسیرها Vite در هنگام حل شناسه‌ها مسیرها را نرمال‌سازی می‌کند تا از جداکننده‌های POSIX ( / ) استفاده کند، در حالی که در ویندوز، حجم درایو را حفظ می‌کند. از طرف دیگر، Rollup به‌طور پیش‌فرض مسیرهای حل‌شده را دست‌نخورده نگه می‌دارد، بنابراین شناسه‌های حل‌شده در ویندوز از جداکننده‌های ( \ ) win32 استفاده می‌کنند. با این حال، پلاگین‌های Rollup به‌صورت داخلی از [تابع کمکی `normalizePath`](https://github.com/rollup/plugins/tree/master/packages/pluginutils#normalizepath) از `‎@rollup/pluginutils` استفاده می‌کنند، که جداکننده‌ها را قبل از انجام مقایسه‌ها به فرمت POSIX تبدیل می‌کند. این بدان معناست که هنگام استفاده از این پلاگین‌ها در Vite، مقادیر `include` و `exclude` در الگوهای پیکربندی و سایر مسیرهای مشابه در مقایسه با شناسه‌های حل‌شده به‌درستی کار می‌کنند. بنابراین، برای پلاگین‌های Vite، هنگام مقایسه مسیرها با شناسه‌های حل‌شده، مهم است که ابتدا مسیرها را نرمال‌سازی کرده و از جداکننده‌های POSIX (`/`) استفاده کنید. یک تابع کمکی معادل normalizePath نیز از ماژول vite صادر شده است. ```js import { normalizePath } from 'vite' normalizePath('foo\\bar') // 'foo/bar' normalizePath('foo/bar') // 'foo/bar' ``` ## فیلتر کردن، الگوی include/exclude Vite تابع [`createFilter` از بسته ‎`@rollup/pluginutils`](https://github.com/rollup/plugins/tree/master/packages/pluginutils#createfilter) را در دسترس قرار می‌دهد تا پلاگین‌ها و یکپارچه‌سازی‌های مخصوص Vite از الگوی استاندارد فیلتر کردن include/exclude استفاده کنند. این الگو در خود هسته Vite نیز به کار می‌رود. ## ارتباط کلاینت-سرور از نسخه 2.9، Vite ابزارهایی را برای پلاگین‌ها فراهم می‌کند تا به ارتباط با کلاینت‌ها کمک کنند. ### سرور به کلاینت در سمت پلاگین، می‌توان از `server.ws.send` برای ارسال رویدادها به کلاینت استفاده کرد: ```js [vite.config.js] export default defineConfig({ plugins: [ { // ... configureServer(server) { server.ws.on('connection', () => { server.ws.send('my:greetings', { msg: 'hello' }) }) }, }, ], }) ``` ::: tip نکته توصیه می‌کنیم **همیشه یک پیشوند** به نام رویدادهای خود اضافه کنید تا از تداخل با سایر پلاگین‌ها جلوگیری شود. ::: در سمت کلاینت، از [`hot.on`](/guide/api-hmr.html#hot-on-event-cb) برای گوش دادن به رویدادها استفاده کنید: ```ts twoslash import 'vite/client' // ---cut--- // client side if (import.meta.hot) { import.meta.hot.on('my:greetings', (data) => { console.log(data.msg) // hello }) } ``` ### کلاینت به سرور برای ارسال رویدادها از کلاینت به سرور، می‌توان از [`hot.send`](/guide/api-hmr.html#hot-send-event-payload) استفاده کرد: ```ts // client side if (import.meta.hot) { import.meta.hot.send('my:from-client', { msg: 'Hey!' }) } ``` سپس از `server.ws.on` استفاده کنید و به رویدادها در سمت سرور گوش دهید. ```js [vite.config.js] export default defineConfig({ plugins: [ { // ... configureServer(server) { server.ws.on('my:from-client', (data, client) => { console.log('Message from client:', data.msg) // Hey! // reply only to the client (if needed) client.send('my:ack', { msg: 'Hi! I got your message!' }) }) }, }, ], }) ``` ### TypeScript برای رویدادهای سفارشی به‌صورت داخلی، Vite تایپ payload را از رابط `CustomEventMap` استنتاج می‌کند. می‌توان رویدادهای سفارشی را با گسترش این ساختار گسترش داد: :::tip نکته باید هنگام مشخص کردن فایل‌های تعریف ساختار تایپ‌اسکریپت، حتماً پسوند `d.ts.` را اضافه کنید. در غیر این صورت، تایپ‌اسکریپت ممکن است نتواند تشخیص دهد که ساختار فایل چیست. ::: ```ts [events.d.ts] import 'vite/types/customEvent.d.ts' declare module 'vite/types/customEvent.d.ts' { interface CustomEventMap { 'custom:foo': { msg: string } // 'event-key': payload } } ``` این تعریف ساختار توسط ` import.meta.hot?.on('custom:foo', (payload) => { // The type of payload will be { msg: string } }) import.meta.hot?.on('unknown:event', (payload) => { // The type of payload will be any }) ``` --- --- url: /guide/api-environment-plugins.md --- # API محیط برای پلاگین‌ها :::warning آزمایشی رابط Environment API هنوز در مرحله‌ی آزمایشی (experimental) هست. با این حال، ما تلاش می‌کنیم بین نسخه‌های اصلی (major) پایداری این APIها را حفظ کنیم تا جامعه‌ی توسعه‌دهندگان بتوانند با آن‌ها کار کرده و تجربیات خود را بر اساس آن‌ها توسعه دهند. ما قصد داریم این APIهای جدید را در یکی از نسخه‌های اصلی آینده به حالت پایدار (stable) برسانیم. البته ممکن است در این فرآیند تغییرات شکننده (breaking changes) نیز اعمال شود، اما این کار زمانی انجام خواهد شد که پروژه‌ها و کتابخانه‌های وابسته فرصت کافی برای آزمایش و ارزیابی این قابلیت‌های جدید را داشته باشند. منابع: * [بحث و گفتگو](https://github.com/vitejs/vite/discussions/16358) جایی که ما در حال جمع‌آوری نظرات درباره APIهای جدید هستیم. * [PR مربوط به Environment API](https://github.com/vitejs/vite/pull/16471) جایی که API جدید پیاده‌سازی و بررسی شده است. لطفاً نظرات و بازخوردهای خود را با ما به اشتراک بگذارید. ::: ## دسترسی به محیط فعلی در هوک‌ها از آنجا که تا نسخه Vite 6 فقط دو محیط وجود داشت (`client` و `ssr`)، یک بولین `ssr` برای شناسایی محیط فعلی در APIهای Vite کافی بود. هوک‌های پلاگین یک بولین `ssr` را در آخرین پارامتر گزینه‌ها دریافت می‌کردند و API ها انتظار داشتند که یک پارامتر `ssr` اختیاری برای ارتباط صحیح ماژول‌ها با محیط مناسب ارائه شود (برای مثال `server.moduleGraph.getModuleByUrl(url, { ssr })`). با معرفی محیط‌های قابل پیکربندی، اکنون یک روش یکنواخت برای دسترسی به گزینه‌ها و نمونه‌های محیط در پلاگین‌ها وجود دارد. هوک‌های پلاگین اکنون `this.environment` را در کانتکست خود ارائه می‌دهند و APIهایی که قبلاً به یک بولین `ssr` نیاز داشتند، اکنون به محیط مناسب محدود شده‌اند (برای مثال `environment.moduleGraph.getModuleByUrl(url)`). سرور Vite یک مسیر پردازش پلاگین مشترک دارد، اما زمانی که یک ماژول پردازش می‌شود، همیشه در کانتکست یک محیط مشخص انجام می‌شود. نمونه `environment` در کانتکست پلاگین در دسترس است. یک پلاگین می‌تواند از نمونه `environment` برای تغییر نحوه پردازش یک ماژول بر اساس پیکربندی محیط استفاده کند (که می‌توان از طریق `environment.config` به آن دسترسی داشت). ```ts transform(code, id) { console.log(this.environment.config.resolve.conditions) } ``` ## ثبت محیط‌های جدید با استفاده از هوک‌ها پلاگین‌ها می‌توانند محیط‌های جدیدی را در هوک `config` اضافه کنند (برای مثال، برای داشتن یک گراف ماژول جداگانه برای [RSC](https://react.dev/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023#react-server-components)): ```ts config(config: UserConfig) { config.environments.rsc ??= {} } ``` یک آبجکت خالی برای ثبت محیط کافی است، زیرا مقادیر پیش‌فرض از تنظیمات محیط از ریشه گرفته می‌شوند. ## پیکربندی محیط با استفاده از هوک‌ها در زمان اجرای هوک `config`، لیست کامل محیط‌ها هنوز مشخص نیست و محیط‌ها می‌توانند تحت تأثیر مقادیر پیش‌فرض از تنظیمات محیط در سطح ریشه یا به صورت صریح از طریق رکورد `config.environments` قرار گیرند. پلاگین‌ها باید مقادیر پیش‌فرض را با استفاده از هوک `config` تنظیم کنند. برای پیکربندی هر محیط، می‌توانند از هوک جدید `configEnvironment` استفاده کنند. این هوک برای هر محیط با تنظیمات جزئی اضافه‌شده آن، شامل مقادیر پیش‌فرض نهایی، فراخوانی می‌شود. ```ts configEnvironment(name: string, options: EnvironmentOptions) { if (name === 'rsc') { options.resolve.conditions = // ... ``` ## هوک `hotUpdate` * **تایپ:** `‎(this: { environment: DevEnvironment }, options: HotUpdateOptions) => Array | void | Promise | void>‎` * **همچنین ببینید:** [HMR API](./api-hmr) هوک `hotUpdate` به پلاگین‌ها اجازه می‌دهد تا مدیریت به‌روزرسانی HMR سفارشی را برای یک محیط خاص انجام دهند. زمانی که یک فایل تغییر می‌کند، الگوریتم HMR برای هر محیط به ترتیب موجود در `server.environments` به صورت سری اجرا می‌شود، بنابراین هوک `hotUpdate` چندین بار فراخوانی خواهد شد. این هوک یک آبجکت کانتکست با امضای زیر دریافت می‌کند: ```ts interface HotUpdateOptions { type: 'create' | 'update' | 'delete' file: string timestamp: number modules: Array read: () => string | Promise server: ViteDevServer } ``` * `this.environment` محیط اجرایی ماژول است که در آن به‌روزرسانی فایل در حال پردازش است. * `modules` آرایه‌ای از ماژول‌ها در این محیط است که تحت تأثیر فایل تغییر یافته قرار گرفته‌اند. این آرایه شامل چندین ماژول است، زیرا یک فایل ممکن است به چندین ماژول سرو شده نگاشت شود (مثلاً در Vue SFCها). * `read` یک تابع خواندن غیرهمزمان است که محتوای فایل را برمی‌گرداند. این تابع ارائه شده است زیرا در برخی سیستم‌ها، ممکن است callback تغییر فایل خیلی سریع اجرا شود، قبل از اینکه ویرایشگر فایل را به‌طور کامل به‌روزرسانی کند، و در این حالت استفاده مستقیم از `fs.readFile` محتوای خالی برمی‌گرداند. تابع `read` این رفتار را نرمال‌سازی می‌کند. این هوک می‌تواند: * لیست ماژول‌های تحت تأثیر را فیلتر کرده و محدود کند تا HMR دقیق‌تر انجام شود. * یک آرایه خالی برگرداند و بارگذاری کامل را انجام دهد: ```js hotUpdate({ modules, timestamp }) { if (this.environment.name !== 'client') return // Invalidate modules manually const invalidatedModules = new Set() for (const mod of modules) { this.environment.moduleGraph.invalidateModule( mod, invalidatedModules, timestamp, true ) } this.environment.hot.send({ type: 'full-reload' }) return [] } ``` * آرایه خالی برگردانید و مدیریت کامل HMR سفارشی را با ارسال رویدادهای سفارشی به کلاینت انجام دهید: ```js hotUpdate() { if (this.environment.name !== 'client') return this.environment.hot.send({ type: 'custom', event: 'special-update', data: {} }) return [] } ``` کد کلاینت باید با استفاده از [HMR API](./api-hmr) هندلر مربوطه را ثبت کند (این کار می‌تواند توسط هوک `transform` همان پلاگین انجام شود): ```js if (import.meta.hot) { import.meta.hot.on('special-update', (data) => { // perform custom update }) } ``` ## وضعیت وابسته به محیط (Per-environment State) در پلاگین‌ها از آنجا که یک نمونه‌ی یکسان از پلاگین ممکن است در محیط‌های مختلف (مثلاً کلاینت و SSR) استفاده شود، وضعیت (state) مربوط به پلاگین باید با استفاده از `this.environment` تفکیک شود. این همان الگویی است که پیش‌تر نیز در اکوسیستم استفاده می‌شده؛ یعنی برای نگهداری وضعیت ماژول‌ها به صورت مجزا برای SSR و کلاینت، از مقدار بولی `ssr` به عنوان کلید استفاده می‌شده تا از قاطی شدن وضعیت ماژول‌های SSR و کلاینت جلوگیری شود. در این حالت می‌توان از ساختاری مانند `Map`‎ برای نگهداری وضعیت مستقل هر محیط استفاده کرد. نکته: برای حفظ سازگاری با نسخه‌های قبلی، متدهای `buildStart` و `buildEnd` به صورت پیش‌فرض فقط برای محیط کلاینت فراخوانی می‌شوند، مگر اینکه گزینه‌ی `perEnvironmentStartEndDuringDev: true` فعال شده باشد. ```js function PerEnvironmentCountTransformedModulesPlugin() { const state = new Map() return { name: 'count-transformed-modules', perEnvironmentStartEndDuringDev: true, buildStart() { state.set(this.environment, { count: 0 }) }, transform(id) { state.get(this.environment).count++ }, buildEnd() { console.log(this.environment.name, state.get(this.environment).count) } } } ``` ## پلاگین‌های مخصوص هر محیط یک پلاگین می‌تواند مشخص کند که در کدام محیط‌ها باید اعمال شود، با استفاده از تابع `applyToEnvironment`. ```js const UnoCssPlugin = () => { // مشترک سراسری state return { buildStart() { // WeakMap مقداردهی وضعیت مخصوص هر محیط با // this.environment با استفاده از }, configureServer() { // استفاده از هوک‌های سراسری به صورت معمول }, applyToEnvironment(environment) { // برگردانید true اگر این پلاگین باید در این محیط فعال باشد، مقدار // یا یک پلاگین جدید برای جایگزینی آن برگردانید // اگر این هوک استفاده نشود، پلاگین در همه محیط‌ها فعال خواهد بود }, resolveId(id, importer) { // فقط برای محیط‌هایی که این پلاگین در آن‌ها اعمال می‌شود، فراخوانی می‌شود }, } } ``` اگر یک پلاگین از محیط آگاه نباشد و دارای وضعیتی باشد که بر اساس محیط فعلی کلیدگذاری نشده است، هوک `applyToEnvironment` امکان تبدیل آن به یک پلاگین مخصوص هر محیط را به‌سادگی فراهم می‌کند. ```js import { nonShareablePlugin } from 'non-shareable-plugin' export default defineConfig({ plugins: [ { name: 'per-environment-plugin', applyToEnvironment(environment) { return nonShareablePlugin({ outputName: environment.name }) }, }, ], }) ``` Vite یک تابع کمکی به نام `perEnvironmentPlugin` ارائه می‌دهد تا مواردی که نیازی به هوک‌های دیگر ندارند، ساده‌تر کند: ```js import { nonShareablePlugin } from 'non-shareable-plugin' export default defineConfig({ plugins: [ perEnvironmentPlugin('per-environment-plugin', (environment) => nonShareablePlugin({ outputName: environment.name }), ), ], }) ``` هوک `applyToEnvironment` در زمان پیکربندی فراخوانی می‌شود، و در حال حاضر بعد از اجرای `configResolved` انجام می‌گیرد. دلیل این ترتیب، وجود پروژه‌هایی در اکوسیستم است که پلاگین‌ها را در این مرحله تغییر می‌دهند. با این حال، ممکن است در آینده فرآیند تشخیص پلاگین‌های محیطی (environment plugins resolution) به قبل از `configResolved` منتقل شود. این تغییر به منظور بهبود ساختار و پیش‌بینی‌پذیری فرایند پیکربندی در نظر گرفته شده است. ## محیط در هوک‌های بیلد مشابه حالت توسعه، هوک‌های پلاگین در زمان بیلد نیز نمونه محیط را دریافت می‌کنند و جایگزین بولین `ssr` می‌شوند. این موضوع برای هوک‌هایی مانند `renderChunk` ، `generateBundle` و سایر هوک‌های مختص بیلد نیز کار می‌کند. ## پلاگین‌های مشترک در زمان بیلد قبل از Vite 6، مسیر اجرا پلاگین‌ها در حالت توسعه و بیلد به صورت متفاوت عمل می‌کرد: * **در زمان توسعه:** پلاگین‌ها مشترک بودند. * **در زمان بیلد:** پلاگین‌ها برای هر محیط جداگانه بودند (در فرآیندهای مختلف: `vite build` سپس `vite build --ssr`). این موضوع باعث می‌شد فریم‌ورک‌ها برای به اشتراک‌گذاری وضعیت بین بیلد `client` و بیلد `ssr` از فایل‌های مانیفست نوشته‌شده در فایل سیستم استفاده کنند. در Vite 6، اکنون تمام محیط‌ها در یک فرآیند واحد بیلد می‌شوند، بنابراین مسیر اجرا پلاگین‌ها و ارتباط بین محیط‌ها می‌تواند با حالت توسعه هماهنگ شود. در یکی از نسخه‌های اصلی آینده، ممکن است به یک هماهنگی کامل برسیم: * **در هر دو حالت توسعه و بیلد:** پلاگین‌ها مشترک خواهند بود، با [فیلتر کردن مخصوص هر محیط](#پلاگینهای-مخصوص-هر-محیط). همچنین یک نمونه مشترک از `ResolvedConfig` در زمان بیلد وجود خواهد داشت که امکان کش کردن در سطح کل فرآیند بیلد برنامه را فراهم می‌کند، مشابه کاری که در زمان توسعه با `WeakMap‎` انجام می‌دهیم. برای Vite 6، ما نیاز داریم یک گام کوچک‌تر برداریم تا سازگاری با نسخه‌های قبلی حفظ شود. پلاگین‌های اکوسیستم در حال حاضر از `config.build` به جای `environment.config.build` برای دسترسی به تنظیمات استفاده می‌کنند، بنابراین به صورت پیش‌فرض باید یک `ResolvedConfig` جدید برای هر محیط ایجاد کنیم. یک پروژه می‌تواند با تنظیم `builder.sharedConfigBuild` روی `true`، به اشتراک‌گذاری کامل تنظیمات و مسیر اجرا پلاگین‌ها را فعال کند. این گزینه در ابتدا فقط برای یک زیرمجموعه کوچک از پروژه‌ها کار خواهد کرد، بنابراین نویسندگان پلاگین می‌توانند برای یک پلاگین خاص با تنظیم فلگ `sharedDuringBuild` روی `true`، اشتراک‌گذاری آن را فعال کنند. این امکان به راحتی به اشتراک‌گذاری وضعیت برای پلاگین‌های معمولی را فراهم می‌کند: ```js function myPlugin() { // بین تمام محیط‌ها در حالت توسعه و بیلد state اشتراک‌گذاری const sharedState = ... return { name: 'shared-plugin', transform(code, id) { ... }, // فعال‌سازی یک نمونه مشترک برای تمام محیط‌ها در زمان بیلد sharedDuringBuild: true, } } ``` --- --- url: /guide/api-environment-runtimes.md --- # API محیط برای رانتایم‌ها :::warning آزمایشی رابط Environment API هنوز در مرحله‌ی آزمایشی (experimental) هست. با این حال، ما تلاش می‌کنیم بین نسخه‌های اصلی (major) پایداری این APIها را حفظ کنیم تا جامعه‌ی توسعه‌دهندگان بتوانند با آن‌ها کار کرده و تجربیات خود را بر اساس آن‌ها توسعه دهند. ما قصد داریم این APIهای جدید را در یکی از نسخه‌های اصلی آینده به حالت پایدار (stable) برسانیم. البته ممکن است در این فرآیند تغییرات شکننده (breaking changes) نیز اعمال شود، اما این کار زمانی انجام خواهد شد که پروژه‌ها و کتابخانه‌های وابسته فرصت کافی برای آزمایش و ارزیابی این قابلیت‌های جدید را داشته باشند. منابع: * [بحث و گفتگو](https://github.com/vitejs/vite/discussions/16358) جایی که ما در حال جمع‌آوری نظرات درباره APIهای جدید هستیم. * [PR مربوط به Environment API](https://github.com/vitejs/vite/pull/16471) جایی که API جدید پیاده‌سازی و بررسی شده است. لطفاً نظرات و بازخوردهای خود را با ما به اشتراک بگذارید. ::: ## Environment Factories سازنده‌های محیط (Environment Factories) قرار است توسط فراهم‌کنندگان رانتایم (مثل Cloudflare) پیاده‌سازی شوند، نه کاربران عادی. این سازنده‌ها در ساده‌ترین حالت، یک `EnvironmentOptions` را برمی‌گردانند که از رانتایم هدف هم برای محیط توسعه و هم بیلد استفاده می‌کند. همچنین می‌توان تنظیمات پیش‌فرض محیط را به‌گونه‌ای تعیین کرد که کاربر نیازی به انجام این کار نداشته باشد. ```ts function createWorkerdEnvironment( userConfig: EnvironmentOptions, ): EnvironmentOptions { return mergeConfig( { resolve: { conditions: [ /*...*/ ], }, dev: { createEnvironment(name, config) { return createWorkerdDevEnvironment(name, config, { hot: true, transport: customHotChannel(), }) }, }, build: { createEnvironment(name, config) { return createWorkerdBuildEnvironment(name, config) }, }, }, userConfig, ) } ``` سپس می‌توان فایل پیکربندی را به شکل زیر نوشت: ```js import { createWorkerdEnvironment } from 'vite-environment-workerd' export default { environments: { ssr: createWorkerdEnvironment({ build: { outDir: '/dist/ssr', }, }), rsc: createWorkerdEnvironment({ build: { outDir: '/dist/rsc', }, }), }, } ``` و فریم‌ورک‌ها می‌توانند برای انجام SSR از یک محیط با رانتایم workerd به این شکل استفاده کنند: ```js const ssrEnvironment = server.environments.ssr ``` ## ایجاد یک Environment Factory جدید سرور توسعه Vite به طور پیش‌فرض دو محیط را ارائه می‌دهد: محیط `client` و محیط `ssr`. محیط کلاینت به طور پیش‌فرض یک محیط مرورگر است، و اجراکننده ماژول آن با ایمپورت کردن ماژول مجازی `‎/@vite/client` در برنامه‌های کلاینت پیاده‌سازی می‌شود. محیط SSR به طور پیش‌فرض در همان رانتایم Node که سرور Vite اجرا می‌شود، اجرا می‌شود و به سرورهای برنامه اجازه می‌دهد تا درخواست‌ها را در زمان توسعه با پشتیبانی کامل از HMR رندر کنند. سورس کد تبدیل‌شده یک ماژول نامیده می‌شود و روابط بین ماژول‌های پردازش‌شده در هر محیط در یک گراف ماژول نگهداری می‌شود. کد تبدیل‌شده برای این ماژول‌ها به رانتایم‌های مرتبط با هر محیط فرستاده می‌شود تا اجرا شود. وقتی یک ماژول در رانتایم ارزیابی می‌شود، ماژول‌های ایمپورت‌شده آن درخواست می‌شوند که باعث می‌شود بخشی مرتبطی از گراف ماژول پردازش شود. اجرا کننده ماژول در Vite اجازه می‌دهد هر کدی را با پردازش آن توسط پلاگین‌های Vite اجرا کنید. این با `server.ssrLoadModule` متفاوت است زیرا پیاده‌سازی اجراکننده از سرور جدا شده است. این موضوع به نویسندگان کتابخانه و فریم‌ورک اجازه می‌دهد لایه ارتباطی خود را بین سرور Vite و اجراکننده پیاده‌سازی کنند. مرورگر با استفاده از Web Socket سرور و از طریق درخواست‌های HTTP با محیط مربوطه خود ارتباط برقرار می‌کند. Node Module Runner می‌تواند به طور مستقیم فراخوانی‌های تابع را برای پردازش ماژول‌ها انجام دهد زیرا در همان فرآیند اجرا می‌شود. سایر محیط‌ها می‌توانند ماژول‌ها را با اتصال به یک رانتایم JS مانند workerd، یا یک Worker Thread همانطور که Vitest انجام می‌دهد، اجرا کنند. یکی از اهداف این قابلیت، فراهم کردن یک API قابل سفارشی‌سازی برای پردازش و اجرای کد است. کاربران می‌توانند با استفاده از ابزارهای ارائه‌شده، سازنده‌های محیط جدیدی بسازند. ```ts import { DevEnvironment, HotChannel } from 'vite' function createWorkerdDevEnvironment( name: string, config: ResolvedConfig, context: DevEnvironmentContext ) { const connection = /* ... */ const transport: HotChannel = { on: (listener) => { connection.on('message', listener) }, send: (data) => connection.send(data), } const workerdDevEnvironment = new DevEnvironment(name, config, { options: { resolve: { conditions: ['custom'] }, ...context.options, }, hot: true, transport, }) return workerdDevEnvironment } ``` ## `ModuleRunner` یک اجراکننده‌ی ماژول (Module Runner) در رانتایم هدف ساخته می‌شود. تمام APIهایی که در بخش بعدی آمده‌اند، مگر در مواردی که به‌طور دیگری ذکر شده باشد، از مسیر `vite/module-runner` ایمپورت می‌شوند. این نقطه ورود در حد ممکن سبک نگه داشته شده و تنها کمترین موارد لازم را برای ساخت اجراکننده ماژول را اکسپورت می‌کند. **امضای تایپ:** ```ts export class ModuleRunner { constructor( public options: ModuleRunnerOptions, public evaluator: ModuleEvaluator = new ESModulesEvaluator(), private debug?: ModuleRunnerDebugger, ) {} /** * URL to execute. * Accepts file path, server path, or id relative to the root. */ public async import(url: string): Promise /** * Clear all caches including HMR listeners. */ public clearCache(): void /** * Clear all caches, remove all HMR listeners, reset sourcemap support. * This method doesn't stop the HMR connection. */ public async close(): Promise /** * Returns `true` if the runner has been closed by calling `close()`. */ public isClosed(): boolean } ``` ارزیاب ماژول در `ModuleRunner` مسئول اجرای کد است. Vite به صورت پیش‌فرض `ESModulesEvaluator` را اکسپورت می‌کند که از `new AsyncFunction` برای اجرای کد استفاده می‌کند. اگر رانتایم جاوااسکریپت شما از ارزیابی ناامن پشتیبانی نمی‌کند، می‌توانید پیاده‌سازی اختصاصی خود را ارائه دهید. اجراکننده‌ی ماژول متد `import` را ارائه می‌دهد. زمانی که سرور Vite رویداد HMR از نوع `full-reload` را اجرا می‌کند، تمام ماژول‌های تحت تأثیر دوباره اجرا خواهند شد. توجه داشته باشید که اجراکننده‌ی ماژول در این فرآیند آبجکت `exports` را به‌روزرسانی نمی‌کند، بلکه آن را بازنویسی می‌کند. بنابراین، اگر نیاز به جدیدترین مقدار `exports` دارید، باید دوباره `import` را اجرا کنید یا ماژول را از `evaluatedModules` دریافت کنید. **مثال استفاده:** ```js import { ModuleRunner, ESModulesEvaluator } from 'vite/module-runner' import { transport } from './rpc-implementation.js' const moduleRunner = new ModuleRunner( { transport, }, new ESModulesEvaluator(), ) await moduleRunner.import('/src/entry-point.js') ``` ## `ModuleRunnerOptions` ```ts twoslash import type { InterceptorOptions as InterceptorOptionsRaw, ModuleRunnerHmr as ModuleRunnerHmrRaw, EvaluatedModules, } from 'vite/module-runner' import type { Debug } from '@type-challenges/utils' type InterceptorOptions = Debug type ModuleRunnerHmr = Debug /** see below */ type ModuleRunnerTransport = unknown // ---cut--- interface ModuleRunnerOptions { /** * A set of methods to communicate with the server. */ transport: ModuleRunnerTransport /** * Configure how source maps are resolved. * Prefers `node` if `process.setSourceMapsEnabled` is available. * Otherwise it will use `prepareStackTrace` by default which overrides * `Error.prepareStackTrace` method. * You can provide an object to configure how file contents and * source maps are resolved for files that were not processed by Vite. */ sourcemapInterceptor?: | false | 'node' | 'prepareStackTrace' | InterceptorOptions /** * Disable HMR or configure HMR options. * * @default true */ hmr?: boolean | ModuleRunnerHmr /** * Custom module cache. If not provided, it creates a separate module * cache for each module runner instance. */ evaluatedModules?: EvaluatedModules } ``` ## `ModuleEvaluator` **امضای تایپ:** ```ts twoslash import type { ModuleRunnerContext as ModuleRunnerContextRaw } from 'vite/module-runner' import type { Debug } from '@type-challenges/utils' type ModuleRunnerContext = Debug // ---cut--- export interface ModuleEvaluator { /** * Number of prefixed lines in the transformed code. */ startOffset?: number /** * Evaluate code that was transformed by Vite. * @param context Function context * @param code Transformed code * @param id ID that was used to fetch the module */ runInlinedModule( context: ModuleRunnerContext, code: string, id: string, ): Promise /** * evaluate externalized module. * @param file File URL to the external module */ runExternalModule(file: string): Promise } ``` Vite به‌صورت پیش‌فرض `ESModulesEvaluator` را اکسپورت می‌کند که این اینترفیس را پیاده‌سازی می‌کند. این ماژول از `new AsyncFunction` برای اجرای کد استفاده می‌کند. بنابراین، اگر کد دارای سورس مپ داخلی (inlined source map) باشد، باید شامل یک [افست ۲ خطی](https://tc39.es/ecma262/#sec-createdynamicfunction) باشد تا فضای موردنیاز برای خطوط جدید اضافه‌شده را جبران کند. این کار به‌طور خودکار توسط `ESModulesEvaluator` انجام می‌شود. اما ارزیاب‌های سفارشی (Custom evaluators) خطوط اضافی را اضافه نخواهند کرد. ## `ModuleRunnerTransport` **امضای تایپ:** ```ts twoslash import type { ModuleRunnerTransportHandlers } from 'vite/module-runner' /** an object */ type HotPayload = unknown // ---cut--- interface ModuleRunnerTransport { connect?(handlers: ModuleRunnerTransportHandlers): Promise | void disconnect?(): Promise | void send?(data: HotPayload): Promise | void invoke?(data: HotPayload): Promise<{ result: any } | { error: any }> timeout?: number } ``` آبجکت Transport برای ارتباط با محیط از طریق RPC یا فراخوانی مستقیم توابع استفاده می‌شود. اگر متد `invoke` پیاده‌سازی نشده باشد، باید متدهای `send` و `connect` را پیاده‌سازی کنید. در این حالت، Vite خودش متد `invoke` را ایجاد می‌کند. برای این کار، باید آن را با نمونه‌ای از `HotChannel` روی سرور ترکیب کنید، مانند مثالی که در آن ماژول رانر در یک (Worker Thread) ایجاد می‌شود: ::: code-group ```js [worker.js] import { parentPort } from 'node:worker_threads' import { fileURLToPath } from 'node:url' import { ESModulesEvaluator, ModuleRunner } from 'vite/module-runner' /** @type {import('vite/module-runner').ModuleRunnerTransport} */ const transport = { connect({ onMessage, onDisconnection }) { parentPort.on('message', onMessage) parentPort.on('close', onDisconnection) }, send(data) { parentPort.postMessage(data) }, } const runner = new ModuleRunner( { transport, }, new ESModulesEvaluator(), ) ``` ```js [server.js] import { BroadcastChannel } from 'node:worker_threads' import { createServer, RemoteEnvironmentTransport, DevEnvironment } from 'vite' function createWorkerEnvironment(name, config, context) { const worker = new Worker('./worker.js') const handlerToWorkerListener = new WeakMap() const workerHotChannel = { send: (data) => worker.postMessage(data), on: (event, handler) => { if (event === 'connection') return const listener = (value) => { if (value.type === 'custom' && value.event === event) { const client = { send(payload) { worker.postMessage(payload) }, } handler(value.data, client) } } handlerToWorkerListener.set(handler, listener) worker.on('message', listener) }, off: (event, handler) => { if (event === 'connection') return const listener = handlerToWorkerListener.get(handler) if (listener) { worker.off('message', listener) handlerToWorkerListener.delete(handler) } }, } return new DevEnvironment(name, config, { transport: workerHotChannel, }) } await createServer({ environments: { worker: { dev: { createEnvironment: createWorkerEnvironment, }, }, }, }) ``` ::: یک مثال دیگر که از یک درخواست HTTP برای ارتباط بین رانر (Runner) و سرور استفاده می‌کند: ```ts import { ESModulesEvaluator, ModuleRunner } from 'vite/module-runner' export const runner = new ModuleRunner( { transport: { async invoke(data) { const response = await fetch(`http://my-vite-server/invoke`, { method: 'POST', body: JSON.stringify(data), }) return response.json() }, }, hmr: false, // disable HMR as HMR requires transport.connect }, new ESModulesEvaluator(), ) await runner.import('/entry.js') ``` در این حالت، متد `handleInvoke` در `NormalizedHotChannel` قابل استفاده است. ```ts const customEnvironment = new DevEnvironment(name, config, context) server.onRequest((request: Request) => { const url = new URL(request.url) if (url.pathname === '/invoke') { const payload = (await request.json()) as HotPayload const result = customEnvironment.hot.handleInvoke(payload) return new Response(JSON.stringify(result)) } return Response.error() }) ``` اما توجه داشته باشید که برای پشتیبانی از HMR، متدهای `send` و `connect` الزامی هستند. متد `send` معمولاً زمانی فراخوانی می‌شود که یک رویداد سفارشی فعال شود (مثلاً `import.meta.hot.send("my-event")`). Vite متد `createServerHotChannel` را از نقطه ورود اصلی اکسپورت می‌کند تا از HMR در حین اجرای SSR در Vite پشتیبانی کند. --- --- url: /guide/api-environment-frameworks.md --- # API محیط برای فریم‌ورک‌ها :::warning آزمایشی رابط Environment API هنوز در مرحله‌ی آزمایشی (experimental) هست. با این حال، ما تلاش می‌کنیم بین نسخه‌های اصلی (major) پایداری این APIها را حفظ کنیم تا جامعه‌ی توسعه‌دهندگان بتوانند با آن‌ها کار کرده و تجربیات خود را بر اساس آن‌ها توسعه دهند. ما قصد داریم این APIهای جدید را در یکی از نسخه‌های اصلی آینده به حالت پایدار (stable) برسانیم. البته ممکن است در این فرآیند تغییرات شکننده (breaking changes) نیز اعمال شود، اما این کار زمانی انجام خواهد شد که پروژه‌ها و کتابخانه‌های وابسته فرصت کافی برای آزمایش و ارزیابی این قابلیت‌های جدید را داشته باشند. منابع: * [بحث و گفتگو](https://github.com/vitejs/vite/discussions/16358) جایی که ما در حال جمع‌آوری نظرات درباره APIهای جدید هستیم. * [PR مربوط به Environment API](https://github.com/vitejs/vite/pull/16471) جایی که API جدید پیاده‌سازی و بررسی شده است. لطفاً نظرات و بازخوردهای خود را با ما به اشتراک بگذارید. ::: ## محیط‌ها و فریم‌ورک‌ها محیط `ssr` و سایر محیط‌های غیرکلاینت به طور پیش‌فرض در زمان توسعه از یک `RunnableDevEnvironment` استفاده می‌کنند. در حالی که این نیاز دارد که رانتایم مشابه با سرور Vite باشد، این روش مشابه با `ssrLoadModule` عمل می‌کند و به فریم‌ورک‌ها اجازه می‌دهد تا مهاجرت کرده و HMR را برای توسعه SSR خود فعال کنند. شما می‌توانید هر محیط اجرایی را با استفاده از تابع `isRunnableDevEnvironment` بررسی کنید. ```ts export class RunnableDevEnvironment extends DevEnvironment { public readonly runner: ModuleRunner } class ModuleRunner { /** * برای اجرا URL * می‌تواند مسیر فایل، مسیر سرور، یا شناسه‌ای نسبی به ریشه را بپذیرد * ssrLoadModule یک ماژول نمونه‌سازی‌شده را برمی‌گرداند مشابه */ public async import(url: string): Promise> /** * ModuleRunner سایر متدهای */ } if (isRunnableDevEnvironment(server.environments.ssr)) { await server.environments.ssr.runner.import('/entry-point.js') } ``` :::warning هشدار `runner` زمانی که برای اولین بار به آن دسترسی پیدا کنید، بلافاصله مقداردهی می‌شود. توجه داشته باشید که وقتی `runner` با فراخوانی `process.setSourceMapsEnabled` ساخته می‌شود یا در صورت عدم دسترسی، با جایگزین کردن `Error.prepareStackTrace` ، Vite از پشتیبانی سورس مپ استفاده می‌کند. ::: فریم‌ورک‌هایی که از طریق [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Window/fetch) با محیط اجرای خود ارتباط برقرار می‌کنند، می‌توانند از `FetchableDevEnvironment` استفاده کنند. این کلاس روشی استاندارد برای مدیریت درخواست‌ها از طریق متد `handleRequest` فراهم می‌کند. ```ts import { createServer, createFetchableDevEnvironment, isFetchableDevEnvironment, } from 'vite' const server = await createServer({ server: { middlewareMode: true }, appType: 'custom', environments: { custom: { dev: { createEnvironment(name, config) { return createFetchableDevEnvironment(name, config, { handleRequest(request: Request): Promise | Response { // handle Request and return a Response }, }) }, }, }, }, }) // Any consumer of the environment API can now call `dispatchFetch` if (isFetchableDevEnvironment(server.environments.custom)) { const response: Response = await server.environments.custom.dispatchFetch( new Request('/request-to-handle'), ) } ``` :::warning هشدار Vite ورودی و خروجی متد `dispatchFetch` را اعتبارسنجی می‌کند: درخواست (Request) باید نمونه‌ای از کلاس سراسری `Request` باشد و پاسخ (Response) نیز باید نمونه‌ای از کلاس سراسری `Response` باشد. اگر این شرایط برقرار نباشد، Vite یک خطای `TypeError` پرتاب می‌کند. توجه داشته باشید که اگرچه `FetchableDevEnvironment` به‌صورت یک کلاس پیاده‌سازی شده است، تیم توسعه Vite آن را به‌عنوان یک جزئیات داخلی (implementation detail) در نظر می‌گیرد. به این معنی که ممکن است در آینده، بدون اعلام قبلی، تغییر کند. ::: ## محیط پیش‌فرض `RunnableDevEnvironment` با توجه به سرور Vite که مطابق [راهنمای راه‌اندازی SSR](/guide/ssr#setting-up-the-dev-server) در حالت میان‌افزار (middleware) پیکربندی شده، بیایید با استفاده از API محیط، میان‌افزار SSR را پیاده‌سازی کنیم. به یاد داشته باشید که الزاماً نباید نام آن `ssr` باشد، بنابراین در این مثال آن را `server` می‌نامیم. (جزئیات مربوط به مدیریت خطا در این مثال نادیده گرفته شده است) ```js import fs from 'node:fs' import path from 'node:path' import { fileURLToPath } from 'node:url' import { createServer } from 'vite' const __dirname = path.dirname(fileURLToPath(import.meta.url)) const viteServer = await createServer({ server: { middlewareMode: true }, appType: 'custom', environments: { server: { // اجرا شده است Vite به طور پیش‌فرض، ماژول‌ها در همان فرآیندی اجرا می‌شوند که سرور }, }, }) // تبدیل کنید RunnableDevEnvironment نیاز داشته باشید آن را به TypeScript شاید در // استفاده کنید runner برای بررسی دسترسی به isRunnableDevEnvironment یا از const serverEnvironment = viteServer.environments.server app.use('*', async (req, res, next) => { const url = req.originalUrl // 1. index.html خواندن فایل const indexHtmlPath = path.resolve(__dirname, 'index.html') let template = fs.readFileSync(indexHtmlPath, 'utf-8') // 2. Vite به HTML تبدیل‌های مربوط به // را اعمال می‌کند Vite را تزریق می‌کند و همچنین تبدیل‌های پلاگین‌های HMR Client // @vitejs/plugin-react پیش‌درآمد از template = await viteServer.transformIndexHtml(url, template) // 3. را ESM کد import(url) ماژول ورودی سرور را بارگیری می‌کند. متد // به صورت خودکار تبدیل می‌کند و نیاز به باندل ندارد Node.js برای استفاده در // را فراهم می‌کند HMR همچنین پشتیبانی کامل از const { render } = await serverEnvironment.runner.import( '/src/entry-server.js', ) // 4. از render برنامه را رندر می‌کند. فرض بر این است که تابع HTML محتوای // فریم‌ورک استفاده می‌کند SSR های مربوط به API از entry-server.js // ReactDOMServer.renderToString() مانند const appHtml = await render(url) // 5. محتوای رندر شده را وارد قالب می‌کند const html = template.replace(``, appHtml) // 6. نهایی را برمی‌گرداند HTML محتوای res.status(200).set({ 'Content-Type': 'text/html' }).end(html) }) ``` ## SSR بدون وابستگی به Runtime مشخص از آنجا که `RunnableDevEnvironment` فقط در همان رانتایم سرور Vite کد را اجرا می‌کند، این رانتایم باید قادر به اجرای سرور Vite باشد (رانتایمی سازگار با Node.js). به این معناست که برای حذف وابستگی به رانتایم مشخص، باید از `DevEnvironment` به صورت خام استفاده کنید. :::info پیشنهاد `FetchableDevEnvironment` در طرح اولیه، متدی به نام `run` در کلاس `DevEnvironment` پیشنهاد شد که با استفاده از گزینه `transport`، امکان ایمپورت در بخش اجراکننده (runner) را فراهم می‌کرد. در آزمایش‌ها مشخص شد که این API به اندازه کافی فراگیر نیست تا توصیه شود. هم‌اکنون منتظر بازخورد در مورد [پیشنهاد `FetchableDevEnvironment`](https://github.com/vitejs/vite/discussions/18191) هستیم. ::: در `RunnableDevEnvironment` متد `runner.import` وجود دارد که مقدار ماژول را برمی‌گرداند، اما در `DevEnvironment` خام در دسترس نیست و نیاز دارد کد استفاده‌کننده از APIهای Vite و ماژول‌های کاربر از یکدیگر جدا باشند. مثال زیر، کد از ماژول کاربر در همان جایی استفاده می‌کند که از APIهای Vite نیز استفاده می‌شود: ```ts // code using the Vite's APIs import { createServer } from 'vite' const server = createServer() const ssrEnvironment = server.environment.ssr const input = {} const { createHandler } = await ssrEnvironment.runner.import('./entrypoint.js') const handler = createHandler(input) const response = handler(new Request('/')) // ------------------------------------- // ./entrypoint.js export function createHandler(input) { return function handler(req) { return new Response('hello') } } ``` اگر کد شما می‌تواند در همان محیط اجرایی ماژول‌های کاربر اجرا شود (یعنی به APIهای مخصوص Node.js وابسته نیست)، می‌توانید از یک ماژول مجازی استفاده کنید. این روش نیاز به دسترسی به مقدار از طریق APIهای Vite را از بین می‌برد. ```ts // Vite های API کد با استفاده از import { createServer } from 'vite' const server = createServer({ plugins: [ // `virtual:entrypoint` پلاگین برای رسیدگی به مسیر مجازی { name: 'virtual-module', /* پیاده‌سازی پلاگین */ }, ], }) const ssrEnvironment = server.environment.ssr const input = {} // از توابعی که توسط فکتوری‌های هر محیط فراهم می‌شوند استفاده می‌کند // بررسی می‌کند هر فکتوری محیط چه امکاناتی ارائه می‌دهد if (ssrEnvironment instanceof RunnableDevEnvironment) { ssrEnvironment.runner.import('virtual:entrypoint') } else if (ssrEnvironment instanceof CustomDevEnvironment) { ssrEnvironment.runEntrypoint('virtual:entrypoint') } else { throw new Error(`Unsupported runtime for ${ssrEnvironment.name}`) } // ------------------------------------- // virtual:entrypoint const { createHandler } = await import('./entrypoint.js') const handler = createHandler(input) const response = handler(new Request('/')) // ------------------------------------- // ./entrypoint.js export function createHandler(input) { return function handler(req) { return new Response('hello') } } ``` برای مثال، برای فراخوانی `transformIndexHtml` روی ماژول کاربر، می‌توان از پلاگین زیر استفاده کرد: ```ts {13-21} function vitePluginVirtualIndexHtml(): Plugin { let server: ViteDevServer | undefined return { name: vitePluginVirtualIndexHtml.name, configureServer(server_) { server = server_ }, resolveId(source) { return source === 'virtual:index-html' ? '\0' + source : undefined }, async load(id) { if (id === '\0' + 'virtual:index-html') { let html: string if (server) { this.addWatchFile('index.html') html = fs.readFileSync('index.html', 'utf-8') html = await server.transformIndexHtml('/', html) } else { html = fs.readFileSync('dist/client/index.html', 'utf-8') } return `export default ${JSON.stringify(html)}` } return }, } } ``` اگر کد شما به APIهای Node.js نیاز دارد، می‌توانید برای ارتباط با کدی که از APIهای Vite در ماژول‌های کاربر استفاده می‌کند، از `hot.send` استفاده کنید. با این حال، دقت داشته باشید که پس از مرحله بیلد، این روش ممکن است همانند قبل کار نکند. ```ts // Vite های API کد با استفاده از import { createServer } from 'vite' const server = createServer({ plugins: [ // `virtual:entrypoint` پلاگین برای رسیدگی به مسیر مجازی { name: 'virtual-module', /* پیاده‌سازی پلاگین */ }, ], }) const ssrEnvironment = server.environment.ssr const input = {} // از توابعی که توسط فکتوری‌های هر محیط فراهم می‌شوند استفاده می‌کند // بررسی می‌کند هر فکتوری محیط چه امکاناتی ارائه می‌دهد if (ssrEnvironment instanceof RunnableDevEnvironment) { ssrEnvironment.runner.import('virtual:entrypoint') } else if (ssrEnvironment instanceof CustomDevEnvironment) { ssrEnvironment.runEntrypoint('virtual:entrypoint') } else { throw new Error(`Unsupported runtime for ${ssrEnvironment.name}`) } const req = new Request('/') const uniqueId = 'a-unique-id' ssrEnvironment.send('request', serialize({ req, uniqueId })) const response = await new Promise((resolve) => { ssrEnvironment.on('response', (data) => { data = deserialize(data) if (data.uniqueId === uniqueId) { resolve(data.res) } }) }) // ------------------------------------- // virtual:entrypoint const { createHandler } = await import('./entrypoint.js') const handler = createHandler(input) import.meta.hot.on('request', (data) => { const { req, uniqueId } = deserialize(data) const res = handler(req) import.meta.hot.send('response', serialize({ res: res, uniqueId })) }) const response = handler(new Request('/')) // ------------------------------------- // ./entrypoint.js export function createHandler(input) { return function handler(req) { return new Response('hello') } } ``` ## محیط‌ها در زمان بیلد در خط فرمان (CLI)، فراخوانی `vite build` و `vite build --ssr` همچنان به‌خاطر سازگاری با نسخه‌های قبلی فقط محیط کلاینت و محیط SSR را بیلد می‌کند. زمانی که `builder` تعریف شده باشد (یا وقتی از `vite build --app` استفاده می‌کنید)، `vite build` برای بیلد کل اپلیکیشن فعال می‌شود. این کار در نسخه مهم بعدی به صورت پیش‌فرض خواهد بود. یک نمونه از `ViteBuilder` (معادل بیلدی `ViteDevServer`) ایجاد می‌شود تا تمام محیط‌های پیکربندی‌شده را برای پروداکشن بیلد کند. به صورت پیش‌فرض، بیلد محیط‌ها به صورت سری و بر اساس ترتیب رکورد `environments` اجرا می‌شود. یک فریم‌ورک یا کاربر می‌تواند با استفاده از تنظیمات زیر مشخص کند چگونه محیط‌ها بیلد شوند: ```js export default { builder: { buildApp: async (builder) => { const environments = Object.values(builder.environments) return Promise.all( environments.map((environment) => builder.build(environment)), ) }, }, } ``` پلاگین‌ها همچنین می‌توانند یک هوک به نام `buildApp` تعریف کنند. هوک‌هایی با ترتیب `'pre'` و `null` قبل از اجرای `builder.buildApp` پیکربندی‌شده اجرا می‌شوند و هوک‌های با ترتیب `'post'` پس از آن اجرا خواهند شد. از ویژگی `environment.isBuilt` می‌توان برای بررسی اینکه آیا یک محیط از قبل ساخته شده است یا خیر، استفاده کرد. ## کد بدون وابستگی مستقیم به محیط اغلب اوقات، نمونه محیط فعلی به عنوان بخشی از کانتکست کدی که اجرا می‌شود در دسترس است، بنابراین نیاز به دسترسی مستقیم از طریق `server.environments` معمولاً کم است. به عنوان مثال، در هوک‌های پلاگین، محیط به عنوان بخشی از `PluginContext` در دسترس قرار می‌گیرد و می‌توانید با `this.environment` به آن دسترسی داشته باشید. برای آشنایی با نحوه ساخت پلاگین‌های آگاه به محیط، به [Environment API for Plugins](./api-environment-plugins.md) مراجعه کنید. --- --- url: /guide/comparisons.md --- # Comparisons ## WMR [WMR](https://github.com/preactjs/wmr) by the Preact team looked to provide a similar feature set. Vite's universal Rollup plugin API for dev and build was inspired by it. WMR is no longer maintained. The Preact team now recommends Vite with [@preactjs/preset-vite](https://github.com/preactjs/preset-vite). ## @web/dev-server [@web/dev-server](https://modern-web.dev/docs/dev-server/overview/) (previously `es-dev-server`) is a great project and Vite 1.0's Koa-based server setup was inspired by it. `@web/dev-server` is a bit lower-level in terms of scope. It does not provide official framework integrations, and requires manually setting up a Rollup configuration for the production build. Overall, Vite is a more opinionated / higher-level tool that aims to provide a more out-of-the-box workflow. That said, the `@web` umbrella project contains many other excellent tools that may benefit Vite users as well. ## Snowpack [Snowpack](https://www.snowpack.dev/) was also a no-bundle native ESM dev server, very similar in scope to Vite. The project is no longer being maintained. The Snowpack team is now working on [Astro](https://astro.build/), a static site builder powered by Vite. The Astro team is now an active player in the ecosystem, and they are helping to improve Vite. Aside from different implementation details, the two projects shared a lot in terms of technical advantages over traditional tooling. Vite's dependency pre-bundling is also inspired by Snowpack v1 (now [`esinstall`](https://github.com/snowpackjs/snowpack/tree/main/esinstall)). Some of the main differences between the two projects are listed in [the v2 Comparisons Guide](https://v2.vite.dev/guide/comparisons). --- --- url: /guide/api-environment.md --- # Environment API :::warning آزمایشی رابط Environment API هنوز در مرحله‌ی آزمایشی (experimental) هست. با این حال، ما تلاش می‌کنیم بین نسخه‌های اصلی (major) پایداری این APIها را حفظ کنیم تا جامعه‌ی توسعه‌دهندگان بتوانند با آن‌ها کار کرده و تجربیات خود را بر اساس آن‌ها توسعه دهند. ما قصد داریم این APIهای جدید را در یکی از نسخه‌های اصلی آینده به حالت پایدار (stable) برسانیم. البته ممکن است در این فرآیند تغییرات شکننده (breaking changes) نیز اعمال شود، اما این کار زمانی انجام خواهد شد که پروژه‌ها و کتابخانه‌های وابسته فرصت کافی برای آزمایش و ارزیابی این قابلیت‌های جدید را داشته باشند. منابع: * [بحث و گفتگو](https://github.com/vitejs/vite/discussions/16358) جایی که ما در حال جمع‌آوری نظرات درباره APIهای جدید هستیم. * [PR مربوط به Environment API](https://github.com/vitejs/vite/pull/16471) جایی که API جدید پیاده‌سازی و بررسی شده است. لطفاً نظرات و بازخوردهای خود را با ما به اشتراک بگذارید. ::: ## استانداردسازی محیط‌ها Vite 6 مفهوم محیط‌ها را استانداردسازی می‌کند. تا نسخه‌ی Vite 5، دو محیط پیش‌فرض وجود داشت: (`client` و در صورت نیاز `ssr`). Environment API (رابط برنامه‌نویسی محیط) جدید به کاربران و توسعه‌دهندگان فریمورک‌ها اجازه می‌دهد تا به تعداد مورد نیاز محیط ایجاد کنند و آن را با نحوه‌ی عملکرد برنامه‌هایشان در محیط پروداکشن تطبیق دهند. این قابلیت جدید نیازمند بازنگری گسترده‌ای در ساختار داخلی بود، اما تلاش زیادی برای حفظ سازگاری با نسخه‌های قبلی صورت گرفته است. هدف اولیه‌ی Vite 6 این است که اکوسیستم را به‌آرامی به نسخه‌ی جدید منتقل کند و پذیرش این APIهای آزمایشی جدید را تا زمانی که تعداد کافی از کاربران مهاجرت کرده و توسعه‌دهندگانِ فریمورک‌ها و افزونه‌ها طراحی جدید را تأیید کنند، به تعویق بیندازد. ## کاهش فاصله بین ساخت و توسعه برای یک SPA/MPA ساده، هیچ API جدیدی در مورد محیط‌ها به پیکربندی افزوده نشده است. از نظر داخلی، Vite گزینه‌ها را به محیط `client` اعمال خواهد کرد، اما نیازی به دانستن این مفهوم هنگام پیکربندی Vite نیست. پیکربندی و رفتار موجود در Vite 5 باید به‌طور یکپارچه در اینجا کار کند. هنگامی که به سمت یک اپلیکیشن معمولی رندر شده در سمت سرور (SSR) می‌رویم، دو محیط خواهیم داشت: * `client`: اپلیکیشن را در مرورگر اجرا می‌کند. * `ssr`: اپلیکیشن را در Node (یا سایر رانتایم‌ها سرور) اجرا می‌کند که صفحات را قبل از ارسال به مرورگر رندر می‌کند. در محیط توسعه (dev)، Vite کد سرور را در همان فرآیند Node که سرور توسعه Vite را اجرا می‌کند، اجرا می‌کند، که شبیه‌سازی نزدیکی به محیط پروداکشن ایجاد می‌کند. با این حال، ممکن است سرورها در رانتایم جاوااسکریپت دیگری مانند [Workerd Cloudflare](https://github.com/cloudflare/workerd) اجرا شوند که محدودیت‌های متفاوتی دارند. اپلیکیشن‌های مدرن همچنین ممکن است در بیشتر از دو محیط اجرا شوند، مثلاً یک مرورگر، یک سرور Node و یک سرور لبه. Vite 5 قادر به نمایاندن مناسب این محیط‌ها نبود. Vite 6 به کاربران امکان می‌دهد برنامه خود را طوری پیکربندی کنند که همه محیط‌های اجرایی آن را در فرایند توسعه و ساخت پوشش دهد. در زمان توسعه، اکنون یک سرور توسعه Vite می‌تواند همزمان کد را در چندین محیط مختلف اجرا کند. سورس کد برنامه همچنان توسط سرور توسعه Vite تبدیل می‌شود. علاوه بر سرور HTTP مشترک، میان‌افزارها، تنظیمات پردازش‌شده و زنجیره پلاگین‌ها، سرور توسعه Vite اکنون دارای مجموعه‌ای از محیط‌های توسعه مستقل است. هر محیط توسعه طوری پیکربندی شده که تا حد امکان به محیط پروداکشن شبیه باشد و به یک رانتایم توسعه متصل است که کد در آن اجرا می‌شود (برای مثال در مورد Workerd، کد سرور اکنون می‌تواند به صورت محلی در Miniflare اجرا شود). در سمت کلاینت، مرورگر کد را ایمپورت و اجرا می‌کند، و در سایر محیط‌ها، یک اجراکننده ماژول، کد تبدیل‌شده را بارگیری و ارزیابی می‌کند. ![Vite Environments](/assets/vite-environments.DZyy20w5.svg) ## پیکربندی محیط‌ها برای یک برنامه SPA/MPA، پیکربندی مشابه Vite 5 خواهد بود. به صورت داخلی، این گزینه‌ها برای پیکربندی محیط `client` استفاده می‌شوند. ```js export default defineConfig({ build: { sourcemap: false, }, optimizeDeps: { include: ['lib'], }, }) ``` این مهم است زیرا ما می‌خواهیم Vite را قابل دسترس نگه داریم و از معرفی مفاهیم جدید تا زمانی که واقعاً به آنها نیاز نباشد، خودداری کنیم. اگر برنامه از چندین محیط تشکیل شده باشد، این محیط‌ها می‌توانند به صورت صریح با گزینه پیکربندی `environments` تنظیم شوند. ```js export default { build: { sourcemap: false, }, optimizeDeps: { include: ['lib'], }, environments: { server: {}, edge: { resolve: { noExternal: true, }, }, }, } ``` اگر به صورت صریح مستند نشده باشد، هر محیط از گزینه‌های پیکربندی سطح بالا ارث می‌برد (به عنوان مثال، محیط‌های جدید `server` و `edge` گزینه `build.sourcemap: false` را به ارث می‌برند). تعداد کمی از گزینه‌های سطح بالا، مانند `optimizeDeps`، فقط برای محیط `client` اعمال می‌شوند، زیرا زمانی که به عنوان پیش‌فرض به محیط‌های سرور اعمال می‌شوند، به خوبی کار نمی‌کنند. محیط `client` همچنین می‌تواند به صورت صریح از طریق `environments.client` پیکربندی شود، اما توصیه می‌کنیم این کار را با گزینه‌های سطح بالا انجام دهید تا پیکربندی کلاینت هنگام اضافه کردن محیط‌های جدید بدون تغییر باقی بماند. رابط `EnvironmentOptions` تمام گزینه‌های مختص هر محیط را در اختیار قرار می‌دهد. برخی گزینه‌های محیطی هم برای `build` و هم برای `dev` اعمال می‌شوند، مانند `resolve`. همچنین `DevEnvironmentOptions` و `BuildEnvironmentOptions` برای گزینه‌های خاص توسعه و ساخت وجود دارند (مانند `dev.warmup` یا `build.outDir`). برخی گزینه‌ها مانند `optimizeDeps` فقط برای توسعه اعمال می‌شوند، اما برای حفظ سازگاری با نسخه‌های قبلی، به جای قرار گرفتن در `dev`، در سطح بالا نگه داشته شده‌اند. ```ts interface EnvironmentOptions { define?: Record resolve?: EnvironmentResolveOptions optimizeDeps: DepOptimizationOptions consumer?: 'client' | 'server' dev: DevOptions build: BuildOptions } ``` رابط `UserConfig` از رابط `EnvironmentOptions` گسترش می‌یابد، که امکان پیکربندی کلاینت و پیش‌فرض‌ها را برای سایر محیط‌ها، از طریق گزینه `environments` فراهم می‌کند. محیط `client` و یک محیط سرور با نام `ssr` همیشه در زمان توسعه حاضر هستند. این امر باعث سازگاری با نسخه‌های قبلی برای `server.ssrLoadModule(url)` و `server.moduleGraph` می‌شود. در زمان بیلد، محیط `client` همیشه وجود دارد، و محیط `ssr` تنها در صورتی وجود خواهد داشت که به صورت صریح پیکربندی شده باشد (با استفاده از `environments.ssr` یا برای سازگاری با نسخه‌های قبلی `build.ssr`). یک برنامه لزوماً نیازی به استفاده از نام `ssr` برای محیط SSR خود ندارد، می‌تواند آن را به عنوان مثال `server` نام‌گذاری کند. ```ts interface UserConfig extends EnvironmentOptions { environments: Record // other options } ``` توجه داشته باشید که ویژگی سطح بالای `ssr` پس از پایدار شدن API محیط، منسوخ خواهد شد. این گزینه نقشی مشابه با `environments` دارد، اما فقط برای محیط پیش‌فرض `ssr` است و تنها امکان پیکربندی مجموعه کوچکی از گزینه‌ها را فراهم می‌کند. ## نمونه‌های محیط سفارشی APIهای پیکربندی سطح پایین در دسترس هستند تا ارائه‌دهندگان رانتایم بتوانند محیط‌هایی با پیش‌فرض‌های مناسب برای رانتایم خود فراهم کنند. این محیط‌ها همچنین می‌توانند فرآیندها یا نخ‌های دیگری را برای اجرای ماژول‌ها در زمان توسعه در یک رانتایم نزدیک‌تر به محیط تولید ایجاد کنند. ```js import { customEnvironment } from 'vite-environment-provider' export default { build: { outDir: '/dist/client', }, environments: { ssr: customEnvironment({ build: { outDir: '/dist/ssr', }, }), }, } ``` ## سازگاری با نسخه‌های قبلی APIهای سرور فعلی Vite هنوز منسوخ نشده‌اند و با Vite 5 سازگار هستند. API محیط جدید در حالت آزمایشی است. متد `server.moduleGraph` یک نمای ترکیبی از گراف‌های ماژول‌های کلاینت و SSR را باز می‌گرداند. نودهای ماژول ترکیبی که سازگاری با نسخه‌های قبلی دارند، از تمام متدهای این آبجکت باز می‌گردند. همین الگو برای نودهای ماژول‌هایی که به متد `handleHotUpdate` ارسال می‌شوند نیز استفاده می‌شود. به عبارت دیگر، این ویژگی به شما اجازه می‌دهد که هم ماژول‌های مرتبط با کلاینت و هم ماژول‌های مرتبط با SSR را به‌طور همزمان مدیریت کنید و نودهای مربوط به هرکدام را به‌طور یکپارچه در دسترس داشته باشید. ما هنوز توصیه نمی‌کنیم که به API محیط تغییر دهید. هدف ما این است که بخش زیادی از کاربران قبل از این تغییرات، Vite 6 را پذیرفته و استفاده کنند تا پلاگین‌ها نیازی به نگهداری دو نسخه مختلف نداشته باشند. برای اطلاعات بیشتر در مورد تغییرات مخرب آینده و مسیر ارتقا، به بخش تغییرات مخرب آینده مراجعه کنید: * [`this.environment` در Hooks](/changes/this-environment-in-hooks) * [HMR `hotUpdate` Plugin Hook](/changes/hotupdate-hook) * [انتقال به API‌های مخصوص هر محیط](/changes/per-environment-apis) * [SSR با استفاده از `ModuleRunner` API](/changes/ssr-using-modulerunner) * [پلاگین‌های مشترک در طول فرآیند ساخت](/changes/shared-plugins-during-build) ## کاربران هدف این راهنما مفاهیم پایه‌ای درباره محیط‌ها را برای کاربران نهایی ارائه می‌دهد. نویسندگان پلاگین‌ها یک API سازگارتر برای تعامل با پیکربندی محیط فعلی دارند. اگر شما بر روی Vite توسعه می‌دهید، راهنمای [API پلاگین‌های محیط](./api-environment-plugins.md) روش استفاده از API‌های اضافی پلاگین‌ها را توضیح می‌دهد که از محیط‌های سفارشی متعدد پشتیبانی می‌کنند. فریم‌ورک‌ها می‌توانند تصمیم بگیرند که محیط‌ها را در سطوح مختلفی در دسترس قرار دهند. اگر شما نویسنده یک فریم‌ورک هستید، برای آشنایی با بخش برنامه‌نویسی API محیط، ادامه مطلب را در [راهنمای API محیط برای فریم‌ورک‌ها](./api-environment-frameworks) مطالعه کنید. برای ارائه‌دهندگان رانتایم (Runtime providers)، [راهنمای API محیط برای رانتایم](./api-environment-runtimes.md) توضیح می‌دهد که چگونه می‌توان یک محیط سفارشی را برای استفاده توسط فریم‌ورک‌ها و کاربران ارائه داد. --- --- url: /changes/ssr-using-modulerunner.md --- # SSR با استفاده از API `ModuleRunner` ::: tip بازخورد بازخورد خود را در [بحث بازخورد API محیط](https://github.com/vitejs/vite/discussions/16358) با ما در میان بگذارید. ::: `server.ssrLoadModule` با وارد کردن از یک [Module Runner](/guide/api-environment#modulerunner) جایگزین شده است. دامنه تأثیر: `نویسندگان افزونه‌های Vite` ::: warning منسوخ شدن در آینده `ModuleRunner` برای اولین بار در نسخه `v6.0` معرفی شد. منسوخ شدن `server.ssrLoadModule` برای یک نسخه اصلی آینده برنامه‌ریزی شده است. برای شناسایی استفاده خود، `future.removeSsrLoadModule` را در تنظیمات Vite خود روی `"warn"` تنظیم کنید. ::: ## انگیزه متد `server.ssrLoadModule(url)` فقط امکان وارد کردن ماژول‌ها در محیط `ssr` را فراهم می‌کند و تنها می‌تواند ماژول‌ها را در همان پروسه سرور توسعه Vite اجرا کند. برای اپلیکیشن‌هایی با محیط‌های سفارشی، هر کدام با یک `ModuleRunner` مرتبط هستند که ممکن است در یک نخ یا پروسه جداگانه اجرا شود. برای وارد کردن ماژول‌ها، اکنون از `moduleRunner.import(url)` استفاده می‌کنیم. ## راهنمای مهاجرت به [راهنمای API محیط برای فریم‌ورک‌ها](../guide/api-environment-frameworks.md) مراجعه کنید. --- --- url: /config/ssr-options.md --- # آپشن‌های SSR آپشن‌های این بخش هم در حالت توسعه (`dev`) و هم در مرحله ساخت (`build`) اعمال خواهند شد،مگر اینکه خلاف آن ذکر شده باشد. ## ssr.external * **تایپ:** `string[]‎ | true` * **مرتبط:** [SSR Externals](/guide/ssr#ssr-externals) وابستگی‌های مشخص‌شده و وابستگی‌های وابسته به آن‌ها را برای SSR به حالت externalize در می‌آورد (مستقل کردن یا خارج کردن یک وابستگی از باندل اصلی). به‌طور پیش‌فرض، همه وابستگی‌ها به‌جز وابستگی‌های لینک‌شده (برای HMR) externalize می‌شوند. اگر می‌خواهید وابستگی لینک‌شده‌ای را نیز externalize کنید، می‌توانید نام آن را در این آپشن مشخص کنید. اگر `true` باشد، تمام وابستگی‌ها از جمله وابستگی‌های لینک‌شده externalized می‌شوند. توجه کنید که وابستگی‌هایی که به‌طور مشخص و صریح لیست شده‌اند (با استفاده از تایپ `string[]‎`) در هر حالتی اولویت دارند، حتی اگر در `ssr.noExternal` (با هر تایپی) نیز تعریف شده باشند. ## ssr.noExternal * **تایپ:** `string | RegExp | (string | RegExp)[] | true` * **مرتبط:** [SSR Externals](/guide/ssr#ssr-externals) از مستقل شدن (externalized) وابستگی‌های فهرست‌شده برای SSR جلوگیری کنید، زیرا آن‌ها در مرحله ساخت (build) باندل خواهند شد. به‌طور پیش‌فرض، فقط وابستگی‌های لینک‌شده (linked) مستقل نمی‌شوند (برای HMR). اگر ترجیح می‌دهید که وابستگی‌های لینک‌شده نیز externalized شوند (مستقل کردن یا خارج کردن یک وابستگی از باندل اصلی)، می‌توانید نام آن‌ها را به گزینه `ssr.external` اضافه کنید. اگر `true` باشد، هیچ وابستگی‌ای مستقل (externalized) نخواهد شد. با این حال، وابستگی‌هایی که به‌طور صریح در `ssr.external` (با استفاده از تایپ `string[]‎`) فهرست شده‌اند، می‌توانند اولویت داشته باشند و همچنان externalized شوند. اگر `ssr.target: 'node'` تنظیم شده باشد، ماژول‌های داخلی Node.js نیز به‌طور پیش‌فرض externalized خواهند شد. توجه داشته باشید که اگر هر دو گزینه `ssr.noExternal: true` و `ssr.external: true` کانفیگ شده باشند، `ssr.noExternal` اولویت دارد و هیچ وابستگی‌ای مستقل (externalized) نخواهد شد. ## ssr.target * **تایپ:** `'node' | 'webworker'` * **پیش‌فرض:** `node` بیلد target برای سرور SSR. ## ssr.resolve.conditions * **تایپ:** `string[]‎` * **پیش‌فرض:** `['module', 'node', 'development|production']` (`defaultServerConditions`) (`['module', 'browser', 'development|production']` (`defaultClientConditions`) برای `ssr.target === 'webworker'`) * **مرتبط:** [Resolve Conditions](./shared-options.md#resolve-conditions) این شرایط در مسیر پلاگین‌ها استفاده می‌شوند و فقط بر وابستگی‌های non-externalized در زمان ساخت SSR تأثیر می‌گذارند. برای تأثیرگذاری بر ایمپورت های externalized، از `ssr.resolve.externalConditions` استفاده کنید. ## ssr.resolve.externalConditions * **تایپ:** `string[]‎` * **پیش‌فرض:** `['node']` شرایطی که در هنگام ایمپورت SSR (شامل `ssrLoadModule`) برای وابستگی‌های مستقیم externalized (وابستگی‌های خارجی که توسط Vite ایمپورت شده‌اند) اعمال می‌شوند. :::tip نکته هنگام استفاده از این آپشن، مطمئن شوید که Node را با [`flag --conditions`](https://nodejs.org/docs/latest/api/cli.html#-c-condition---conditionscondition) وبا مقادیر یکسان در هر دو حالت dev و build اجرا کنید تا رفتار یکسانی داشته باشید. برای مثال، وقتی `['node', 'custom']` را تنظیم می‌کنید، باید در حالت dev دستور `NODE_OPTIONS='--conditions custom' vite` و پس از بیلد دستور `NODE_OPTIONS="--conditions custom" node ./dist/server.js` را اجرا کنید. ::: ## ssr.resolve.mainFields * **تایپ:** `string[]‎` * **پیش‌فرض:** `['module', 'jsnext:main', 'jsnext']` فهرستی از فیلدهای `package.json` که هنگام تشخیص entry pointهای یک پکیج بررسی می‌شوند. توجه داشته باشید که این گزینه نسبت به اکسپورت شرطی که از فیلد `exports` شناسایی می‌شود، اولویت کم‌تری دارد: اگر entry point با موفقیت از `exports` تشخیص داده شود، فیلد `main` نادیده گرفته خواهد شد. این تنظیم فقط بر وابستگی‌های غیرمستقل (non-externalized) تأثیر می‌گذارد. --- --- url: /config/worker-options.md --- # آپشن‌های Worker آپشن‌های این بخش برای همه‌ی حالت‌های dev، build و preview اعمال می‌شوند مگر آنکه بطور مشخص ذکر شده باشد. ## worker.format * **تایپ:** `'es' | 'iife'` * **مقدار پیش فرض:** `'iife'` فرمت خروجی برای باندل worker. ## worker.plugins * **تایپ:** [`() => (Plugin | Plugin[])[]`](./shared-options#plugins) پلاگین های vite که بر باندل های worker اعمال می‌شوند. توجه کنید که [config.plugins](./shared-options#plugins) فقط در حالت dev بر روی باندل های worker اعمال خواهند شد و برای حالت build باید از این گزینه استفاده کنید. این تابع باید نمونه‌های جدیدی از پلاگین‌ها را بازگرداند چون آن‌ها به‌صورت موازی در build های rollup اجرا می‌شوند. به همین دلیل، تغییر گزینه‌های config.worker در هوک config نادیده گرفته می‌شود. ## worker.rollupOptions * **تایپ:** [`RollupOptions`](https://rollupjs.org/configuration-options/) آپشن‌های Rollup برای ساخت باندل worker. --- --- url: /guide/using-plugins.md --- # استفاده از پلاگین‌ها Vite از طریق پلاگین‌ها قابل گسترش است. این پلاگین‌ها بر پایه‌ی رابط پلاگین‌های Rollup طراحی شده‌اند، با این تفاوت که گزینه‌های اضافی مخصوص Vite نیز به آن‌ها افزوده شده است. به همین دلیل، کاربران Vite می‌توانند هم‌زمان از اکوسیستم قدرتمند پلاگین‌های Rollup بهره ببرند و در عین حال، سرور توسعه و قابلیت‌های SSR را مطابق نیاز خود سفارشی کنند. ## اضافه کردن یک پلاگین برای استفاده از یک پلاگین، باید آن را به `devDependencies` پروژه اضافه کرده و در آرایه `plugins` در فایل کانفیگ `vite.config.js` قرار دهید. به عنوان مثال، برای پشتیبانی از مرورگرهای قدیمی، می‌توان از پلاگین رسمی [‎@vitejs/plugin-legacy](https://github.com/vitejs/vite/tree/main/packages/plugin-legacy) استفاده کرد: ``` $ npm add -D @vitejs/plugin-legacy ``` ```js twoslash [vite.config.js] import legacy from '@vitejs/plugin-legacy' import { defineConfig } from 'vite' export default defineConfig({ plugins: [ legacy({ targets: ['defaults', 'not IE 11'], }), ], }) ``` آرایه `plugins` همچنین می‌تواند پیش‌تنظیماتی را بپذیرد که شامل چندین پلاگین به عنوان یک عنصر واحد هستند. این ویژگی برای موارد پیچیده‌تر (مثل یکپارچه‌سازی فریم‌ورک‌ها) که با استفاده از چندین پلاگین پیاده‌سازی می‌شوند، مفید است. آرایه‌ی پلاگین‌ها به طور داخلی به صورت تخت (flat) پردازش خواهد شد. پلاگین‌های نادرست نادیده گرفته خواهند شد. این ویژگی می‌تواند برای فعال یا غیرفعال کردن راحت پلاگین‌ها مورد استفاده قرار گیرد. ## یافتن پلاگین‌ها :::tip نکته Vite هدف دارد تا پشتیبانی آماده از الگوهای رایج توسعه وب را فراهم کند. قبل از جستجو برای یک پلاگین Vite یا پلاگین سازگار با Rollup، پیشنهاد می‌شود راهنمای [ویژگی‌ها](../guide/features.md) را بررسی کنید. بسیاری از قابلیت‌هایی که در پروژه‌های Rollup نیاز به پلاگین دارند، در Vite به طور پیش‌فرض پشتیبانی می‌شوند. ::: بخش [پلاگین‌ها](../plugins/) را برای اطلاعات بیشتر درباره پلاگین‌های رسمی بررسی کنید. پلاگین‌های جامعه (community) در [awesome-vite](https://github.com/vitejs/awesome-vite#plugins) لیست شده‌اند. همچنین می‌توانید پلاگین‌هایی که از [کنوانسیون‌های توصیه‌شده](./api-plugin.md#conventions) پیروی می‌کنند را با استفاده از [جستجوی npm برای vite-plugin](https://www.npmjs.com/search?q=vite-plugin\&ranking=popularity) برای پلاگین‌های Vite یا [جستجوی npm برای rollup-plugin](https://www.npmjs.com/search?q=rollup-plugin\&ranking=popularity) برای پلاگین‌های Rollup پیدا کنید. ## ترتیب اعمال پلاگین برای سازگاری با برخی از پلاگین‌های Rollup، ممکن است نیاز باشد ترتیب پلاگین‌ها را تغییر دهید یا آن‌ها را فقط در زمان بیلد اعمال کنید. این باید جزئیات پیاده‌سازی در سطح پلاگین‌های Vite باشد. شما می‌توانید موقعیت یک پلاگین را با استفاده از اصلاح‌کننده `enforce` تنظیم کنید: * `pre`: اجرای پلاگین قبل از پلاگین‌های اصلی Vite * پیش‌فرض: اجرای پلاگین بعد از پلاگین‌های اصلی Vite * `post`: اجرای پلاگین بعد از پلاگین‌های build Vite ```js twoslash [vite.config.js] import image from '@rollup/plugin-image' import { defineConfig } from 'vite' export default defineConfig({ plugins: [ { ...image(), enforce: 'pre', }, ], }) ``` برای اطلاعات دقیق، راهنمای [API پلاگین‌ها](./api-plugin.md#plugin-ordering) را بررسی کنید. ## فراخوانی شرطی به طور پیش‌فرض، پلاگین‌ها برای هر دو حالت serve و build فراخوانی می‌شوند. در مواردی که نیاز است یک پلاگین به صورت شرطی فقط در زمان serve یا build اعمال شود، از ویژگی `apply` استفاده کنید تا فقط در زمان `'build'` یا `'serve'` فراخوانی شوند: ```js twoslash [vite.config.js] import typescript2 from 'rollup-plugin-typescript2' import { defineConfig } from 'vite' export default defineConfig({ plugins: [ { ...typescript2(), apply: 'build', }, ], }) ``` ## بیلد پلاگین‌ها برای مشاهده مستندات مربوط به ایجاد پلاگین‌ها، راهنمای [API پلاگین‌ها](./api-plugin.md) را بررسی کنید. --- --- url: /guide/api-environment-instances.md --- # استفاده از نمونه‌های `Environment` :::warning Experimental رابط Environment API هنوز در مرحله‌ی آزمایشی (experimental) هست. با این حال، ما تلاش می‌کنیم بین نسخه‌های اصلی (major) پایداری این APIها را حفظ کنیم تا جامعه‌ی توسعه‌دهندگان بتوانند با آن‌ها کار کرده و تجربیات خود را بر اساس آن‌ها توسعه دهند. ما قصد داریم این APIهای جدید را در یکی از نسخه‌های اصلی آینده به حالت پایدار (stable) برسانیم. البته ممکن است در این فرآیند تغییرات شکننده (breaking changes) نیز اعمال شود، اما این کار زمانی انجام خواهد شد که پروژه‌ها و کتابخانه‌های وابسته فرصت کافی برای آزمایش و ارزیابی این قابلیت‌های جدید را داشته باشند. منابع: * [بحث و گفتگو](https://github.com/vitejs/vite/discussions/16358) جایی که ما در حال جمع‌آوری نظرات درباره APIهای جدید هستیم. * [PR مربوط به Environment API](https://github.com/vitejs/vite/pull/16471) جایی که API جدید پیاده‌سازی و بررسی شده است. لطفاً نظرات و بازخوردهای خود را با ما به اشتراک بگذارید. ::: ## دسترسی به محیط‌ها در حالت توسعه (dev)، می‌توان با استفاده از `server.environments` به محیط‌های موجود در یک سرور توسعه دسترسی داشت: ```js // دریافت کنید configureServer سرور را ایجاد کنید یا آن را از هوک const server = await createServer(/* options */) const clientEnvironment = server.environments.client clientEnvironment.transformRequest(url) console.log(server.environments.ssr.moduleGraph) ``` همچنین می‌توانید از طریق پلاگین‌ها به محیط فعلی دسترسی داشته باشید. برای جزئیات بیشتر، به [API محیط برای پلاگین‌ها](./api-environment-plugins.md#accessing-the-current-environment-in-hooks) مراجعه کنید. ## کلاس `DevEnvironment` در حالت توسعه (dev)، هر محیط یک نمونه از کلاس `DevEnvironment` است: ```ts class DevEnvironment { /** * Vite شناسه‌ی منحصربه‌فرد برای محیط در یک سرور * را در دسترس قرار می‌دهد 'ssr' و 'client' محیط‌های Vite ، به‌طور پیش‌فرض */ name: string /** * کانال ارتباطی برای ارسال و دریافت پیام‌ها از * اجراکننده ماژول مرتبط در رانتام هدف */ hot: NormalizedHotChannel /** * گراف نودهای ماژول، با روابط وارد شده بین * ماژول‌های پردازش شده و نتیجه کش شده کد پردازش شده */ moduleGraph: EnvironmentModuleGraph /** * پلاگین‌های اضافه شده برای این محیط، از جمله پلاگین‌هایی که * مخصوص هر محیط ایجاد شده‌اند `create` با استفاده از هوک */ plugins: Plugin[] /** * امکان حل و فصل، بارگذاری و تبدیل کد را از طریق * مسیر پردازش پلاگین های محیط فراهم می‌کند */ pluginContainer: EnvironmentPluginContainer /** * گزینه های تنظیمات اضافه شده برای این محیط. گزینه‌های موجود در * دامنه‌ی کلی سرور به‌عنوان پیش‌فرض برای تمام محیط‌ها درنظر گرفته می‌شوند * optimizedDeps و external ، resolve conditions می‌توانند بازنویسی شوند. مانند */ config: ResolvedConfig & ResolvedDevEnvironmentOptions constructor( name: string, config: ResolvedConfig, context: DevEnvironmentContext, ) /** * را به یک شناسه تبدیل می‌کند، آن را بارگذاری کرده و URL آدرس * کد را از طریق مسیر پردازش پلاگین‌ها پردازش می‌کند * گراف ماژول نیز به‌روزرسانی می‌شود */ async transformRequest(url: string): Promise /** * یک درخواست را برای پردازش با اولویت پایین ثبت می‌کند. این کار * اطلاعاتی Vite برای جلوگیری از وابستگی‌های زنجیره‌ای مفید است. سرور * درباره‌ی ماژول‌های ایمپورت شده توسط درخواست‌های دیگر دارد، بنابراین می‌تواند * گراف ماژول را از پیش آماده کند تا ماژول‌ها هنگام درخواست، پردازش‌ شده باشند */ async warmupRequest(url: string): Promise } ``` با `DevEnvironmentContext` به صورت زیر است: ```ts interface DevEnvironmentContext { hot: boolean transport?: HotChannel | WebSocketServer options?: EnvironmentOptions remoteRunner?: { inlineSourceMap?: boolean } depsOptimizer?: DepsOptimizer } ``` و با `TransformResult` به صورت زیر است: ```ts interface TransformResult { code: string map: SourceMap | { mappings: '' } | null etag?: string deps?: string[] dynamicDeps?: string[] } ``` یک نمونه از محیط در سرور Vite به شما امکان می‌دهد که یک URL را با استفاده از متد `environment.transformRequest(url)` پردازش کنید. این تابع از خط پردازش پلاگین‌ها برای تبدیل `url` به یک شناسه‌ی ماژول (`id`) استفاده می‌کند، آن را بارگذاری می‌کند (با خواندن فایل از فایل سیستم یا از طریق پلاگینی که یک ماژول مجازی را پیاده‌سازی کرده است) و سپس کد را تبدیل می‌کند. در حین تبدیل ماژول،ایمپورت‌های آن و دیگر اطلاعات متادیتا در گراف ماژول محیط ثبت می‌شوند، با ایجاد یا به‌روزرسانی نود ماژول مربوطه. پس از اتمام پردازش، نتیجه‌ی تبدیل نیز در ماژول ذخیره می‌شود. :::info نام‌گذاری transformRequest در نسخه‌ی کنونی این پیشنهاد، از `transformRequest(url)` و `warmupRequest(url)` استفاده می‌کنیم تا درک و بحث درباره‌ی آن برای کاربرانی که به API فعلی Vite عادت دارند، آسان‌تر باشد. پیش از انتشار، می‌توانیم فرصت را برای بازبینی این نام‌ها نیز غنیمت بشماریم. برای مثال، ممکن است نام آن را به `environment.processModule(url)` یا `environment.loadModule(url)` تغییر دهیم، مشابه `context.load(id)` در پلاگین‌های Rollup. در حال حاضر، حفظ نام‌های فعلی و به تعویق انداختن این بحث را بهتر می‌دانیم. ::: ## گراف‌های ماژول مجزا هر محیط یک گراف ماژول ایزوله دارد. همه گراف‌های ماژول امضای یکسانی دارند، بنابراین می‌توان الگوریتم‌های کلی برای پیمایش یا پیمایش گراف بدون وابستگی به محیط پیاده‌سازی کرد. مثال خوب آن `hotUpdate` است. وقتی یک فایل تغییر می‌کند، گراف ماژول هر محیط بررسی می‌شود تا ماژول‌های تحت تأثیر را پیدا کند و HMR را به صورت مستقل برای هر محیط انجام دهد. ::: info نکته Vite نسخه ۵ یک گراف ماژول مشترک بین کلاینت و SSR داشت. اگر یک نود هنوز پردازش نشده یا باطل شده باشد، نمی‌توان تشخیص داد که مربوط به محیط کلاینت، SSR، یا هر دو است. نودهای ماژول دارای برخی ویژگی‌های پیشونددار هستند، مانند `clientImportedModules` و `ssrImportedModules` (به‌علاوه `importedModules` که اجتماع هر دو را برمی‌گرداند). فیلد `importers` همه ایمپورترهای مربوط به هر دو محیط کلاینت و SSR را برای هر نود ماژول شامل می‌شود. هر نود ماژول همچنین دارای `transformResult` و `ssrTransformResult` است. لایه‌ای برای حفظ سازگاری به اکوسیستم اجازه می‌دهد تا از `server.moduleGraph` منسوخ شده به این مدل جدید مهاجرت کند. ::: هر ماژول توسط یک نمونه از `EnvironmentModuleNode` نشان داده می‌شود. ممکن است ماژول‌ها در گراف بدون پردازش اولیه ثبت شوند (در این حالت، مقدار `transformResult` برابر `null` خواهد بود). فیلدهای `importers` و `importedModules` نیز پس از پردازش ماژول به‌روزرسانی می‌شوند. ```ts class EnvironmentModuleNode { environment: string url: string id: string | null = null file: string | null = null type: 'js' | 'css' importers = new Set() importedModules = new Set() importedBindings: Map> | null = null info?: ModuleInfo meta?: Record transformResult: TransformResult | null = null acceptedHmrDeps = new Set() acceptedHmrExports: Set | null = null isSelfAccepting?: boolean lastHMRTimestamp = 0 lastInvalidationTimestamp = 0 } ``` `environment.moduleGraph` is an instance of `EnvironmentModuleGraph`: ```ts export class EnvironmentModuleGraph { environment: string urlToModuleMap = new Map() idToModuleMap = new Map() etagToModuleMap = new Map() fileToModulesMap = new Map>() constructor( environment: string, resolveId: (url: string) => Promise, ) async getModuleByUrl( rawUrl: string, ): Promise getModuleById(id: string): EnvironmentModuleNode | undefined getModulesByFile(file: string): Set | undefined onFileChange(file: string): void onFileDelete(file: string): void invalidateModule( mod: EnvironmentModuleNode, seen: Set = new Set(), timestamp: number = monotonicDateNow(), isHmr: boolean = false, ): void invalidateAll(): void async ensureEntryFromUrl( rawUrl: string, setIsSelfAccepting = true, ): Promise createFileOnlyEntry(file: string): EnvironmentModuleNode async resolveUrl(url: string): Promise updateModuleTransformResult( mod: EnvironmentModuleNode, result: TransformResult | null, ): void getModuleByEtag(etag: string): EnvironmentModuleNode | undefined } ``` --- --- url: /releases.md --- # انتشارها انتشارهای Vite از نسخه‌گذاری معنایی ([Semantic Versioning](https://semver.org/)) پیروی می‌کنند. آخرین نسخه‌ی پایدار Vite را می‌توانید در صفحه‌ی [npm](https://www.npmjs.com/package/vite) در npm ببینید. فهرست کامل تغییرات نسخه‌های گذشته در [GitHub](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md) در دسترس است. ## چرخه انتشار دروقع Vite چرخه‌ی انتشار ثابتی ندارد. * نسخه‌های **پچ (Patch)** در صورت نیاز منتشر می‌شوند (معمولاً هر هفته). * نسخه‌های **فرعی (Minor)** همیشه شامل ویژگی‌های جدید هستند و در صورت نیاز منتشر می‌شوند. این نسخه‌ها همیشه یک مرحله پیش‌انتشار بتا (pre-release) دارند (معمولاً هر دو ماه یک‌بار). * نسخه‌های **اصلی (Major)** معمولاً با [برنامه پایان عمر (EOL) Node.js](https://endoflife.date/nodejs) هماهنگ هستند و از قبل اعلام می‌شوند. این نسخه‌ها پس از بحث‌های بلندمدت با اکوسیستم منتشر شده و مراحل پیش‌انتشار آلفا و بتا را طی می‌کنند (معمولاً هر سال یک‌بار). بازه‌های نسخه‌ی Vite که توسط تیم Vite پشتیبانی می‌شوند به‌صورت خودکار بر اساس موارد زیر تعیین می‌شوند: * نسخه‌ی **Current Minor** به‌طور منظم رفع اشکال (bug fixe) می‌شود. * نسخه‌ی **Previous Major** (فقط آخرین نسخه‌ی Minor آن) و **Previous Minor** اصلاحات مهم و پچ‌های امنیتی دریافت می‌کنند. * نسخه‌های **Second-to-last Major** و **Second-to-last Minor** فقط پچ‌های امنیتی دریافت می‌کنند. * تمام نسخه‌های قبل از این بازه‌ها دیگر پشتیبانی نمی‌شوند. برای مثال، اگر آخرین نسخه‌ی Vite برابر با ۵.۳.۱۰ باشد: * پچ‌های معمولی برای `vite@5.3.` منتشر می‌شوند. * اصلاحات مهم و پچ‌های امنیتی به `vite@4` و `.vite@5.2` منتقل می‌شوند. * پچ‌های امنیتی همچنین به `vite@3` و `vite@5.1` منتقل می‌شوند. * نسخه‌های `vite@2` و `v‍ite@5.0` دیگر پشتیبانی نمی‌شوند. کاربران باید برای دریافت به‌روزرسانی‌ها، نسخه‌ی خود را ارتقا (upgrade) دهند. ما توصیه می‌کنیم Vite را به‌صورت منظم به‌روزرسانی کنید. هنگام ارتقا به هر نسخه‌ی اصلی (Major)، [راهنمای مهاجرت](https://vite.dev/guide/migration.html) را بررسی کنید. تیم Vite با پروژه‌های اصلی اکوسیستم همکاری نزدیکی دارد تا کیفیت نسخه‌های جدید را تضمین کند. نسخه‌های جدید Vite قبل از انتشار، از طریق پروژه [vite-ecosystem-ci project](https://github.com/vitejs/vite-ecosystem-ci) تست می‌شوند. بیشتر پروژه‌هایی که از Vite استفاده می‌کنند، باید بتوانند سریعاً پشتیبانی ارائه دهند یا به نسخه‌های جدید مهاجرت کنند. ## حالات خاص در نسخه‌گذاری معنایی ### تعاریف تایپ اسکریپت ممکن است بین نسخه‌های Minor تغییرات ناسازگار در تعاریف تایپ اسکریپت ارائه دهیم. دلیل این موضوع این است که: * گاهی خود تایپ اسکریپت بین نسخه‌های Minor تغییرات ناسازگار دارد و ما ممکن است برای پشتیبانی از نسخه‌های جدیدتر، تایپ‌ها را تغییر دهیم. * گاهی لازم است از ویژگی‌هایی استفاده کنیم که فقط در نسخه‌های جدیدتر تایپ اسکریپت وجود دارند، بنابراین حداقل نسخه‌ی موردنیاز تایپ‌اسکریپت را افزایش می‌دهیم. * اگر از تایپ اسکریپت استفاده می‌کنید، می‌توانید بازه نسخه semver را قفل کنید روی نسخه فرعی فعلی و هنگام انتشار نسخه Minor جدید Vite به‌صورت دستی ارتقا دهید. ### esbuild [esbuild](https://esbuild.github.io/) هنوز به نسخه ۱.۰.۰ نرسیده و گاهی تغییرات ناسازگار دارد که برای دسترسی به ویژگی‌ها و بهبودهای عملکردی جدید باید آن‌ها را در Vite بگنجانیم. ممکن است نسخه esbuild را در یک نسخه‌ی Minor در Vite افزایش دهیم. ### نسخه‌های ناپایدار Node.js نسخه‌های ناپایدار Node.js (شماره فرد) به‌عنوان بخشی از تست‌های CI Vite آزمایش نمی‌شوند، اما تا قبل از [پایان عمر](https://endoflife.date/nodejs) آن‌ها باید کار کنند. ## پیش‌انتشارها نسخه‌های Minor معمولاً از چندین نسخه‌ی بتا (با تعداد غیرثابت) عبور می‌کنند. نسخه‌های Major نیز یک مرحله آلفا و یک مرحله بتا خواهند داشت. پیش‌انتشارها به پذیرندگان اولیه و نگهدارندگان اکوسیستم اجازه می‌دهند تا تست‌های یکپارچگی و پایداری انجام دهند و بازخورد بدهند. هیچوقت از پیش‌انتشارها در محیط production استفاده نکنید. همه پیش‌انتشارها ناپایدار محسوب می‌شوند و ممکن است تغییرات ناسازگار داشته باشند. همیشه هنگام استفاده از پیش‌انتشارها نسخه دقیق را قفل کنید. ## فرایند منسوخ شدن ما به‌صورت دوره‌ای ویژگی‌هایی که در نسخه‌های Minor با گزینه‌های بهتر جایگزین شده‌اند را منسوخ می‌کنیم. ویژگی‌های منسوخ‌شده همچنان با یک هشدار یا لاگ کار می‌کنند و در نسخه‌ی Minor بعدی پس از اعلام منسوخ‌شدن حذف خواهند شد. [راهنمای مهاجرت](https://vite.dev/guide/migration.html) هر نسخه‌ی Major، این حذف‌ها را فهرست کرده و مسیر ارتقا را مستند می‌کند.ض ## ویژگی‌های آزمایشی برخی ویژگی‌ها هنگام انتشار در نسخه پایدار Vite به‌عنوان آزمایشی علامت‌گذاری می‌شوند. ویژگی‌های آزمایشی به ما کمک می‌کنند تا تجربه‌ی واقعی کاربران را جمع‌آوری کنیم و طراحی نهایی آن‌ها را بهبود دهیم. هدف این است که کاربران با استفاده در محیط تولید بازخورد دهند. خود ویژگی‌های آزمایشی ناپایدار هستند و فقط باید به‌صورت کنترل‌شده استفاده شوند. این ویژگی‌ها ممکن است بین نسخه‌های Minor تغییر کنند، بنابراین کاربران هنگام استفاده باید نسخه Vite خود را قفل کنند. برای هر ویژگی آزمایشی، [بحثی در GitHub](https://github.com/vitejs/vite/discussions/categories/feedback?discussions_q=is%3Aopen+label%3Aexperimental+category%3AFeedback) ایجاد خواهیم کرد. --- --- url: /changes/per-environment-apis.md --- # انتقال به APIهای مخصوص هر محیط ::: tip بازخورد بازخورد خود را در [بحث بازخورد API محیط](https://github.com/vitejs/vite/discussions/16358) با ما در میان بگذارید. ::: چندین API از `ViteDevServer` که به گراف ماژول‌ها و تبدیل ماژول‌ها مرتبط بودند، به نمونه‌های `DevEnvironment` منتقل شده‌اند. دامنه تأثیر: `نویسندگان افزونه‌های Vite` ::: warning منسوخ شدن در آینده نمونه `Environment` برای اولین بار در نسخه `v6.0` معرفی شد. منسوخ شدن `server.moduleGraph` و سایر متدهایی که اکنون در محیط‌ها قرار دارند، برای یکی از نسخه‌های اصلی (major) آینده برنامه‌ریزی شده است. هنوز توصیه نمی‌کنیم از متدهای سرور فاصله بگیرید. برای شناسایی استفاده خود، این موارد را در تنظیمات Vite خود تنظیم کنید: ```ts future: { removeServerModuleGraph: 'warn', removeServerTransformRequest: 'warn', } ``` ::: ## انگیزه در Vite نسخه ۵ و قبل از آن، یک سرور توسعه Vite همیشه دو محیط (`client` و `ssr`) داشت. گراف `server.moduleGraph` شامل ماژول‌هایی از هر دو این محیط‌ها به‌صورت مخلوط بود. گره‌ها از طریق لیست‌های `clientImportedModules` و `ssrImportedModules` به هم متصل بودند (اما یک لیست واحد `importers` برای هر کدام نگهداری می‌شد). یک ماژول تبدیل‌شده با یک `id` و یک مقدار بولین `ssr` نمایش داده می‌شد. این مقدار بولین باید به APIها منتقل می‌شد، به عنوان مثال `server.moduleGraph.getModuleByUrl(url, ssr)` و `server.transformRequest(url, { ssr })`. در Vite نسخه ۶، اکنون امکان ایجاد هر تعداد محیط سفارشی (`client`، `ssr`، `edge` و غیره) وجود دارد. یک مقدار بولین ساده `ssr` دیگر کافی نیست. به جای تغییر APIها به شکلی مانند `server.transformRequest(url, { environment })`، این متدها را به نمونه محیط منتقل کردیم تا بتوان آن‌ها را بدون نیاز به سرور توسعه Vite فراخوانی کرد. ## راهنمای مهاجرت * `server.moduleGraph` -> [`environment.moduleGraph`](/guide/api-environment-instances#separate-module-graphs) * `server.transformRequest(url, ssr)` -> `environment.transformRequest(url)` * `server.warmupRequest(url, ssr)` -> `environment.warmupRequest(url)` --- --- url: /plugins.md --- # پلاگین‌ها :::tip نکته Vite هدف دارد پشتیبانی پیش‌فرض از الگوهای رایج توسعه وب را ارائه دهد. قبل از جست‌وجو برای یافتن پلاگین‌های Vite یا پلاگین‌های سازگار با Rollup، [راهنمای ویژگی‌ها](../guide/features.md) را بررسی کنید. بسیاری از مواردی که در پروژه‌های Rollup نیاز به استفاده از پلاگین دارند، در Vite به‌صورت پیش‌فرض پوشش داده شده‌اند. ::: برای کسب اطلاعات بیشتر درباره نحوه استفاده از پلاگین‌ها، بخش [استفاده از پلاگین‌ها](../guide/using-plugins) را مطالعه کنید. ## Official Plugins ### [@vitejs/plugin-vue](https://github.com/vitejs/vite-plugin-vue/tree/main/packages/plugin-vue) * از Vue 3 Single File Components پشتیبانی می‌کند . ### [@vitejs/plugin-vue-jsx](https://github.com/vitejs/vite-plugin-vue/tree/main/packages/plugin-vue-jsx) * از Vue 3 JSX پشتیبانی می‌کند (با استفاده از [تبدیل اختصاصی Babel](https://github.com/vuejs/jsx-next)). ### [@vitejs/plugin-vue2](https://github.com/vitejs/vite-plugin-vue2) * از Vue 2.7 Single File Components پشتیبانی می‌کند. ### [@vitejs/plugin-vue2-jsx](https://github.com/vitejs/vite-plugin-vue2-jsx) * از Vue 2.7 JSX پشتیبانی می‌کند (با استفاده از [تبدیل اختصاصی Babel](https://github.com/vuejs/jsx-vue2/)). ### [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/tree/main/packages/plugin-react) * با استفاده از esbuild و Babeldدر نهایت HMR سریع و پکیجی کم‌حجم ارائه می‌دهد، در حالی که امکان استفاده از پایپ‌لاین تبدیل Babel را هم دارد. در فرآیند ساخت (build)، اگر پلاگین‌های اضافی Babel اضافه نشوند، تنها از esbuild استفاده می‌شود. ### [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) * در مرحله توسعه، Babel با SWC جایگزین می‌شود. در مرحله بیلد پرواکشن، اگر از پلاگین‌ها استفاده شود، SWC+esbuild به کار گرفته می‌شوند و در غیر این صورت فقط از esbuild استفاده می‌شود. برای پروژه‌های بزرگ که به اکسننشن های غیراستاندارد React نیازی ندارند، زمان راه‌اندازی اولیه (cold start) و تعویض ماژول‌ها در حین توسعه (HMR) می‌توانند به طور قابل توجهی سریع‌تر باشند. ### [@vitejs/plugin-legacy](https://github.com/vitejs/vite/tree/main/packages/plugin-legacy) * پشتیبانی از مرورگرهای قدیمی برای بیلد پرواکشن فراهم می‌کند. ## Community Plugins [awesome-vite](https://github.com/vitejs/awesome-vite#plugins) را بررسی کنید - شما همچنین می‌توانید یک درخواست PR ارسال کنید تا پلاگین‌های خود را در آنجا اضافه کنید. ## Rollup Plugins [پلاگین‌های Vite](../guide/api-plugin) توسعه یافته از اینترفیس پلاگین‌های Rollup هستند. برای جزئیات بیشتر، به بخش [سازگاری با پلاگین‌های Rollup](../guide/api-plugin#rollup-plugin-compatibility) مراجعه کنید. --- --- url: /changes/shared-plugins-during-build.md --- # پلاگین‌های مشترک در زمان Build ::: tip بازخورد نظرات خود را در [بازخورد درباره Environment API](https://github.com/vitejs/vite/discussions/16358) با ما به اشتراک بگذارید. ::: برای اطلاعات بیشتر به بخش [Shared plugins during build](/guide/api-environment-plugins.md#shared-plugins-during-build) مراجعه کنید. **دامنه تأثیر:** نویسندگان افزونه‌های Vite ::: warning تغییر پیش‌فرض در آینده ویژگی `builder.sharedConfigBuild` برای اولین بار در نسخه `v6.0` معرفی شد. می‌توانید آن را روی `true` تنظیم کنید تا بررسی کنید افزونه‌هایتان با پیکربندی مشترک چگونه کار می‌کنند. ما به دنبال بازخورد هستیم تا پس از آمادگی اکوسیستم افزونه‌ها، این مقدار پیش‌فرض را در نسخه‌ای اصلی از Vite تغییر دهیم. ::: ## انگیزه هماهنگ کردن مسیر پلاگین‌ها در محیط توسعه و ساخت. ## راهنمای مهاجرت برای اینکه بتوانید پلاگین‌ها را در محیط‌های مختلف به اشتراک بگذارید، وضعیت پلاگین باید بر اساس محیط جاری کلیدگذاری شود. پلاگینی به شکل زیر تعداد ماژول‌های تبدیل‌شده در همه محیط‌ها را محاسبه می‌کند. ```js function CountTransformedModulesPlugin() { let transformedModules return { name: 'count-transformed-modules', buildStart() { transformedModules = 0 }, transform(id) { transformedModules++ }, buildEnd() { console.log(transformedModules) }, } } ``` اگر به جای آن بخواهیم تعداد ماژول‌های تبدیل‌شده را برای هر محیط شمارش کنیم، باید یک Map نگه داریم: ```js function PerEnvironmentCountTransformedModulesPlugin() { const state = new Map() return { name: 'count-transformed-modules', perEnvironmentStartEndDuringDev: true, buildStart() { state.set(this.environment, { count: 0 }) } transform(id) { state.get(this.environment).count++ }, buildEnd() { console.log(this.environment.name, state.get(this.environment).count) } } } ``` برای ساده‌سازی این الگو، Vite یک ابزار کمکی به نام `perEnvironmentState` را اکسپورت می‌کند: ```js function PerEnvironmentCountTransformedModulesPlugin() { const state = perEnvironmentState<{ count: number }>(() => ({ count: 0 })) return { name: 'count-transformed-modules', perEnvironmentStartEndDuringDev: true, buildStart() { state(this).count = 0 } transform(id) { state(this).count++ }, buildEnd() { console.log(this.environment.name, state(this).count) } } } ``` --- --- url: /guide/dep-pre-bundling.md --- # پیش‌بسته‌بندی(پیش‌باندل) وابستگی زمانی‌که شما `vite` را برای اولین بار اجرا می‌کنید Vite وابستگی‌های پروژه شما را قبل از لود لوکال سایت شما، پیش‌بسته‌بندی می‌کند. این فرایند به صورت پیشفرض، اتوماتیک و شفاف انجام می‌شود. ## چرایی این چیزی‌است که در Vite "پیش‌بسته‌بندی وابستگی" می‌نامیم. این فرایند دو هدف دارد: 1. **سازگاری CommonJS and UMD:** در زمان توسعه، در حالت Vite dev تمام کدها به شکل ماژول native ESM آماده می‌شوند. پس Vite باید وابستگی‌هایی که به شکل CommonJs یا UMD هستند را ابتدا به ESM تبدیل کند. زمانی که Vite دارد وابستگی‌های CommonJsای را تبدیل می‌کند، آنالیز هوشمندانه‌ی import را اجرا می‌کند تا importهای نامگذاری شده‌ی ماژول‌های CommonJS همانطور که انتظار می‌رود بتوانند کار کنند حتی اگر export ها به صورت داینامیک نسبت داده شده باشند (مانند React): ```js // مطابق انتظار کار می‌کند import React, { useState } from 'react' ``` 2. **بازدهی:** Vite وابستگی‌های ESM با ماژول‌های داخلی بسیار را تبدیل به یک ماژول می‌کند تا بازدهی‌ لودهای بعدی صفحه را بهبود دهد. بعضی از پکیج‌ها، ماژول‌های ES خود را به شکل چندین فایل جداگانه که یکدیگر را import کرده‌اند بیلد کرده و همراه خود می‌آورند. برای مثال، [`lodash-es` بیش از ۶۰۰ ماژول داخلی دارد](https://unpkg.com/browse/lodash-es/)! وقتی ما این کار را می‌کنیم`import { debounce } from 'lodash-es'‎`، مرورگر بیش از ۶۰۰ درخواست HTTP را همزمان ارسال می‌کند! حتی با وجود اینکه سرور مشکلی با هندل کردن آنها ندارد، تعداد زیاد درخواست‌ها باعث ازدحام در سمت مرورگر می‌شود که همین امر باعث کندتر لود شدن صفحه به شکل قابل‌ ملاحظه‌ای می‌گردد. به جای این، با پیش‌بسته‌بندیِ `lodash-es` در یک ماژول حالا ما تنها به یک HTTP درخواست نیاز داریم! ::: tip نکته پیش‌بسته‌بندی وابستگی فقط در حالت توسعه(development) اعمال می‌شود و از `esbuild` برای تبدیل وابستگی‌ها به ESM استفاده می‌شود. در حالت production به جای آن از ‎`@rollup/plugin-commonjs` استفاده می‌شود. ::: ## یافتن خودکار وابستگی اگر کشی موجود نباشد، Vite کد شما را می‌کاود و به صورت اتوماتیک وابستگی‌های importها را پیدا می‌کند(مانند "bare imports" که انتظار می‌رود از `node_modules` خوانده شود) و از این importهای پیدا شده به عنوان نقاط ورودی پیش‌بسته‌بندی استفاده کند. فرایند پیش‌بسته‌بندی از `esbuild` استفاده می‌کند پس معمولا بسیار سریع است. بعد از شروع به‌کار سرور، اگر یک وابستگی import جدید مشاهده شود که در کش موجود نیست، Vite دوباره فرایند پیش‌بسته‌بندی وابستگی را اجرا کرده و در صورت نیاز صفحه را مجددا لود می‌کند. ## مخزن یکپارچه (Monorepos) و وابستگی‌های مرتبط(Linked Dependencies) در یک مخزن یکپارچه، یک وابستگی ممکن است به یک پکیج در همان مخزن مرتبط باشد. Vite به صورت خودکار وابستگی‌هایی که از `node_modules` فراخوانی نمی‌شوند را شناسایی کرده و با آن وابستگی مانند یک سورس کد عمل می‌کند. این کار تلاشی برای بسته‌بندی کردن آن وابستگی مرتبط نیست بلکه آنالیز لیست وابستگی‌ِ آن وابستگی مرتبط است. گرچه، این امر نیازمند این است که وابستگی مرتبط به صورت ESM export شده باشد. اگر به این شکل نبود شما می‌توانید وابستگی را در تنظیماتتان به [`optimizeDeps.include`](/config/dep-optimization-options.md#optimizedeps-include)و[`build.commonjsOptions.include`](/config/build-options.md#build-commonjsoptions) اضافه کنید. ```js twoslash [vite.config.js] import { defineConfig } from 'vite' // ---cut--- export default defineConfig({ optimizeDeps: { include: ['linked-dep'], }, build: { commonjsOptions: { include: [/linked-dep/, /node_modules/], }, }, }) ``` هنگامی که تغییراتی در وابستگیِ مرتبط می‌دهید، dev server را با قابلیت دستور ‎`--force` ریست کنید تا تغییرات اعمال شوند. ## اختصاصی‌کردن رفتار روش‌های پیشفرض کشف وابستگی ممکن است همیشه مطلوب نباشند. در مواردی که شما مشخصا می‌خواهید وابستگی ها را از لیست include/exclude کنید از [`optimizeDeps` config options](/config/dep-optimization-options.md) استفاده کنید. یک مورد مرسوم برای `optimizeDeps.include` یا `optimizeDeps.exclude` زمانی است که شما یک importای دارید که مستقیما قابل کشف در سورس کد نیست. برای مثال، شاید آن import در نتیجه‌ی تغییر پلاگینی بوجود آمده است. این به این معنا است که Vite قادر به یافتن آن import در اسکن اولیه نخواهد بود - بلکه تنها زمانی که توسط مرورگر درخواست داده شود و تغییر(transformed) پیدا کند قابل مشاهده می‌گردد. این موضوع باعث می‌شود سرور بلافاصله بعد از شروع، دوباره بسته‌بندی را انجام دهد. هر دو حالت `include` و `exclude` می‌توانند برای این هدف مورد استفاده قرار گیرند. اگر وابستگی بزرگ باشد (به همراه ماژول‌های داخلی بسیاری) یا CommonJS باشد، پس شما باید آنرا include کنید؛ اگر وابستگی کوچک است و همین حالا هم ماژول ESM معتبری است، می‌توانید آنرا exclude کنید و اجازه دهید که مرورگر مستقیما آن‌ را لود کند. همچنین شما می‌توانید esbuild را بیشتر نیز با [قابلیت`optimizeDeps.esbuildOptions`](/config/dep-optimization-options.md#optimizedeps-esbuildoptions) سفارشی‌سازی کنید. برای مثال، اضافه کردن یک پلاگین esbuild برای هندل کردن فایل‌های مخصوص در وابستگی‌ها یا تغییر [build `target`](https://esbuild.github.io/api/#target). ## کش‌کردن ### کش فایل‌سیستم (File System) Vite وابستگی‌های پیش‌بسته‌بندی را در `node_modules/.vite` کش می‌کند. Vite اینکه نیاز به اجرای مجدد مرحله پیش‌بسته‌بندی هست یا نه را بر اساس چند منبع تشخیص می‌دهد: * محتوای package manager lockfile مثل: `package-lock.json`, `yarn.lock`, `pnpm-lock.yaml` یا `bun.lockb`. * زمان تغییر پوشه patches. * فیلدهای مرتبط در `vite.config.js`، در صورت وجود. * مقدار `NODE_ENV`. مرحله پیش‌بسته‌بندی تنها زمانی نیاز به اجرای مجدد دارد که یکی از موارد بالا تغییر کرده باشد. اگر به دلایلی می‌خواهید که Vite را مجبور به انجام پیش‌بسته‌بندی وابستگی‌ کنید، یا می‌توانید سرور dev را با گزینه دستور ‎`--force` اجرا کنید یا اینکه فایل `node_modules/.vite` پوشه کش را به صورت دستی پاک کنید. ### کش مرورگر {#browser-cache} فراخوانی درخواست‌های وابستگی به خوبی با هدرهای HTTP `max-age=31536000,immutable` کش می‌شوند تا بازدهی بارگیری مجدد صفحه در حالت dev افزایش پیدا کند. وقتی که کش شدند، این درخواست‌ها دیگر هرگز به سرور dev ارسال نمی‌شوند. آنها زمانی که یک نسخه دیگر نصب شود به صورت خودکار با اضافه شدن ورژن کوئری (version query) ، غیرمعتبر می‌شوند(همانند آنچه که در لاک‌فایل پکیج منیجر شما دیده می‌شود). اگر می‌خواهید که وابستگی‌های خود را با تغییرات لوکال دیباگ کنید می‌توانید: 1. غیرفعال کردن موقت کش در تب Network در devtools مرورگر خود. 2. اجرای مجدد سرور dev با علامت ‎`--force` برای پیش‌بسته‌بندی مجدد وابستگی‌ها. 3. بارگیری مجدد صفحه. --- --- url: /config.md --- # پیکربندی Vite هنگام اجرای `vite` از خط فرمان، Vite به‌طور خودکار تلاش می‌کند تا فایلی با نام `vite.config.js` را در [ریشه پروژه](/guide/#index-html-و-ریشه-root-پروژه) پیدا کند (پسوندهای دیگر JS و TS نیز پشتیبانی می‌شوند). ساده‌ترین فایل پیکربندی به این شکل است: ```js [vite.config.js] export default { // گزینه‌های پیکربندی } ``` Vite از سینتکس ماژول‌های ES در فایل پیکربندی پشتیبانی می‌کند، حتی اگر پروژه از ESM بومی Node استفاده نکند، مثلاً `"type": "module"` در `package.json` نباشد. در این حالت، فایل پیکربندی پیش از بارگذاری به‌طور خودکار پیش‌پردازش می‌شود. همچنین می‌توانید با استفاده از گزینه `config--` در CLI، فایل پیکربندی خاصی را مشخص کنید (فایل با توجه به مسیر کاری جاری (`cwd`) تفسیر و خوانده می‌شود): ```bash vite --config my-config.js ``` ::: tip بارگذاری پیکربندی به‌طور پیش‌فرض، Vite از `esbuild` برای باندل کردن پیکربندی به یک فایل موقت و بارگذاری آن استفاده می‌کند. این ممکن است در مونوریپوها هنگام ایمپورت فایل‌های TypeScript مشکل ایجاد کند. اگر با این روش مشکلی داشتید، می‌توانید با `configLoader runner--` از [module runner](/guide/api-environment-runtimes.html#modulerunner) استفاده کنید که فایل موقتی ایجاد نمی‌کند و فایل‌ها را در لحظه تبدیل می‌کند. توجه کنید که module runner از CJS در فایل‌های پیکربندی پشتیبانی نمی‌کند، اما پکیج‌های خارجی CJS باید به‌طور عادی کار کنند. همچنین، اگر از محیطی استفاده می‌کنید که TypeScript را پشتیبانی می‌کند (مثلاً `node --experimental-strip-types`) یا فقط جاوااسکریپت ساده می‌نویسید، می‌توانید با `configLoader native--` از ران‌تایم بومی محیط برای بارگذاری فایل پیکربندی استفاده کنید. توجه داشته باشید که تغییرات در ماژول‌های ایمپورت‌شده توسط فایل پیکربندی تشخیص داده نمی‌شوند و سرور Vite به‌طور خودکار ری‌استارت نمی‌شود. ::: ## هوشمندی پیکربندی (Intellisense) از آنجا که Vite با تایپ‌های TypeScript ارائه می‌شود، می‌توانید از هوشمندی IDE خود با استفاده از نکات تایپ jsdoc بهره ببرید: ```js /** @type {import('vite').UserConfig} */ export default { // ... } ``` یا می‌توانید از تابع کمکی `defineConfig` استفاده کنید که بدون نیاز به توضیحات jsdoc، هوشمندی را فراهم می‌کند: ```js import { defineConfig } from 'vite' export default defineConfig({ // ... }) ``` Vite همچنین از فایل‌های پیکربندی TypeScript پشتیبانی می‌کند. می‌توانید از `vite.config.ts` با تابع کمکی `defineConfig` یا عملگر `satisfies` استفاده کنید: ```ts import type { UserConfig } from 'vite' export default { // ... } satisfies UserConfig ``` ## پیکربندی شرطی اگر پیکربندی نیاز به تعیین شرطی گزینه‌ها بر اساس دستور (`serve` یا `build`)، [حالت](/guide/env-and-mode#modes) استفاده‌شده، ساخت SSR (`isSsrBuild`) یا پیش‌نمایش ساخت (`isPreview`) داشته باشد، می‌تواند به جای آبجکت، یک تابع صادر کند: ```js twoslash import { defineConfig } from 'vite' // ---cut--- export default defineConfig(({ command, mode, isSsrBuild, isPreview }) => { if (command === 'serve') { return { // پیکربندی خاص توسعه } } else { // command === 'build' return { // پیکربندی خاص ساخت } } }) ``` در API Vite، مقدار `command` در طول توسعه `serve` است (همچنین در CLI نام‌های مستعار [`vite`](/guide/cli#vite) و `vite dev` و `vite serve` را داریم) و هنگام ساخت برای تولید، `build` است ([`vite build`](/guide/cli#vite-build)). `isSsrBuild` و `isPreview` پرچم‌های اختیاری اضافی برای تمایز نوع دستورهای `build` و `serve` هستند. برخی ابزارهایی که پیکربندی Vite را بارگذاری می‌کنند ممکن است از این پرچم‌ها پشتیبانی نکنند و به جای آن `undefined` ارسال کنند. بنابراین توصیه می‌شود از مقایسه صریح با `true` و `false` استفاده کنید. ## پیکربندی ناهمگام اگر پیکربندی نیاز به فراخوانی توابع ناهمگام داشته باشد، می‌تواند یک تابع ناهمگام صادر کند. این تابع ناهمگام همچنین می‌تواند از طریق `defineConfig` برای پشتیبانی بهتر از هوشمندی منتقل شود: ```js twoslash import { defineConfig } from 'vite' // ---cut--- export default defineConfig(async ({ command, mode }) => { const data = await asyncFunction() return { // vite پیکربندی } }) ``` ## استفاده از متغیرهای محیطی در پیکربندی متغیرهای محیطی به‌طور معمول از `process.env` قابل دسترسی هستند. توجه داشته باشید که Vite به‌طور پیش‌فرض فایل‌های `‎.env` را بارگذاری نمی‌کند، زیرا فایل‌های قابل بارگذاری تنها پس از ارزیابی پیکربندی Vite مشخص می‌شوند، مثلاً گزینه‌های `root` و `envDir` بر رفتار بارگذاری تأثیر می‌گذارند. با این حال، می‌توانید از تابع کمکی صادرشده `loadEnv` برای بارگذاری فایل `env.` خاص در صورت نیاز استفاده کنید. ```js twoslash import { defineConfig, loadEnv } from 'vite' export default defineConfig(({ mode }) => { // .در دایرکتوری کاری جاری بارگذاری کن `mode` را بر اساس env فایل // ،`VITE_` ها بدون توجه به پیشوند env برای بارگذاری همه // .پارامتر سوم را به '' تنظیم کن const env = loadEnv(mode, process.cwd(), '') return { // پیکربندی vite define: { __APP_ENV__: JSON.stringify(env.APP_ENV), }, } }) ``` ## دیباگ کردن فایل پیکربندی در VS Code وقتی از رفتار پیش‌فرض `configLoader bundle--`استفاده می‌شه، Vite فایل پیکربندی موقتی تولیدشده را در پوشه `node_modules/.vite-temp` می‌نویسد و هنگام تنظیم نقاط توقف برای دیباگ در فایل پیکربندی Vite، خطای "فایل پیدا نشد" رخ می‌دهد. برای رفع این مشکل، پیکربندی زیر را به `vscode/settings.json.` اضافه کنید: ```json { "debug.javascript.terminalOptions": { "resolveSourceMapLocations": [ "${workspaceFolder}/**", "!**/node_modules/**", "**/node_modules/.vite-temp/**" ] } } ``` --- --- url: /changes.md --- # تغییرات اساسی لیست تغییرات اساسی در Vite شامل منسوخ شدن API‌ها، حذف‌ها، و تغییرات. بیشتر تغییرات زیر را می‌توانید با استفاده از [گزینه `آینده`](/config/shared-options.html#future) در تنظیمات Vite خود به‌صورت اختیاری فعال کنید. ## برنامه‌ریزی شده این تغییرات برای نسخه اصلی بعدی Vite برنامه‌ریزی شده‌اند. هشدارهای مربوط به منسوخ شدن یا استفاده در صورت امکان شما را راهنمایی خواهند کرد و ما با نویسندگان فریم‌ورک‌ها، افزونه‌ها و کاربران در ارتباط هستیم تا این تغییرات را اعمال کنیم. * *هنوز هیچ تغییر برنامه‌ریزی شده‌ای وجود ندارد* ## قابل توجه این تغییرات در حال بررسی هستند و اغلب شامل API‌های آزمایشی می‌باشند که هدف آن‌ها بهبود الگوهای استفاده فعلی است. از آنجا که تمامی تغییرات در اینجا ذکر نشده‌اند، لطفاً برای مشاهده لیست کامل به [Experimental Label in Vite GitHub Discussions](https://github.com/vitejs/vite/discussions/categories/feedback?discussions_q=label%3Aexperimental+category%3AFeedback) مراجعه کنید. ما توصیه نمی‌کنیم که هنوز به این API‌ها سوئیچ کنید. این API‌ها در Vite گنجانده شده‌اند تا به ما در جمع‌آوری بازخورد کمک کنند. لطفاً این پیشنهادها را بررسی کنید و در بحث‌های مرتبط در GitHub به ما اطلاع دهید که چگونه در موارد استفاده شما کار می‌کنند. * [`this.environment` در هوک‌ها](/changes/this-environment-in-hooks) * [هوک پلاگین `hotUpdate`برای HMR](/changes/hotupdate-hook) * [انتقال به API‌های مخصوص هر محیط](/changes/per-environment-apis) * [SSR با استفاده از `ModuleRunner` API](/changes/ssr-using-modulerunner) * [اشتراک‌گذاری پلاگین‌ها در حین ساخت (build)](/changes/shared-plugins-during-build) ## گذشته تغییرات زیر اعمال شده یا لغو گردیده‌اند. این تغییرات در نسخه اصلی فعلی دیگر معتبر یا قابل استفاده نیستند. * *هنوز هیچ تغییر گذشته‌ای وجود ندارد* --- --- url: /guide/why.md --- # چرا Vite ## مشکلات قبل از اینکه ماژول‌های ES در مرورگرها در دسترس باشند، توسعه‌دهندگان مکانیزم بومی برای نوشتن جاوااسکریپت به صورت ماژولار نداشتند. به همین دلیل همه با مفهوم "bundling (بسته بندی)" آشنا هستیم: استفاده از ابزارهایی که ماژول‌های سورس کد ما را جستجو، پردازش و در فایل‌هایی که می‌توانند در مرورگر اجرا شوند، ادغام می‌کنند. با گذشت زمان، ما ابزارهایی مانند [Rollup](https://rollupjs.org) ، [webpack](https://webpack.js.org/) و [Parcel](https://parceljs.org/) را دیده‌ایم که تجربه توسعه برای توسعه‌دهندگان فرانت‌اند را بهبود بخشیده‌اند. با این حال، همان‌طور که برنامه‌های بلندپروازانه‌تری می‌سازیم، میزان جاوااسکریپتی که با آن سروکار داریم نیز به طور چشمگیری افزایش می‌یابد. در پروژه‌های بزرگ مقیاس، داشتن هزاران ماژول غیرمعمول نیست. ما در حال رسیدن به یک گلوگاه عملکردی برای ابزارهای مبتنی بر جاوااسکریپت هستیم: اغلب ممکن است زمان انتظار غیرمعقولی (گاهی تا چند دقیقه!) طول بکشد تا یک سرور توسعه راه‌اندازی شود، و حتی با جایگزینی سریع ماژول (HMR)، ویرایش فایل‌ها ممکن است چند ثانیه طول بکشد تا در مرورگر منعکس شوند. این بازخورد کند می‌تواند به شدت بر بهره‌وری و رضایت توسعه‌دهندگان تأثیر بگذارد. Vite هدف دارد این مشکلات را با بهره‌گیری از پیشرفت‌های جدید در اکوسیستم حل کند: در دسترس بودن ماژول‌های ES بومی در مرورگر، و ظهور ابزارهای جاوااسکریپت نوشته‌شده با زبان‌هایی که به باینری کامپایل می‌شوند. ### شروع کُند سرور وقتی سرور توسعه به صورت cold-starting اجرا می‌شود، قبل از اینکه برنامه بتواند ارائه شود باید یک راه‌اندازی ساخت مبتنی بر باندلر به طور پیش‌فرض تمام برنامه شما را پیمایش و بیلد کند. Vite در زمان شروع، سرور توسعه را با تقسیم ماژول‌های یک برنامه به دو دسته بهبود می‌بخشد: **وابستگی‌ها** و **سورس کد**. * **وابستگی‌ها** عمدتاً جاوااسکریپت ساده هستند که در طول توسعه تغییر نمی‌کنند. برخی وابستگی‌های بزرگ (مثلاً کتابخانه‌های کامپوننت با صدها ماژول) نیز دارای پردازش بسیار گران هستند. وابستگی‌ها ممکن است در انواع مختلف فرمت‌های ماژول (مثلاً ESM یا CommonJS) ارائه شوند. Vite با استفاده از [esbuild](https://esbuild.github.io/) می‌تواند [وابستگی‌ها را پیش‌باندل](./dep-pre-bundling.md) کند. esbuild با زبان Go نوشته شده و وابستگی‌ها را 10 تا 100 برابر سریع‌تر از باندلرهای مبتنی بر جاوااسکریپت پیش‌باندل می‌کند. * **سورس کد** اغلب حاوی جاوااسکریپت غیر‌ساده‌ای است که نیاز به تبدیل دارد (مثلاً JSX ، CSS یا کامپوننت‌های Vue/Svelte)، و بسیار زیاد ویرایش می‌شود. همچنین، نیازی نیست تمام سورس کد به طور همزمان بارگذاری شود (مثلاً با تقسیم کد مبتنی بر مسیر). Vite سورس کد را از طریق [ESM بومی](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules) ارائه می‌دهد. این اساساً اجازه می‌دهد تا مرورگر بخشی از کار یک باندلر را انجام دهد: Vite فقط نیاز دارد سورس کد را بر اساس تقاضا تبدیل کند و سرویس دهد، همان‌طور که مرورگر آن را درخواست می‌کند. کدی که پشت ایمپورت داینامیک شرطی است تنها در صورت استفاده واقعی در صفحه فعلی پردازش می‌شود. ### به‌روزرسانی‌های کند وقتی یک فایل در یک راه‌اندازی ساخت مبتنی بر باندلر ویرایش می‌شود، بازسازی کل باندل به یک دلیل واضح ناکارآمد است: سرعت به‌روزرسانی به صورت خطی با اندازه برنامه کاهش می‌یابد. در برخی باندلرها، سرور توسعه باندلینگ را در حافظه (memory) انجام می‌دهد تا فقط نیاز باشد بخشی از گراف ماژول خود را هنگام تغییر یک فایل نامعتبر کند، اما همچنان نیاز است کل باندل را بازسازی کرده و صفحه وب را دوباره بارگذاری کند. بازسازی باندل می‌تواند پرهزینه باشد، و بارگذاری مجدد صفحه وضعیت فعلی برنامه را از بین می‌برد. به همین دلیل است که برخی باندلرها از جایگزینی سریع ماژول (Hot Module Replacement (HMR)) پشتیبانی می‌کنند: اجازه می‌دهد یک ماژول بدون تأثیر بر بقیه صفحه به صورت "سریع" جایگزین شود. این به طور قابل توجهی تجربه توسعه (DX) را بهبود می‌بخشد - با این حال، در عمل ما متوجه شده‌ایم که حتی سرعت به‌روزرسانی HMR نیز با رشد اندازه برنامه به طور قابل توجهی کاهش می‌یابد. در Vite، عملیات HMR بر روی ESM بومی انجام می‌شود. وقتی فایلی ویرایش می‌شود، Vite تنها زنجیره‌ی بین ماژول ویرایش‌شده و نزدیک‌ترین مرز HMR را نامعتبر می‌کند (که معمولاً فقط خود ماژول است). این فرآیند باعث می‌شود که به‌روزرسانی‌های HMR، بدون توجه به اندازه‌ی برنامه، همواره با سرعت بالا انجام شوند. Vite همچنین از هدرهای HTTP برای سرعت بخشیدن به بارگذاری مجدد کامل صفحه استفاده می‌کند (باز هم، اجازه دهید مرورگر کار بیشتری برای ما انجام دهد): درخواست‌های ماژول سورس کد به‌صورت مشروط با وضعیت `304 Not Modified` انجام می‌شوند، در حالی که ماژول‌های وابستگی با هدر `Cache-Control: max-age=31536000, immutable` به‌شدت کش می‌شوند. به همین دلیل، پس از یک‌بار کش شدن، دیگر نیازی به ارسال درخواست به سرور ندارند. پس از تجربه سرعت Vite، بعید است که بخواهید دوباره به توسعه مبتنی بر باندل برگردید. ## چرا برای پروداکشن باندل کنیم حتی با وجود اینکه ESM بومی اکنون به طور گسترده پشتیبانی می‌شود، به دلیل رفت‌و‌آمدهای اضافی شبکه که توسط ایمپورت‌های تودرتو ایجاد می‌شود، ارسال ESM بدون باندل در محیط پروداکشن همچنان ناکارآمد است (حتی با HTTP/2) . برای دستیابی به بهترین عملکرد بارگذاری در پروداکشن، همچنان بهتر است کد خود را با استفاده از tree-shaking، بارگذاری تنبل (lazy-loading) و تقسیم‌بندی بخش‌های مشترک (برای بهبود کش) باندل کنید. اطمینان از خروجی بهینه و سازگاری رفتاری بین سرور توسعه و بیلد ساخته شده برای پروداکشن آسان نیست. به همین دلیل است که Vite با یک [کامند بیلد](./build.md) از پیش پیکربندی‌شده ارائه می‌شود که بسیاری از [بهینه‌سازی‌های عملکرد](./features.md#build-optimizations) را به صورت پیش‌فرض در خود دارد. ## چرا با esbuild باندل نکنیم؟ در حالی که Vite از esbuild برای [پیش‌باندل کردن برخی وابستگی‌ها در زمان توسعه](./dep-pre-bundling.md) استفاده می‌کند، Vite از esbuild به عنوان یک باندلر برای بیلدهای پروداکشن استفاده نمی‌کند. API فعلی پلاگین Vite با استفاده از `esbuild` به عنوان باندلر سازگار نیست. با وجود اینکه `esbuild` سریع‌تر است، پذیرش API انعطاف‌پذیر پلاگین و زیرساخت Rollup توسط Vite به موفقیت آن در اکوسیستم کمک بزرگی کرده است. در حال حاضر، ما معتقدیم که Rollup توازن بهتری بین عملکرد و انعطاف‌پذیری ارائه می‌دهد. Rollup همچنین در حال کار بر روی بهبودهای عملکردی است، [تغییر پارسر خود به SWC در نسخه 4](https://github.com/rollup/rollup/pull/5073) و تلاش‌هایی در حال انجام است برای ساخت نسخه‌ای به زبان Rust از Rollup به نام Rolldown. زمانی که Rolldown آماده شود، می‌تواند هر دو Rollup و esbuild را در Vite جایگزین کند، عملکرد بیلد را به طرز قابل توجهی بهبود بخشد و ناسازگاری‌های بین توسعه و بیلد را از بین ببرد. می‌توانید [سخنرانی کلیدی Evan You در ViteConf 2023 برای جزئیات بیشتر تماشا کنید](https://youtu.be/hrdwQHoAp0M). ## Vite چگونه با سایر ابزارهای ساخت بدون باندل مقایسه می‌شود؟ ابزار [WMR](https://github.com/preactjs/wmr) که توسط تیم Preact توسعه داده شده بود، هدفش ارائه مجموعه‌ای از قابلیت‌های مشابه با Vite بود. رابط افزونه‌ی مشترک Vite برای محیط توسعه و ساخت (build) از WMR الهام گرفته است. اما WMR دیگر پشتیبانی نمی‌شود و تیم Preact اکنون استفاده از Vite همراه با بسته‌ی [‎@preactjs/preset-vite](https://github.com/preactjs/preset-vite) را پیشنهاد می‌دهد. [Snowpack](https://www.snowpack.dev/) نیز یک سرور توسعه ESM بومی بدون باندل بود که بسیار شبیه به Vite بود. پیش‌باندل کردن وابستگی‌های Vite نیز از Snowpack v1 (اکنون [`esinstall`](https://github.com/snowpackjs/snowpack/tree/main/esinstall)) الهام گرفته شده است. Snowpack دیگر نگهداری نمی‌شود. تیم Snowpack اکنون روی [Astro](https://astro.build/) کار می‌کند، یک سازنده سایت استاتیک که از Vite قدرت گرفته است. پروژه [‎@web/dev-server](https://modern-web.dev/docs/dev-server/overview/) (که قبلاً با نام `es-dev-server` شناخته می‌شد) یکی از پروژه‌های عالی است که معماری سرور مبتنی بر Koa در Vite نسخه 1.0 از آن الهام گرفته شده است. پروژه‌ی جامع `‎@web` به‌صورت فعال نگهداری می‌شود و شامل ابزارهای فوق‌العاده‌ی دیگری نیز هست که می‌توانند برای کاربران Vite مفید باشند. --- --- url: /guide/static-deploy.md --- # دیپلوی یک سایت استاتیک راهنماهای زیر بر اساس برخی فرضیات مشترک نوشته شده‌اند: * شما از مسیر پیش‌فرض برای خروجی فایل‌های بیلد شده (`dist`) استفاده می‌کنید. این مسیر را می‌توانید با استفاده از گزینه `build.outDir` تغییر دهید. اگر مسیر خروجی را تغییر داده‌اید، می‌توانید دستورالعمل‌های زیر را بر اساس نیاز خود تنظیم و تطبیق دهید. * شما از npm به عنوان پکیج منیجر استفاده می‌کنید. اگر از Yarn یا دیگر پکیج منیجرها استفاده می‌کنید، می‌توانید از دستورات معادل برای اجرای اسکریپت‌ها استفاده کنید. * Vite به عنوان یک وابستگی توسعه (dev dependency) به صورت محلی در پروژه شما نصب شده است و شما اسکریپت‌های npm زیر را در پروژه خود تنظیم کرده‌اید: ```json [package.json] { "scripts": { "build": "vite build", "preview": "vite preview" } } ``` توجه داشته باشید که دستور `vite preview` فقط برای پیش‌نمایش فایل‌های build شده به کار می‌رود و نمی‌توان از آن به عنوان یک پروداکشن سرور استفاده کرد. ::: tip توجه این راهنماها دستورالعمل‌هایی برای انجام پیاده سازی استاتیک (Static Deployment) سایت شما با استفاده از Vite ارائه می‌دهند. Vite همچنین از رندرینگ سمت سرور (Server-Side Rendering یا SSR) پشتیبانی می‌کند. SSR به فریم‌ورک‌های فرانت‌اندی اشاره دارد که قابلیت اجرای یک برنامه یکسان در Node.js، پیش‌رندر کردن آن به HTML و در نهایت Hydrate آن در سمت کلاینت را فراهم می‌کنند. برای یادگیری بیشتر درباره این قابلیت، به [راهنمای SSR](./ssr) مراجعه کنید. از طرف دیگر، اگر به دنبال ادغام با فریم‌ورک‌های سنتی سمت سرور هستید، به جای آن [راهنمای ادغام با backend](./backend-integration) را بررسی کنید. ::: ## بیلد برنامه می‌توانید از دستور `npm run build` برای بیلد برنامه استفاده کنید. ```bash $ npm run build ``` به طور پیش‌فرض، خروجی بیلد در پوشه `dist` ذخیره می‌شود. شما می‌توانید این پوشه `dist` را روی هر پلتفرم دلخواهی که مدنظر دارید، دیپلوی کنید. ### تست برنامه به صورت لوکال پس از بیلد کردن برنامه، می‌توانید آن را به صورت لوکال با استفاده از دستور `npm run preview` تست کنید. ```bash $ npm run preview ``` دستور `vite preview`،این دستور یک وب سرور استاتیک لوکال راه‌اندازی می‌کند که فایل‌های داخل پوشه `dist` را در آدرس `http://localhost:4173` سرو می‌دهد. این روشی ساده برای بررسی این است که production build در محیط لوکال شما به درستی نمایش داده می‌شود. می‌توانید پورت سرور را با استفاده از فلگ `‎--port` به عنوان آرگومان تنظیم کنید. ```json [package.json] { "scripts": { "preview": "vite preview --port 8080" } } ``` اکنون دستور `preview` سرور را در آدرس `http://localhost:8080` راه‌اندازی می‌کند. ## GitHub Pages 1. مقدار `base` را در فایل `vite.config.js` به درستی تنظیم کنید. * اگر قصد دارید پروژه را در `https://.github.io/‎` یا روی یک دامنه سفارشی از طریق GitHub Pages (مثلاً `www.example.com`) مستقر کنید، `base` را روی `'/'` تنظیم کنید. همچنین می‌توانید `base` را از تنظیمات حذف کنید، زیرا به طور پیش‌فرض مقدار آن `'/'` است. * اگر قصد دارید پروژه را در `https://.github.io//‎` مستقر کنید (مثلاً اگر مخزن شما در آدرس `https://github.com//‎` قرار دارد)، `base` را روی `'//'` تنظیم کنید. 2. به بخش تنظیمات GitHub Pages در صفحه تنظیمات مخزن بروید و منبع استقرار را به عنوان **GitHub Actions** انتخاب کنید. این کار شما را به ایجاد یک workflow هدایت می‌کند که پروژه شما را بیلد و مستقر می‌کند. یک workflow نمونه که وابستگی‌ها را نصب کرده و با استفاده از npm پروژه را بیلد می‌کند، ارائه شده است: <<< ./static-deploy-github-pages.yaml#content ## GitLab Pages و GitLab CI 1. مقدار `base` را در فایل `vite.config.js` به درستی تنظیم کنید. * اگر قصد دارید پروژه خود را در آدرس `‎https://.gitlab.io/‎` دیپلوی کنید، می‌توانید `base` را نادیده بگیرید، زیرا به طور پیش‌فرض مقدار آن `'/'` است. * اگر قصد دارید پروژه خود را در آدرس `https://.gitlab.io//‎` دیپلوی کنید (مثلاً اگر مخزن شما در آدرس `https://gitlab.com//‎` قرار دارد)، باید `base` را به `'//'` تنظیم کنید. 2. در root پروژه خود، یک فایل با نام `‎.gitlab-ci.yml` ایجاد کنید و محتوای زیر را به آن اضافه کنید. این فایل باعث می‌شود هر زمان که تغییراتی در محتوای پروژه ایجاد کنید، به‌طور خودکار سایت شما ساخته شده (build) و دیپلوی شود: ```yaml [.gitlab-ci.yml] image: node:lts pages: stage: deploy cache: key: files: - package-lock.json prefix: npm paths: - node_modules/ script: - npm install - npm run build - cp -a dist/. public/ artifacts: paths: - public rules: - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH ``` ## Netlify ### Netlify CLI 1. [Netlify CLI](https://cli.netlify.com/) را نصب کنید. 2. با استفاده از دستور `ntl init` یک سایت جدید ایجاد کنید. 3. با دستور `ntl deploy` دیپلوی کنید. ```bash # Install the Netlify CLI $ npm install -g netlify-cli # Create a new site in Netlify $ ntl init # Deploy to a unique preview URL $ ntl deploy ``` CLI Netlify یک preview URL در اختیار شما قرار می‌دهد تا بتوانید آن را بررسی کنید. زمانی که آماده هستید به مرحله production بروید، از فلگ `prod` استفاده کنید: ```bash # Deploy the site into production $ ntl deploy --prod ``` ### Netlify با Git 1. کد خود را به یک ریپازیتوری Git (مثل GitHub، GitLab، BitBucket، Azure DevOps) پوش کنید. 2. [پروژه را به Netlify ایمپورت کنید](https://app.netlify.com/start). 3. برنچ (Branch)، پوشه خروجی و متغیرهای محیطی را در صورت نیاز تنظیم کنید. 4. روی **Deploy** کلیک کنید. 5. اپلیکیشن Vite شما دیپلوی شد! بعد از اینکه پروژه شما ایمپورت و دیپلوی شد، تمام پوش‌های بعدی به برنچ‌های غیر از برنچ اصلی (Production Branch) و همچنین Pull Request‌ها، [Preview Deployments](https://docs.netlify.com/site-deploys/deploy-previews/) ایجاد می‌کنند و تمام تغییرات اعمال شده روی برنچ اصلی (معمولاً “main”) منجر به یک [Production Deployment](https://docs.netlify.com/site-deploys/overview/#definitions) خواهند شد. ## Vercel ### Vercel CLI 1. [Vercel CLI](https://vercel.com/cli) را نصب کنید و دستور `vercel` را اجرا کنید تا دیپلوی انجام شود. 2. Vercel تشخیص می‌دهد که شما از Vite استفاده می‌کنید و تنظیمات صحیح را برای دیپلوی فعال می‌کند. 3. اپلیکیشن شما دیپلوی شد! (مثال: [vite-vue-template.vercel.app](https://vite-vue-template.vercel.app/)) ```bash $ npm i -g vercel $ vercel init vite Vercel CLI > Success! Initialized "vite" example in ~/your-folder. - To deploy, `cd vite` and run `vercel`. ``` ### Vercel برای Git 1. کد خود را به ریپازیتوری Git (مثل GitHub، GitLab، Bitbucket) پوش کنید. 2. [پروژه Vite خود را به Vercel ایمپورت کنید](https://vercel.com/new). 3. Vercel تشخیص می‌دهد که شما از Vite استفاده می‌کنید و تنظیمات صحیح را برای دیپلوی فعال می‌کند. 4. اپلیکیشن شما دیپلوی شد! (مثال: [vite-vue-template.vercel.app](https://vite-vue-template.vercel.app/)) بعد از اینکه پروژه شما ایمپورت و دیپلوی شد، تمام پوش‌های بعدی به برنچ‌ها، [Preview Deployments](https://vercel.com/docs/concepts/deployments/environments#preview) ایجاد می‌کنند و تمام تغییرات اعمال شده روی برنچ اصلی (معمولاً “main”) منجر به یک [Production Deployment](https://vercel.com/docs/concepts/deployments/environments#production) خواهند شد. برای اطلاعات بیشتر، می‌توانید درباره [Git Integration در Vercel](https://vercel.com/docs/concepts/git) مطالعه کنید. ## Cloudflare Pages ### Cloudflare Pages از طریق Wrangler 1. [Wrangler CLI](https://developers.cloudflare.com/workers/wrangler/get-started/) را نصب کنید. 2. Wrangler را با حساب Cloudflare خود احراز هویت کنید. برای این کار از دستور `wrangler login` استفاده کنید. 3. دستور build خود را اجرا کنید. 4. با استفاده از دستور `npx wrangler pages deploy dist` دیپلوی کنید. ```bash # Install Wrangler CLI $ npm install -g wrangler # Login to Cloudflare account from CLI $ wrangler login # Run your build command $ npm run build # Create new deployment $ npx wrangler pages deploy dist ``` بعد از آپلود فایل‌ها، Wrangler یک preview URL در اختیار شما قرار می‌دهد تا سایت خود را بررسی کنید. وقتی وارد داشبورد Cloudflare Pages می‌شوید، پروژه جدید خود را مشاهده خواهید کرد. ### Cloudflare Pages با Git 1. کد خود را به ریپازیتوری Git (مثل GitHub، GitLab) پوش کنید. 2. وارد داشبورد Cloudflare شوید و حساب خود را در **Account Home** > **Pages** انتخاب کنید. 3. **Create a new Project** و گزینه **Connect Git** را انتخاب کنید. 4. پروژه Git که می‌خواهید دیپلوی کنید را انتخاب کرده و روی **Begin setup** کلیک کنید. 5. در تنظیمات build، پریست فریم‌ورک مربوطه را بسته به فریم‌ورک Vite انتخاب‌شده تنظیم کنید. 6. سپس ذخیره کرده و دیپلوی کنید! 7. اپلیکیشن شما دیپلوی شد! (مثال: `https://.pages.dev/‎`) بعد از اینکه پروژه شما ایمپورت و دیپلوی شد، تمام پوش‌های بعدی به برنچ‌ها، [Preview Deployments](https://developers.cloudflare.com/pages/platform/preview-deployments/) ایجاد می‌کنند (مگر اینکه در [branch build controls](https://developers.cloudflare.com/pages/platform/branch-build-controls/) غیرفعال شده باشد). تمام تغییرات در برنچ اصلی (معمولاً “main”) منجر به یک Production Deployment خواهد شد. همچنین می‌توانید دامنه‌های سفارشی اضافه کنید و تنظیمات build سفارشی را در Pages مدیریت کنید. برای اطلاعات بیشتر، [Cloudflare Pages Git Integration](https://developers.cloudflare.com/pages/get-started/#manage-your-site) را مطالعه کنید. ## Google Firebase 1. مطمئن شوید که [firebase-tools](https://www.npmjs.com/package/firebase-tools) نصب شده است. 2. در root پروژه خود فایل‌های `firebase.json` و `.firebaserc` را با محتوای زیر ایجاد کنید: ```json [firebase.json] { "hosting": { "public": "dist", "ignore": [], "rewrites": [ { "source": "**", "destination": "/index.html" } ] } } ``` ```js [.firebaserc] { "projects": { "default": "" } } ``` 3. بعد از اجرای دستور `npm run build`، با استفاده از دستور `firebase deploy` دیپلوی کنید. ## Surge ابتدا اگر surge را نصب نکرده‌اید، آن را نصب کنید. دستور `npm run build` را اجرا کنید. برای دیپلوی روی surge، دستور `surge dist` را وارد کنید. همچنین می‌توانید با استفاده از دستور `surge dist yourdomain.com` روی یک دامنه سفارشی دیپلوی کنید. ## Azure Static Web Apps می‌توانید اپلیکیشن Vite خود را به سرعت با سرویس [Static Web Apps](https://aka.ms/staticwebapps) مایکروسافت Azure دیپلوی کنید. برای این کار به موارد زیر نیاز دارید: * یک حساب Azure و کلید اشتراک. می‌توانید [یک حساب Azure رایگان ایجاد کنید](https://azure.microsoft.com/free). * کد اپلیکیشن شما که به [GitHub](https://github.com) پوش شده باشد. * [افزونه SWA](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-azurestaticwebapps) در [Visual Studio Code](https://code.visualstudio.com). افزونه را در VS Code نصب کنید و به root پروژه خود بروید. افزونه Static Web Apps را باز کنید، به Azure وارد شوید و روی علامت '+' کلیک کنید تا یک Static Web App جدید ایجاد کنید. از شما خواسته می‌شود که کلید اشتراک مورد نظر خود را انتخاب کنید. مراحل راهنمای ارائه‌شده توسط افزونه را دنبال کنید تا نام اپلیکیشن خود را انتخاب کنید، پریست فریم‌ورک را تنظیم کنید و مسیر root اپلیکیشن (معمولاً `/`) و مسیر فایل‌های ساخته‌شده (`‎/dist`) را مشخص کنید. راهنما اجرا می‌شود و یک GitHub Action در ریپازیتوری شما در پوشه `‎.github` ایجاد می‌کند. این Action برای دیپلوی اپلیکیشن شما کار می‌کند (پیشرفت آن را در تب Actions ریپازیتوری خود مشاهده کنید) و پس از تکمیل موفقیت‌آمیز، می‌توانید اپلیکیشن خود را در آدرس ارائه‌شده در پنجره پیشرفت افزونه مشاهده کنید. برای این کار، روی دکمه 'Browse Website' که پس از اجرای GitHub Action ظاهر می‌شود، کلیک کنید. ## Render می‌توانید اپلیکیشن Vite خود را به عنوان یک سایت استاتیک در [Render](https://render.com/) دیپلوی کنید. 1. یک [حساب Render](https://dashboard.render.com/register) ایجاد کنید. 2. در [داشبورد](https://dashboard.render.com/)، روی دکمه **New** کلیک کنید و **Static Site** را انتخاب کنید. 3. حساب GitHub/GitLab خود را متصل کنید یا از یک ریپازیتوری عمومی استفاده کنید. 4. یک نام پروژه و برنچ مشخص کنید. * **Build Command**: `npm install && npm run build` * **Publish Directory**: `dist` 5. روی **Create Static Site** کلیک کنید. اپلیکیشن شما باید در `https://.onrender.com/‎` دیپلوی شود. به طور پیش‌فرض، هر کامیت جدیدی که به برنچ مشخص‌شده پوش شود، به طور خودکار یک دیپلوی جدید ایجاد می‌کند. [Auto-Deploy](https://render.com/docs/deploys#toggling-auto-deploy-for-a-service) را می‌توان در تنظیمات پروژه پیکربندی کرد. همچنین می‌توانید یک [دامنه سفارشی](https://render.com/docs/custom-domains) به پروژه خود اضافه کنید. ## Flightcontrol سایت استاتیک خود را با استفاده از [Flightcontrol](https://www.flightcontrol.dev/?ref=docs-vite) و با دنبال کردن این [دستورالعمل‌ها](https://www.flightcontrol.dev/docs/reference/examples/vite?ref=docs-vite) دیپلوی کنید. ## Kinsta Static Site Hosting سایت استاتیک خود را با استفاده از [Kinsta](https://kinsta.com/static-site-hosting/) و با دنبال کردن این [دستورالعمل‌ها](https://kinsta.com/docs/react-vite-example/) دیپلوی کنید. ## xmit Static Site Hosting سایت استاتیک خود را با استفاده از [xmit](https://xmit.co) و با دنبال کردن این [راهنما](https://xmit.dev/posts/vite-quickstart/) دیپلوی کنید. --- --- url: /guide/api-javascript.md --- # ‌رابط برنامه‌نویسی اپلیکیشن (API) جاوا اسکریپت رابط‌های جاوااسکریپت در Vite به‌طور کامل تایپ شده‌اند (typed) و توصیه می‌شود برای بهره‌مندی از قابلیت‌هایی مانند IntelliSense و اعتبارسنجی (validation)، از TypeScript استفاده کنید یا بررسی تایپ (type checking) را در VS Code برای فایل‌های JS فعال نمایید. ## تابع `createServer` **امضای تایپ:** ```ts async function createServer(inlineConfig?: InlineConfig): Promise ``` **مثال استفاده:** ```ts twoslash import { fileURLToPath } from 'node:url' import { createServer } from 'vite' const __dirname = fileURLToPath(new URL('.', import.meta.url)) const server = await createServer({ // any valid user config options, plus `mode` and `configFile` configFile: false, root: __dirname, server: { port: 1337, }, }) await server.listen() server.printUrls() server.bindCLIShortcuts({ print: true }) ``` :::tip نکته هنگامی که از `createServer` و `build` در یک پردازش (process) مشترک Node.js استفاده می‌کنید، هر دو تابع برای عملکرد صحیح به مقدار `process.env.NODE_ENV` وابسته هستند، که این مقدار نیز به گزینه‌ی پیکربندی `mode` بستگی دارد. برای جلوگیری از بروز رفتارهای متناقض، مقدار `process.env.NODE_ENV` یا `mode` در هر دو API را روی `development` تنظیم کنید. در غیر این صورت، می‌توانید با ایجاد یک پردازش فرزند (child process) این دو API را به‌صورت جداگانه اجرا کنید. ::: :::tip نکته زمانی که از [حالت میدلور (middleware mode)](/config/server-options.html#server-middlewaremode) به همراه [پیکربندی پراکسی برای WebSocket](/config/server-options.html#server-proxy) استفاده می‌کنید، باید **سرور HTTP والد** (parent http server) را در گزینه‌ی `middlewareMode` مشخص کنید تا پروکسی به‌درستی به سرور متصل شود. ```ts twoslash import http from 'http' import { createServer } from 'vite' const parentServer = http.createServer() // or express, koa, etc. const vite = await createServer({ server: { // Enable middleware mode middlewareMode: { // Provide the parent http server for proxy WebSocket server: parentServer, }, proxy: { '/ws': { target: 'ws://localhost:3000', // Proxying WebSocket ws: true, }, }, }, }) // @noErrors: 2339 parentServer.use(vite.middlewares) ``` ## کانفیگ درون خطی (`InlineConfig`) رابط `InlineConfig` نسخه‌ای توسعه‌یافته از `UserConfig` است که چند ویژگی اضافی دارد: * `کانفیگ‌فایل (configFile)`: مشخص می‌کند از کدام فایل پیکربندی استفاده شود. اگر تنظیم نشود، Vite به‌صورت خودکار به‌دنبال فایل پیکربندی در ریشه پروژه می‌گردد. برای غیرفعال کردن این رفتار، مقدار آن را `false` قرار دهید. ## پیکربندی درست شده (`ResolvedConfig`) رابط `ResolvedConfig` شامل تمام ویژگی‌های `UserConfig` است، با این تفاوت که بیشتر این ویژگی‌ها **به‌طور کامل resolve شده و مقداردهی شده‌اند** (undefined نیستند). همچنین شامل ابزارهایی (utilities) مانند موارد زیر نیز می‌شود: * `تابع config.assetsInclude`: تابعی برای بررسی اینکه آیا یک `id` به‌عنوان یک asset در نظر گرفته می‌شود یا نه. * `تابع config.logger`: آبجکت لاگر داخلی Vite (برای ثبت و نمایش پیام‌ها و گزارش‌ها در طول اجرا). ## اینتر فیس `ViteDevServer` ```ts interface ViteDevServer { /** * The resolved Vite config object. */ config: ResolvedConfig /** * A connect app instance * - Can be used to attach custom middlewares to the dev server. * - Can also be used as the handler function of a custom http server * or as a middleware in any connect-style Node.js frameworks. * * https://github.com/senchalabs/connect#use-middleware */ middlewares: Connect.Server /** * Native Node http server instance. * Will be null in middleware mode. */ httpServer: http.Server | null /** * Chokidar watcher instance. If `config.server.watch` is set to `null`, * it will not watch any files and calling `add` or `unwatch` will have no effect. * https://github.com/paulmillr/chokidar/tree/3.6.0#api */ watcher: FSWatcher /** * Web socket server with `send(payload)` method. */ ws: WebSocketServer /** * Rollup plugin container that can run plugin hooks on a given file. */ pluginContainer: PluginContainer /** * Module graph that tracks the import relationships, url to file mapping * and hmr state. */ moduleGraph: ModuleGraph /** * The resolved urls Vite prints on the CLI (URL-encoded). Returns `null` * in middleware mode or if the server is not listening on any port. */ resolvedUrls: ResolvedServerUrls | null /** * Programmatically resolve, load and transform a URL and get the result * without going through the http request pipeline. */ transformRequest( url: string, options?: TransformOptions, ): Promise /** * Apply Vite built-in HTML transforms and any plugin HTML transforms. */ transformIndexHtml( url: string, html: string, originalUrl?: string, ): Promise /** * Load a given URL as an instantiated module for SSR. */ ssrLoadModule( url: string, options?: { fixStacktrace?: boolean }, ): Promise> /** * Fix ssr error stacktrace. */ ssrFixStacktrace(e: Error): void /** * Triggers HMR for a module in the module graph. You can use the `server.moduleGraph` * API to retrieve the module to be reloaded. If `hmr` is false, this is a no-op. */ reloadModule(module: ModuleNode): Promise /** * Start the server. */ listen(port?: number, isRestart?: boolean): Promise /** * Restart the server. * * @param forceOptimize - force the optimizer to re-bundle, same as --force cli flag */ restart(forceOptimize?: boolean): Promise /** * Stop the server. */ close(): Promise /** * Bind CLI shortcuts */ bindCLIShortcuts(options?: BindCLIShortcutsOptions): void /** * Calling `await server.waitForRequestsIdle(id)` will wait until all static imports * are processed. If called from a load or transform plugin hook, the id needs to be * passed as a parameter to avoid deadlocks. Calling this function after the first * static imports section of the module graph has been processed will resolve immediately. * @experimental */ waitForRequestsIdle: (ignoredId?: string) => Promise } ``` :::info اطلاعات تابع `waitForRequestsIdle` به‌عنوان یک راه‌حل اضطراری طراحی شده است تا تجربه توسعه (DX) را برای ویژگی‌هایی که نمی‌توانند با طبیعت درخواستی سرور توسعه Vite پیاده‌سازی شوند، بهبود بخشد. این تابع می‌تواند در زمان راه‌اندازی توسط ابزارهایی مانند Tailwind استفاده شود تا تولید کلاس‌های CSS اپلیکیشن تا زمانی که کد اپلیکیشن دیده نشده است به تعویق بیفتد و از تغییرات ناگهانی استایل جلوگیری کند. زمانی که این تابع در یک هوک بارگذاری یا تبدیل استفاده می‌شود و از سرور پیش‌فرض HTTP1 استفاده می‌شود، یکی از شش کانال HTTP مسدود خواهد شد تا زمانی که سرور تمام ایمپورت‌های استاتیک را پردازش کند. بهینه‌ساز وابستگی‌های Vite هم‌اکنون از این تابع برای جلوگیری از بارگذاری مجدد کامل صفحه در صورت کمبود وابستگی‌ها استفاده می‌کند و بارگذاری وابستگی‌های پیش‌بسته را تا زمانی که تمام وابستگی‌های ایمپورتی از منابع ایمپورت استاتیک جمع‌آوری شوند، به تأخیر می‌اندازد. ممکن است Vite در نسخه‌های اصلی آینده استراتژی متفاوتی اتخاذ کند و به‌طور پیش‌فرض مقدار `optimizeDeps.crawlUntilStaticImports: false` را تنظیم کند تا از تاثیر منفی عملکرد در برنامه‌های بزرگ در هنگام راه‌اندازی سرد (cold start) جلوگیری کند. ::: ## `build` **امضای تایپ:** ```ts async function build( inlineConfig?: InlineConfig, ): Promise ``` **مثال استفاده:** ```ts twoslash [vite.config.js] import path from 'node:path' import { fileURLToPath } from 'node:url' import { build } from 'vite' const __dirname = fileURLToPath(new URL('.', import.meta.url)) await build({ root: path.resolve(__dirname, './project'), base: '/foo/', build: { rollupOptions: { // ... }, }, }) ``` ## `preview` **امضای تایپ:** ```ts async function preview(inlineConfig?: InlineConfig): Promise ``` **مثال استفاده:** ```ts twoslash import { preview } from 'vite' const previewServer = await preview({ // any valid user config options, plus `mode` and `configFile` preview: { port: 8080, open: true, }, }) previewServer.printUrls() previewServer.bindCLIShortcuts({ print: true }) ``` ## اینترفیس `PreviewServer` ```ts interface PreviewServer { /** * The resolved vite config object */ config: ResolvedConfig /** * A connect app instance. * - Can be used to attach custom middlewares to the preview server. * - Can also be used as the handler function of a custom http server * or as a middleware in any connect-style Node.js frameworks * * https://github.com/senchalabs/connect#use-middleware */ middlewares: Connect.Server /** * native Node http server instance */ httpServer: http.Server /** * The resolved urls Vite prints on the CLI (URL-encoded). Returns `null` * if the server is not listening on any port. */ resolvedUrls: ResolvedServerUrls | null /** * Print server urls */ printUrls(): void /** * Bind CLI shortcuts */ bindCLIShortcuts(options?: BindCLIShortcutsOptions): void } ``` ## تابع `resolveConfig` **امضای تایپ:** ```ts async function resolveConfig( inlineConfig: InlineConfig, command: 'build' | 'serve', defaultMode = 'development', defaultNodeEnv = 'development', isPreview = false, ): Promise ``` مقدار `command` در حالت توسعه (dev) و پیش‌نمایش (preview)، برابر با `serve` است و در حالت ساخت (build)، برابر با `build` می‌باشد. ## تابع `mergeConfig` **امضای تایپ:** ```ts function mergeConfig( defaults: Record, overrides: Record, isRoot = true, ): Record ``` دو پیکربندی Vite را به‌طور عمیق با هم ترکیب می‌کند. مقدار `isRoot` نمایانگر سطحی است که در پیکربندی Vite در حال ترکیب آن هستید. به‌عنوان مثال، اگر در حال ترکیب دو گزینه `build` هستید، مقدار آن را `false` قرار دهید. :::tip نکته تابع `mergeConfig` تنها پیکربندی‌هایی که به‌صورت آبجکت هستند را می‌پذیرد. اگر پیکربندی شما به‌صورت تابع callback است، باید آن را قبل از ارسال به `mergeConfig` فراخوانی کنید. شما می‌توانید از تابع‌کمکی `defineConfig` برای ترکیب یک پیکربندی به‌صورت callback با یک پیکربندی دیگر استفاده کنید: ```ts twoslash import { defineConfig, mergeConfig, type UserConfigFnObject, type UserConfig, } from 'vite' declare const configAsCallback: UserConfigFnObject declare const configAsObject: UserConfig // ---cut--- export default defineConfig((configEnv) => mergeConfig(configAsCallback(configEnv), configAsObject), ) ``` ::: ## تابع `searchForWorkspaceRoot` **امضای تایپ:** ```ts function searchForWorkspaceRoot( current: string, root = searchForPackageRoot(current), ): string ``` **مرتبط:** [server.fs.allow](/config/server-options.md#server-fs-allow) ریشه‌ی workspace احتمالی را جست‌وجو کن اگر شرایط زیر برقرار باشند؛ در غیر این صورت، به مقدار `root` بازمی‌گردد: * وجود فیلد `workspaces` در فایل `package.json` * وجود یکی از فایل‌های زیر: * فایل `lerna.json` * و یا فایل `pnpm-workspace.yaml` ## تابع `loadEnv` **امضای تایپ:** ```ts function loadEnv( mode: string, envDir: string, prefixes: string | string[] = 'VITE_', ): Record ``` **مرتبط:** [`‎.env` Files](./env-and-mode.md#env-files) فایل‌های `‎.env` را درون دایرکتوری `envDir` بارگذاری کنید؛ به‌طور پیش‌فرض، فقط متغیرهای محیطی با پیشوند `VITE_‎` بارگذاری می‌شوند، مگر اینکه پیشوندها (`prefixes`) تغییر داده شوند. ## تابع `normalizePath` **امضای تایپ:** ```ts function normalizePath(id: string): string ``` **مرتبط:** [Path Normalization](./api-plugin.md#path-normalization) مسیر (path) را نرمال‌سازی می‌کند تا بین افزونه‌های Vite قابل تعامل باشد. ## `transformWithEsbuild` **امضای تایپ:** ```ts async function transformWithEsbuild( code: string, filename: string, options?: EsbuildTransformOptions, inMap?: object, ): Promise ``` تبدیل JavaScript یا TypeScript با استفاده از esbuild. این کار برای افزونه‌هایی مفید است که ترجیح می‌دهند با فرآیند تبدیل داخلی Vite هماهنگ باشند. ## تابع `loadConfigFromFile` **امضای تایپ:** ```ts async function loadConfigFromFile( configEnv: ConfigEnv, configFile?: string, configRoot: string = process.cwd(), logLevel?: LogLevel, customLogger?: Logger, ): Promise<{ path: string config: UserConfig dependencies: string[] } | null> ``` بارگذاری دستی فایل تنظیمات Vite با استفاده از esbuild. ## تابع `preprocessCSS` * **آزمایشی:** [Give Feedback](https://github.com/vitejs/vite/discussions/13815) **امضای تایپ:** ```ts async function preprocessCSS( code: string, filename: string, config: ResolvedConfig, ): Promise interface PreprocessCSSResult { code: string map?: SourceMapInput modules?: Record deps?: Set } ``` پیش‌پردازش فایل‌های `‎.css` ، `‎.scss` ، `‎.sass` ، `‎.less` ، `‎.styl` و `‎.stylus` به CSS ساده، به‌طوری‌که بتوان آن را در مرورگرها استفاده کرد یا توسط ابزارهای دیگر پردازش کرد. مشابه [پشتیبانی داخلی از پیش‌پردازش CSS](/guide/features#css-pre-processors)، پیش‌پردازش‌گر مربوطه باید به‌صورت جداگانه نصب شده باشد تا قابل استفاده باشد. پیش‌پردازش‌گر مورد استفاده از روی پسوند `filename` تشخیص داده می‌شود. اگر نام فایل با `‎.module.{ext}` به پایان برسد، به‌عنوان یک [CSS module](https://github.com/css-modules/css-modules) در نظر گرفته می‌شود و نتیجه‌ی بازگشتی شامل یک آبجکت `modules` خواهد بود که نام کلاس‌های اصلی را به نام‌های تبدیل‌شده نگاشت می‌کند. توجه داشته باشید که پیش‌پردازش، آدرس‌های موجود در `url()‎` یا `image-set()‎` را resolve نخواهد کرد. --- --- url: /guide/cli.md --- # رابط خط فرمان - CLI ## سرور توسعه ### `vite` برای اجرای سرور توسعه Vite در دایرکتوری فعلی، دستور `‌vite‌` را اجرا کنید. همچنین `‌vite dev`‌ و `‌vite serve‌` به‌عنوان نام‌های مستعار آن عمل می‌کنند. #### استفاده ```bash vite [root] ``` #### گزینه‌ها | گزینه‌ها | | | --------------------------- | -------------------------------------------------------------------------------------------------------------- | | `‎--host [host]` | مشخص کردن نام هاست (`string`) | | `‎--port ‎` | مشخص کردن پورت (`number`) | | `‎--open [path]‎` | باز کردن مرورگر در هنگام راه‌اندازی (`boolean \| string`) | | `‎--cors` | فعال کردن CORS ؛(`boolean`) | | `‎--strictPort` | خروج اگر پورت مشخص شده در حال استفاده باشد (`boolean`) | | `‎--force` | مجبور کردن بهینه‌ساز برای نادیده گرفتن کش و دوباره بیلد گرفتن (`boolean`) | | `‎-c, --config ‎` | استفاده از فایل کانفیگ مشخص شده (`string`) | | `‎--base ‎` | مسیر پایه public (پیش‌فرض: `/`) (`string`) | | `‎-l, --logLevel ‎` | info | warn | error | silent (`string`) | | `‎--clearScreen` | اجازه/غیرفعال کردن پاک کردن صفحه هنگام لاگ‌گیری (`boolean`) | | `‎--configLoader ‎` | استفاده از `bundle` برای باندل کردن کانفیگ با esbuild یا `runner` (آزمایشی) برای پردازش آن به صورت آنی، یا از `native` (آزمایشی) برای بارگذاری با استفاده از runtime بومی (پیش‌فرض: `bundle`) | | `‎--profile` | شروع inspector داخلی Node.js ؛([گلوگاه‌های عملکرد](/guide/troubleshooting#performance-bottlenecks)) | | `‎-d, --debug [feat]‎` | نمایش لاگ‌های دیباگ (`string \| boolean`) | | `‎-f, --filter ‎` | فیلتر کردن لاگ‌های دیباگ (`string`) | | `‎-m, --mode ‎` | تنظیم حالت env ؛(`string`) | | `‎-h, --help` | نمایش گزینه‌های موجود CLI | | `‎-v, --version` | نمایش شماره نسخه | ## بیلد ### `vite build` بیلد برای پروداکشن #### استفاده ```bash vite build [root] ``` #### گزینه‌ها | گزینه‌ها | | | -------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | | `‎--target ‎` | هدف ترنسپایل (پیش‌فرض: `"modules"`) (`string`) | | `‎--outDir ‎` | دایرکتوری خروجی (پیش‌فرض: `dist`) (`string`) | | `‎--assetsDir ‎` | دایرکتوری زیر outDir برای قرار دادن asset ها (پیش‌فرض: `"assets"`) (`string`) | | `‎--assetsInlineLimit ‎` | حد آستانه inline دارایی‌های استاتیک به صورت base64 بر حسب بایت (پیش‌فرض: `4096`) (`number`) | | `‎--ssr [entry]‎` | ورودی مشخص شده برای رندرینگ سمت سرور (SSR) (`string`) | | `‎--sourcemap [output]‎` | خروجی source map برای بیلد (پیش‌فرض: `false`) (`boolean \| "inline" \| "hidden"`) | | `‎--minify [minifier]‎` | فعال/غیرفعال کردن فشرده‌سازی، یا مشخص کردن فشرده‌سازی برای استفاده (پیش‌فرض: `"esbuild"`) (`boolean \| "terser" \| "esbuild"`) | | `‎--manifest [name]‎` | تولید فایل json مانیفست بیلد (`boolean \| string`) | | `‎--ssrManifest [name]‎` | تولید فایل json مانیفست ssr ؛(`boole an \| string`) | | `‎--emptyOutDir‎` | خالی کردن اجباری outDir وقتی که خارج از root است (`boolean`) | | `‎-w, --watch` | اجرای مجدد بیلد هنگام تغییر در فایل‌ها یا ماژول‌ها (`boolean`) | | `‎-c, --config ‎` | استفاده از فایل کانفیگ مشخص شده (`string`) | | `‎--base ‎` | مسیر پایه عمومی (پیش‌فرض: `/`) (`string`) | | `‎-l, --logLevel ‎` | Info | warn | error | silent (`string`) | | `‎--clearScreen` | اجازه/غیرفعال کردن پاک کردن صفحه هنگام لاگ‌گیری (`boolean`) | | `‎--configLoader ‎` | استفاده از `bundle` برای باندل کردن کانفیگ با esbuild یا `runner` (آزمایشی) برای پردازش آن به صورت آنی (پیش‌فرض: `bundle`) | | `‎--profile` | شروع inspector داخلی Node.js ؛([گلوگاه‌های عملکرد](/guide/troubleshooting#performance-bottlenecks)) | | `‎-d, --debug [feat]‎` | نمایش لاگ‌های دیباگ (`string \| boolean`) | | `‎-f, --filter ‎` | فیلتر کردن لاگ‌های دیباگ (`string`) | | `‎-m, --mode ‎` | تنظیم حالت env ؛(`string`) | | `‎-h, --help` | نمایش گزینه‌های موجود CLI | | `‎--app` | بیلد همه محیط‌ها، مشابه `builder: {}` (`boolean`, آزمایشی) | ## سایر موارد ### `vite optimize` پیش‌باندل وابستگی‌ها. **منسوخ شده**: فرآیند پیش‌باندل به‌صورت خودکار اجرا می‌شود و نیازی به فراخوانی ندارد. #### استفاده ```bash vite optimize [root] ``` #### گزینه‌ها | گزینه‌ها | توضیحات | | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | | `‎--force` | مجبور کردن بهینه‌ساز برای نادیده گرفتن کش و دوباره بیلد گرفتن (`boolean`) | | `‎-c, --config ‎` | استفاده از فایل کانفیگ مشخص شده (`string`) | | `‎--base ‎` | مسیر پایه public (پیش‌فرض: `/`) (`string`) | | `‎-l, --logLevel ‎` | Info | warn | error | silent (`string`) | | `‎--clearScreen` | اجازه/غیرفعال کردن پاک کردن صفحه هنگام لاگ‌گیری (`boolean`) | | `‎--configLoader ‎` | استفاده از `bundle` برای باندل کردن کانفیگ با esbuild یا `runner` (آزمایشی) برای پردازش آن به صورت آنی (پیش‌فرض: `bundle`) | | `‎-d, --debug [feat]‎` | نمایش لاگ‌های دیباگ (`string \| boolean`) | | `‎-f, --filter ‎` | فیلتر کردن لاگ‌های دیباگ (`string`) | | `‎-m, --mode ‎` | تنظیم حالت env ؛(`string`) | | `‎-h, --help` | نمایش گزینه‌های موجود CLI | ### `vite preview` پیش‌نمایش محلی بیلد پروداکشن. از این به عنوان سرور پروداکشن استفاده نکنید زیرا برای این منظور طراحی نشده است. #### استفاده ```bash vite preview [root] ``` #### گزینه‌ها | گزینه‌ها | | | --------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | | `‎--host [host]` | مشخص کردن نام هاست (`string`) | | `‎--port ‎` | مشخص کردن پورت (`number`) | | `‎--strictPort` | خروج اگر پورت مشخص شده در حال استفاده باشد (`boolean`) | | `‎--open [path]‎` | باز کردن مرورگر در هنگام راه‌اندازی (`boolean \| string`) | | `‎--outDir ‎` | دایرکتوری خروجی (پیش‌فرض: `dist`) (`string`) | | `‎-c, --config ‎` | استفاده از فایل کانفیگ مشخص شده (`string`) | | `‎--base ‎` | مسیر پایه عمومی (پیش‌فرض: `/`) (`string`) | | `‎-l, --logLevel ‎` | Info | warn | error | silent (`string`) | | `‎--clearScreen` | اجازه/غیرفعال کردن پاک کردن صفحه هنگام لاگ‌گیری (`boolean`) | | `‎--configLoader ‎` | استفاده از `bundle` برای باندل کردن کانفیگ با esbuild یا `runner` (آزمایشی) برای پردازش آن به صورت آنی (پیش‌فرض: `bundle`) | | `‎-d, --debug [feat]‎` | نمایش لاگ‌های دیباگ (`string \| boolean`) | | `‎-f, --filter ‎` | فیلتر کردن لاگ‌های دیباگ (`string`) | | `‎-m, --mode ‎` | تنظیم حالت env ؛(`string`) | | `‎-h, --help` | نمایش گزینه‌های موجود CLI | --- --- url: /guide/ssr.md --- # رندر سمت سرور (SSR) :::tip نکته رندر سمت سرور یا SSR، به قابلیتی در فریم‌ورک‌های فرانت‌اند مانند React ، Preact ، Vue و Svelte گفته می‌شود که اجازه می‌دهد همان اپلیکیشن در محیط Node.js اجرا شود، خروجی HTML تولید کند و سپس در مرورگر کاربر فرآیند "hydration" (فعال‌سازی تعاملی) را انجام دهد. اگر به دنبال یکپارچه‌سازی با فریم‌ورک‌های سنتی سمت سرور هستید، پیشنهاد می‌شود به [راهنمای اتصال به بک‌اند](./backend-integration) مراجعه کنید. این راهنما فرض را بر آن دارد که شما پیش‌تر با مفاهیم SSR در فریم‌ورک انتخابی‌تان آشنا هستید، و تمرکز آن صرفاً بر نکات خاص و کاربردی SSR در Vite است. ::: :::warning API سطح پایین این رابط برنامه‌نویسی (API) مخصوص توسعه‌دهندگان کتابخانه‌ها و سازندگان فریم‌ورک‌هاست، و جزو ابزارهای سطح پایین Vite محسوب می‌شود. اگر هدف شما ساخت یک اپلیکیشن است، توصیه می‌کنیم ابتدا ابزارها و افزونه‌های سطح بالاتری که در [بخش SSR پروژه Awesome Vite](https://github.com/vitejs/awesome-vite#ssr) معرفی شده‌اند را بررسی کنید. با این حال، اپلیکیشن‌های بسیاری تاکنون با تکیه بر همین API بومی و سطح پایین Vite به‌خوبی توسعه یافته‌اند. در حال حاضر، Vite در حال توسعه یک API پیشرفته‌تر برای SSR مبتنی بر [Environment API](https://github.com/vitejs/vite/discussions/16358) است. برای آگاهی بیشتر می‌توانید به لینک مورد نظر مراجعه کنید. ::: ## پروژه‌های نمونه Vite به‌صورت داخلی از رندر سمت سرور (SSR) پشتیبانی می‌کند. پروژه [`create-vite-extra`](https://github.com/bluwy/create-vite-extra) مجموعه‌ای از تنظیمات آماده‌ی SSR را فراهم کرده که می‌توانید به‌عنوان مرجع در این راهنما از آن‌ها استفاده کنید: * [Vanilla (بدون فریم‌ورک خاص)](https://github.com/bluwy/create-vite-extra/tree/master/template-ssr-vanilla) * [Vue](https://github.com/bluwy/create-vite-extra/tree/master/template-ssr-vue) * [React](https://github.com/bluwy/create-vite-extra/tree/master/template-ssr-react) * [Preact](https://github.com/bluwy/create-vite-extra/tree/master/template-ssr-preact) * [Svelte](https://github.com/bluwy/create-vite-extra/tree/master/template-ssr-svelte) * [Solid](https://github.com/bluwy/create-vite-extra/tree/master/template-ssr-solid) همچنین می‌توانید این پروژه‌ها را به‌صورت محلی با اجرای [دستور `create-vite`](./index.md#scaffolding-your-first-vite-project) راه‌اندازی کنید. در بخش انتخاب فریم‌ورک، گزینه‌ی `Others > create-vite-extra` را انتخاب نمایید. ## ساختار پروژه یک اپلیکیشن معمولی با پشتیبانی از SSR (رندر سمت سرور) معمولاً دارای ساختاری مشابه زیر است: ``` - index.html - server.js # سرور اصلی اپلیکیشن - src/ - main.js # کد عمومی برنامه که مستقل از محیط اجراست - entry-client.js # در مرورگر DOM مسئول نصب برنامه روی - entry-server.js # در فریم‌ورک SSR مربوط به API مسئول رندر کردن برنامه در سمت سرور با استفاده از ``` در فایل `index.html` باید به `entry-client.js` اشاره شود و همچنین محلی برای جای‌گذاری خروجی رندر شده توسط سرور در نظر گرفته شود: ```html [index.html]
``` می‌توانید به‌جای `‎‎` از هر نشانه‌گذاری دلخواه دیگری استفاده کنید، فقط کافی است که قابل شناسایی و جایگزینی دقیق باشد. ## منطق شرطی اگه نیاز دارید کد شرطی بر اساس SSR یا کلاینت بنویسید، می‌تونید از این کد استفاده کنید: ```js twoslash import 'vite/client' // ---cut--- if (import.meta.env.SSR) { // ... فقط کد مخصوص سرور } ``` این شرط در زمان build به‌صورت استاتیک جایگزین می‌شود، بنابراین کدهایی که استفاده نمی‌شوند حذف می‌شوند (tree-shaking)، که باعث سبک‌تر شدن باندل نهایی می‌شود. ## راه‌اندازی سرور توسعه (Dev Server) وقتی دارید یک برنامه SSR می‌سازید، احتمالاً می‌خواهید کنترل کامل روی سرور اصلی‌تان داشته باشید و Vite را از محیط پروداکشن (production) جدا کنید. به همین دلیل، توصیه می‌شود از Vite در حالت middleware استفاده کنید. در ادامه یک نمونه با [Express](https://expressjs.com/) آورده شده است: ```js{15-18} twoslash [server.js] import fs from 'node:fs' import path from 'node:path' import { fileURLToPath } from 'node:url' import express from 'express' import { createServer as createViteServer } from 'vite' const __dirname = path.dirname(fileURLToPath(import.meta.url)) async function createServer() { const app = express() // ایجاد کنید و نوع اپلیکیشن را به middleware را در حالت Vite سرور // غیرفعال شود و سرور والد Vite داخلی HTML تنظیم کنید تا سرو 'custom' // بتواند کنترل را به دست بگیرد const vite = await createViteServer({ server: { middlewareMode: true }, appType: 'custom' }) // خودتان express استفاده کنید. اگر از روتر middleware به عنوان vite مربوط connect از نمونه // .استفاده کنید router.use استفاده می‌کنید، باید از (express.Router()) // زمانی که سرور مجدداً راه‌اندازی می‌شود )برای مثال بعد از اینکه کاربر فایل // همچنان همان ارجاع `vite.middlewares` (را تغییر می‌دهد، vite.config.js // .(های تزریق‌شده توسط پلاگین‌ها middleware‌ و Vite با یک پشته داخلی جدید از) خواهد بود // مورد زیر حتی پس از راه‌اندازی مجدد معتبر است app.use(vite.middlewares) app.use('*all', async (req, res) => { // را سرو می‌کنیم - در ادامه به این موضوع خواهیم پرداخت index.html فایل }) app.listen(5173) } createServer() ``` در اینجا `vite` یک نمونه از [ViteDevServer](./api-javascript#vitedevserver) است. `vite.middlewares` یک نمونه از [Connect](https://github.com/senchalabs/connect) است که می‌توان از آن به عنوان یک middleware در هر فریم‌ورک Node.js که با connect سازگار است استفاده کرد. گام بعدی پیاده‌سازی یک handler کلی (`*`) برای سرو HTML رندر شده در سمت سرور است: ```js twoslash [server.js] // @noErrors import fs from 'node:fs' import path from 'node:path' import { fileURLToPath } from 'node:url' /** @type {import('express').Express} */ var app /** @type {import('vite').ViteDevServer} */ var vite // ---cut--- app.use('*all', async (req, res, next) => { const url = req.originalUrl try { // 1. index.html خواندن فایل let template = fs.readFileSync( path.resolve(__dirname, 'index.html'), 'utf-8', ) // 2. مربوط به HMR شامل تزریق کلاینت .Vite توسط HTML اعمال تغییرات // است Vite توسط پلاگین‌های HTML و همچنین انجام ترنسفورم‌های Vite // @vitejs/plugin-react های سراسری از preamble مثل template = await vite.transformIndexHtml(url, template) // 3. را طوری تبدیل می‌کند ESM به‌طور خودکار کد ssrLoadModule .بارگذاری ورودی سمت سرور // مشابه، کارایی در HMR قابل اجرا باشد! نیازی به باندل نیست و با Node.js که در // کردن ماژول‌ها دارد invalidate const { render } = await vite.ssrLoadModule('/src/entry-server.js') // 4. entry-server.js خروجی `render` اپلیکیشن. فرض شده که تابع HTML رندر کردن // فریم‌ورک استفاده می‌کند، SSR های API از // ReactDOMServer.renderToString() مثلاً const appHtml = await render(url) // 5. HTML رندرشده در قالب HTML قرار دادن const html = template.replace(``, () => appHtml) // 6. نهایی به مرورگر HTML ارسال res.status(200).set({ 'Content-Type': 'text/html' }).end(html) } catch (e) { // استک‌ترِیس را اصلاح می‌کند Vite ،در صورت بروز خطا، // تا به کد اصلی شما ارجاع دهد vite.ssrFixStacktrace(e) next(e) } }) ``` اسکریپت `dev` در فایل `package.json` نیز باید طوری تغییر داده شود که به‌جای آن از اسکریپت سرور استفاده کند. ```diff [package.json] "scripts": { - "dev": "vite" + "dev": "node server" } ``` ## ساخت(build) برای محیط پروداکشن برای انتشار یک پروژه SSR در محیط پروداکشن، باید مراحل زیر را انجام دهید: 1. یک بیلد (build) برای کلاینت مثل همیشه تولید شود؛ 2. یک بیلد SSR نیز تولید شود که مستقیماً با `import()‎` بارگذاری شود، تا نیازی به استفاده از `ssrLoadModule` در Vite نباشد. اسکریپت‌های ما در فایل `package.json` به شکل زیر خواهند بود: ```json [package.json] { "scripts": { "dev": "node server", "build:client": "vite build --outDir dist/client", "build:server": "vite build --outDir dist/server --ssr src/entry-server.js" } } ``` به فلگ `‎--ssr` توجه کنید که نشان می‌دهد این بیلد مخصوص SSR است. همچنین باید ورودی (entry) مربوط به SSR را مشخص کند. سپس در فایل `server.js` باید منطق مخصوص پروداکشن را اضافه کنیم با بررسی مقدار `process.env.NODE_ENV`: * به جای خواندن فایل `index.html` از ریشه پروژه، از فایل `dist/client/index.html` به عنوان قالب استفاده کنید، چون این فایل شامل لینک‌های درست برای فایل‌های خروجی کلاینت است. * به جای استفاده از `await vite.ssrLoadModule('/src/entry-server.js')`، از `import('./dist/server/entry-server.js')` استفاده کنید (این فایل خروجی بیلد SSR است). * ساخت و استفاده از سرور توسعه `vite` را فقط در حالت توسعه (dev) انجام دهید و در حالت پروداکشن، از میان افزارهای سرو فایل‌های استاتیک برای ارائه فایل‌ها از مسیر `dist/client` استفاده کنید. برای مشاهده نمونه پیاده‌سازی، به [پروژه‌های نمونه](#example-projects) مراجعه کنید. ## تولید دستورهای پیش بارگذاری دستور `vite build` از فلگ `‎--ssrManifest` پشتیبانی می‌کند که یک فایل به نام `.vite/ssr-manifest.json` در دایرکتوری خروجی بیلد ایجاد می‌کند: ```diff - "build:client": "vite build --outDir dist/client", + "build:client": "vite build --outDir dist/client --ssrManifest", ``` اسکریپت بالا حالا فایل `dist/client/.vite/ssr-manifest.json` را برای بیلد کلاینت تولید می‌کند (بله، مانیفست SSR از بیلد کلاینت ایجاد می‌شود چون هدف این است که ID های ماژول‌ها را به فایل‌های مربوط به کلاینت متصل کنیم). این مانیفست شامل اطلاعاتی است که به ما می‌گوید هر ID ماژول به کدام بخش‌ها (chunks) و فایل‌های مرتبط با آن ماژول در بیلد کلاینت اشاره دارد. برای استفاده از مانیفست، فریمورک‌ها باید روشی فراهم کنند تا ID ماژول‌های کامپوننت‌هایی که در هنگام رندر سرور استفاده شده‌اند، جمع‌آوری شوند. `‎@vitejs/plugin-vue` این قابلیت را به طور پیش‌فرض ارائه می‌دهد و به طور خودکار ID های ماژول کامپوننت‌هایی که در هنگام رندر سرور استفاده شده‌اند را در SSR context مربوط به Vue ثبت می‌کند: ```js [src/entry-server.js] const ctx = {} const html = await vueServerRenderer.renderToString(app, ctx) // ماژول‌هایی است که در طول رندر شدن استفاده شده‌اند ID یک مجموعه از ctx.modules حالا ``` در بخش پروداکشن فایل `server.js`، باید فایل manifest را بخوانیم و آن را به تابع `render` که از `src/entry-server.js` اکسپورت شده، بدهیم. این کار اطلاعات کافی برای تولید دستورهای preload مربوط به فایل‌هایی که در مسیرهای async استفاده شده‌اند را فراهم می‌کند. برای نمونه‌ی کامل، [کد دمو](https://github.com/vitejs/vite-plugin-vue/blob/main/playground/ssr-vue/src/entry-server.js) را ببینید. همچنین می‌توان از این اطلاعات برای ارسال [103 Early Hints](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/103) استفاده کرد. ## پیش‌رندرینگ / تولید سایت ایستا (SSG) اگر مسیرها (routes) و داده‌های مورد نیاز آن‌ها از قبل مشخص باشند، می‌توان آن‌ها را با استفاده از همان منطق SSR در حالت production، به صورت HTML ایستا (static) پیش‌پردازش کرد. این روش را می‌توان نوعی از تولید سایت ایستا یا SSG نیز در نظر گرفت. برای نمونه‌ی عملی، به [اسکریپت pre-render دمو](https://github.com/vitejs/vite-plugin-vue/blob/main/playground/ssr-vue/prerender.js) مراجعه کنید. ## وابستگی‌های خارجی در SSR در حالت SSR، وابستگی‌ها به‌صورت پیش‌فرض از سیستم تبدیل ماژول Vite خارج (externalize) می‌شوند. این کار باعث افزایش سرعت در هر دو زمان توسعه (dev) و ساخت (build) پروژه می‌شود. اگر یک وابستگی نیاز داشته باشد که توسط زنجیره‌ی تبدیل Vite پردازش شود (مثلاً چون از قابلیت‌های Vite به‌صورت مستقیم و بدون تبدیل در آن استفاده شده)، می‌توانید آن را به گزینه‌ی [`ssr.noExternal`](../config/ssr-options.md#ssr-noexternal) اضافه کنید. وابستگی‌هایی که لینک شده‌اند (مثل آن‌هایی که با `npm link` یا در محیط‌های monorepo استفاده شده‌اند)، به‌صورت پیش‌فرض external نمی‌شوند تا Vite بتواند از HMR استفاده کند. اگر نمی‌خواهید این رفتار اتفاق بیفتد (مثلاً برای شبیه‌سازی شرایطی که انگار وابستگی‌ها لینک نشده‌اند) می‌توانید آن‌ها را به گزینه‌ی [`ssr.external`](../config/ssr-options.md#ssr-external) اضافه کنید. :::warning کار با aliasها اگر aliasهایی تعریف کرده‌اید که یک پکیج را به پکیج دیگری هدایت می‌کنند، ممکن است بهتر باشد به‌جای آن، خود پکیج‌های داخل `node_modules` را alias کنید تا قابلیت external شدن آن‌ها در SSR به درستی عمل کند. هر دو ابزار [Yarn](https://classic.yarnpkg.com/en/docs/cli/add/#toc-yarn-add-alias) و [pnpm](https://pnpm.io/aliases/) از alias کردن با پیشوند `npm:‎` پشتیبانی می‌کنند. ::: ## منطق افزونه مخصوص SSR برخی فریم‌ورک‌ها مثل Vue یا Svelte، کامپوننت‌ها را بسته به این‌که برای کلاینت باشند یا SSR، به شکل‌های مختلفی کامپایل می‌کنند. با استفاده از این ویژگی، افزونه‌ها می‌توانند رفتار متفاوتی در حالت SSR نسبت به کلاینت داشته باشند. برای پشتیبانی از این تبدیل‌های شرطی، Vite یک ویژگی اضافی به نام `ssr` را در آبجکت `options` به هوک‌های زیر از افزونه‌ها منتقل می‌کند: * `resolveId` * `load` * `transform` **مثال:** ```js twoslash /** @type {() => import('vite').Plugin} */ // ---cut--- export function mySSRPlugin() { return { name: 'my-ssr', transform(code, id, options) { if (options?.ssr) { // ... SSR انجام تبدیل مخصوص } }, } } ``` آبجکت `options` که در توابع `load` و `transform` استفاده می‌شود، اختیاری است. Rollup در حال حاضر از این آبجکت استفاده نمی‌کند، اما ممکن است در آینده برای افزودن اطلاعات بیشتر به این hookها از آن استفاده شود. :::tip نکته قبل از نسخه 2.7 از Vite، اطلاعات مربوط به SSR به جای اینکه در آبجکت `options` قرار بگیرد، به صورت یک پارامتر جداگانه به توابع پلاگین داده می‌شد. الان بیشتر فریم‌ورک‌ها و پلاگین‌ها به‌روز شده‌اند، ولی ممکن است هنوز در برخی منابع قدیمی نسخه قبلی این روش را ببینید. ::: ## هدف SSR هدف پیش‌فرض برای ساخت SSR، محیط Node است، اما شما همچنین می‌توانید سرور را در یک Web Worker اجرا کنید. نحوه حل ارجاعات پکیج‌ها برای هر پلتفرم متفاوت است. شما می‌توانید هدف را به Web Worker تغییر دهید با تنظیم `ssr.target` به `'webworker'`. ## بسته‌بندی SSR در برخی موارد مانند رانتایم `webworker`، ممکن است بخواهید بیلد SSR خود را به در یک فایل جاوا اسکریپت واحد بسته‌بندی (bundle) کنید. شما می‌توانید این رفتار را با تنظیم `ssr.noExternal` به `true` فعال کنید. این کار دو چیز انجام می‌دهد: * تمام وابستگی‌ها را به عنوان `noExternal` در نظر می‌گیرد. * اگر هرکدام از کتابخانه‌های داخلی Node.js ایمپورت شوند، یک خطا ایجاد می‌کند. ## شرایط حل بسته برای SSR به طور پیش‌فرض، برای ساخت SSR، Vite از شرایطی که در [`resolve.conditions`](../config/shared-options.md#resolve-conditions) تنظیم شده است، برای حل ورودی بسته‌ها استفاده می‌کند. شما می‌توانید با استفاده از گزینه‌های [`ssr.resolve.conditions`](../config/ssr-options.md#ssr-resolve-conditions) و [`ssr.resolve.externalConditions`](../config/ssr-options.md#ssr-resolve-externalconditions)، این رفتار را تغییر داده و سفارشی‌سازی کنید. ## Vite CLI دستورات CLI مانند `‎$ vite dev` و `‎$ vite preview` می‌توانند برای برنامه‌های SSR نیز استفاده شوند. شما می‌توانید میدل‌ورهای SSR خود را با استفاده از [`configureServer`](/guide/api-plugin#configureserver) به سرور توسعه و با استفاده از [`configurePreviewServer`](/guide/api-plugin#configurepreviewserver) به سرور پیش‌نمایش اضافه کنید. :::tip نکته از هوک پس از عملیات استفاده کنید تا میانه‌افزار SSR شما *پس از* میدل‌ورهای Vite اجرا شود. ::: --- --- url: /guide/build.md --- # ساخت برای محیط پروداکشن هنگامی که زمان استقرار اپلیکیشن برای محیط پروداکشن فرا می‌رسد، کافی است دستور `vite build` را اجرا کنید. به طور پیش‌فرض، این دستور از فایل `root>/index.html>` به عنوان نقطه ورود ساخت استفاده می‌کند و یک بسته اپلیکیشن تولید می‌کند که برای میزبانی روی سرویس‌های میزبانی استاتیک مناسب است. برای راهنمایی درباره سرویس‌های محبوب، بخش [استقرار سایت استاتیک](./static-deploy) را بررسی کنید. ## سازگاری با مرورگرها به‌صورت پیش‌فرض، بسته تولید (production bundle) فرض می‌کند که مرورگر مدرن و رایجی استفاده می‌شود که در [Baseline](https://web-platform-dx.github.io/web-features/) (قابل‌دسترس به‌طور گسترده) قرار دارد. محدوده پیش‌فرض پشتیبانی مرورگرها به شرح زیر است: * Chrome >=107 * Edge >=107 * Firefox >=104 * Safari >=16 می‌توانید هدف‌های سفارشی را از طریق [گزینه تنظیمات `build.target`](/config/build-options.md#build-target) مشخص کنید، که پایین‌ترین هدف `es2015` است. اگر هدف پایین‌تری تنظیم شود، Vite همچنان به حداقل محدوده پشتیبانی مرورگرها نیاز دارد، زیرا به [ایمپورت پویای ESM بومی](https://caniuse.com/es6-module-dynamic-import) و [`import.meta`](https://caniuse.com/mdn-javascript_operators_import_meta) وابسته است: * Chrome >=64 * Firefox >=67 * Safari >=11.1 * Edge >=79 توجه داشته باشید که به‌صورت پیش‌فرض، Vite تنها وظیفه‌ی تبدیل سینتکس (syntax transforms) را بر عهده دارد و **شامل پلی‌فیل‌ها (polyfills) نمی‌شود**. می‌توانید از وب‌سایت استفاده کنید که بر اساس رشته‌ی UserAgent مرورگر کاربر، به‌صورت خودکار بسته‌ی مناسب پلی‌فیل را تولید می‌کند. مرورگرهای قدیمی‌تر می‌توانند از طریق پلاگین [vitejs/plugin-legacy@](https://github.com/vitejs/vite/tree/main/packages/plugin-legacy) پشتیبانی شوند، که به طور خودکار چانک‌های قدیمی و پلی‌فیل‌های مربوط به ویژگی‌های زبان ES را تولید می‌کند. چانک‌های قدیمی تنها در مرورگرهایی که از ESM بومی پشتیبانی نمی‌کنند، به صورت شرطی بارگذاری می‌شوند. ## مسیر پایه عمومی {#public-base-path} * مرتبط: [مدیریت asset ها](./assets) اگر پروژه خود را در یک مسیر عمومی تودرتو مستقر می‌کنید، کافی است [گزینه تنظیمات `base`](/config/shared-options.md#base) را مشخص کنید تا همه مسیرهای asset ها به طور متناسب بازنویسی شوند. این گزینه همچنین می‌تواند به عنوان پرچم خط فرمان مشخص شود، مثلاً `/vite build --base=/my/public/path` . آدرس asset های ایمپورت‌شده در جاوااسکریپت، ارجاعات `()url` در CSS و ارجاعات asset در فایل‌های `html.` به طور خودکار برای رعایت این گزینه در طول ساخت تنظیم می‌شوند. استثنا زمانی است که نیاز دارید آدرس‌ها را به صورت پویا در لحظه ترکیب کنید. در این مورد، می‌توانید از متغیر سراسری تزریق‌شده `import.meta.env.BASE_URL` استفاده کنید که همان مسیر پایه عمومی خواهد بود. توجه داشته باشید که این متغیر در طول ساخت به صورت استاتیک جایگزین می‌شود، بنابراین باید دقیقاً به همان شکل استفاده شود (یعنی `import.meta.env['BASE_URL']` کار نخواهد کرد). برای کنترل پیشرفته مسیر پایه، [گزینه‌های پیشرفته پایه](#advanced-base-options) را بررسی کنید. ### مسیر پایه نسبی اگر مسیر پایه را از قبل نمی‌دانید، می‌توانید یک مسیر پایه نسبی با `‎"base": "./"‎` یا `‎"base": ""‎` تنظیم کنید. این کار باعث می‌شود همه آدرس‌های تولیدشده نسبت به هر فایل نسبی باشند. :::warning پشتیبانی از مرورگرهای قدیمی‌تر هنگام استفاده از مسیرهای پایه نسبی پشتیبانی از `import.meta` برای مسیرهای پایه نسبی مورد نیاز است. اگر نیاز به پشتیبانی از [مرورگرهایی دارید که از `import.meta` پشتیبانی نمی‌کنند](https://caniuse.com/mdn-javascript_operators_import_meta)، می‌توانید از [پلاگین `legacy`](https://github.com/vitejs/vite/tree/main/packages/plugin-legacy) استفاده کنید. ::: ## سفارشی‌سازی ساخت ساخت را می‌توان از طریق [گزینه‌های تنظیمات ساخت](/config/build-options.md) سفارشی کرد. به طور خاص، می‌توانید [گزینه‌های Rollup](https://rollupjs.org/configuration-options/) را مستقیماً از طریق `build.rollupOptions` تنظیم کنید: ```js [vite.config.js] export default defineConfig({ build: { rollupOptions: { // https://rollupjs.org/configuration-options/ }, }, }) ``` برای مثال، می‌توانید چند نسخه خروجی مختلف برای Rollup مشخص کنید و از پلاگین‌هایی استفاده نمایید که فقط هنگام ساخت (build) پروژه اعمال می‌شوند. ## استراتژی تقسیم چانک‌ها می‌توانید نحوه تقسیم چانک‌ها را با استفاده از `build.rollupOptions.output.manualChunks` (به [مستندات Rollup](https://rollupjs.org/configuration-options/#output-manualchunks) مراجعه کنید) پیکربندی کنید. اگر از یک فریم‌ورک استفاده می‌کنید، به مستندات آن‌ها برای تنظیم نحوه تقسیم چانک‌ها مراجعه کنید. ## مدیریت خطای بارگذاری Vite در صورت شکست بارگذاری ایمپورت‌های پویا، رویداد `vite:preloadError` را منتشر می‌کند. `event.payload` شامل خطای ایمپورت اصلی است. اگر `event.preventDefault()‎` را فراخوانی کنید، خطا صادر نخواهد شد. ```js twoslash window.addEventListener('vite:preloadError', (event) => { window.location.reload() // برای مثال، تازه‌سازی صفحه }) ``` هنگامی که یک استقرار جدید رخ می‌دهد، سرویس میزبانی ممکن است asset های استقرارهای قبلی را حذف کند. در نتیجه، کاربری که پیش از استقرار جدید از سایت شما بازدید کرده است، ممکن است با خطای ایمپورت مواجه شود. این خطا به این دلیل رخ می‌دهد که asset های در حال اجرا روی دستگاه آن کاربر قدیمی هستند و تلاش می‌کند چانک قدیمی مربوطه را که حذف شده است، وارد کند. این رویداد برای رسیدگی به این موقعیت مفید است. ## بازسازی هنگام تغییر فایل‌ها می‌توانید ناظر Rollup را با `vite build --watch` فعال کنید. یا می‌توانید [گزینه‌های ناظر](https://rollupjs.org/configuration-options/#watch) را مستقیماً از طریق `build.watch` تنظیم کنید: ```js [vite.config.js] export default defineConfig({ build: { watch: { // https://rollupjs.org/configuration-options/#watch }, }, }) ``` با فعال بودن پرچم `‎--watch`، تغییرات در `vite.config.js` و همچنین هر فایل دیگری که باید بسته‌بندی شود، باعث بازسازی می‌شود. ## اپلیکیشن چندصفحه‌ای فرض کنید ساختار کد منبع شما به صورت زیر است: ``` ├── package.json ├── vite.config.js ├── index.html ├── main.js └── nested ├── index.html └── nested.js ``` در طول توسعه، کافی است به `/nested/` بروید یا به آن لینک دهید - همان‌طور که انتظار می‌رود، مانند یک سرور فایل استاتیک معمولی کار می‌کند. در طول ساخت، تنها کاری که باید انجام دهید این است که چندین فایل `html.` را به عنوان نقاط ورود مشخص کنید: ```js twoslash [vite.config.js] import { dirname, resolve } from 'node:path' import { fileURLToPath } from 'node:url' import { defineConfig } from 'vite' const __dirname = dirname(fileURLToPath(import.meta.url)) export default defineConfig({ build: { rollupOptions: { input: { main: resolve(__dirname, 'index.html'), nested: resolve(__dirname, 'nested/index.html'), }, }, }, }) ``` اگر ریشه متفاوتی مشخص کنید، به یاد داشته باشید که `dirname__` همچنان پوشه فایل `vite.config.js` شما خواهد بود هنگام رفع مسیرهای ورودی. بنابراین، باید ورودی `root` خود را به آرگومان‌های `resolve` اضافه کنید. توجه داشته باشید که برای فایل‌های HTML، نام داده‌شده به ورودی در آبجکت `rollupOptions.input` نادیده گرفته می‌شود و در عوض، شناسه رفع‌شده فایل را هنگام تولید asset HTML در پوشه dist رعایت می‌کند. این امر ساختار ثابتی با نحوه عملکرد سرور توسعه تضمین می‌کند. ## حالت کتابخانه هنگامی که یک کتابخانه متمرکز بر مرورگر توسعه می‌دهید، احتمالاً بیشتر زمان خود را صرف یک صفحه آزمایشی/دمو می‌کنید که کتابخانه واقعی شما را ایمپورت می‌کند. با Vite، می‌توانید از `index.html` خود برای این منظور استفاده کنید تا تجربه توسعه روان داشته باشید. هنگامی که زمان بسته‌بندی کتابخانه برای توزیع فرا می‌رسد، از [گزینه تنظیمات `build.lib`](/config/build-options.md#build-lib) استفاده کنید. مطمئن شوید که هر وابستگی‌ای که نمی‌خواهید در کتابخانه شما بسته‌بندی شود، مانند `vue` یا `react`، خارجی‌سازی کنید: ::: code-group ```js twoslash [vite.config.js (ورودی تک)] import { dirname, resolve } from 'node:path' import { fileURLToPath } from 'node:url' import { defineConfig } from 'vite' const __dirname = dirname(fileURLToPath(import.meta.url)) export default defineConfig({ build: { lib: { entry: resolve(__dirname, 'lib/main.js'), name: 'MyLib', // پسوندهای مناسب اضافه خواهند شد fileName: 'my-lib', }, rollupOptions: { // اطمینان حاصل کنید وابستگی‌هایی که نباید در کتابخانه بسته‌بندی شوند، خارجی‌سازی شوند external: ['vue'], output: { // برای وابستگی‌های خارجی‌شده فراهم کنید UMD متغیرهای سراسری برای استفاده در ساخت globals: { vue: 'Vue', }, }, }, }, }) ``` ```js twoslash [vite.config.js (ورودی‌های چندگانه)] import { dirname, resolve } from 'node:path' import { fileURLToPath } from 'node:url' import { defineConfig } from 'vite' const __dirname = dirname(fileURLToPath(import.meta.url)) export default defineConfig({ build: { lib: { entry: { 'my-lib': resolve(__dirname, 'lib/main.js'), secondary: resolve(__dirname, 'lib/secondary.js'), }, name: 'MyLib', }, rollupOptions: { // اطمینان حاصل کنید وابستگی‌هایی که نباید در کتابخانه بسته‌بندی شوند، خارجی‌سازی شوند external: ['vue'], output: { // برای وابستگی‌های خارجی‌شده فراهم کنید UMD متغیرهای سراسری برای استفاده در ساخت globals: { vue: 'Vue', }, }, }, }, }) ``` ::: فایل ورودی شامل اکسپورت‌هایی خواهد بود که کاربران بسته شما می‌توانند ایمپورت کنند: ```js [lib/main.js] import Foo from './Foo.vue' import Bar from './Bar.vue' export { Foo, Bar } ``` اجرای `vite build` با این پیکربندی از یک پیش‌تنظیم Rollup استفاده می‌کند که برای انتشار کتابخانه‌ها مناسب است و دو فرمت بسته تولید می‌کند: * `es` و `umd` (برای ورودی تک) * `es` و `cjs` (برای ورودی‌های چندگانه) فرمت‌ها را می‌توان با [گزینه `build.lib.formats`](/config/build-options.md#build-lib) پیکربندی کرد. ``` $ vite build ...ساخت برای پروداکشن dist/my-lib.js 0.08 kB / gzip: 0.07 kB dist/my-lib.umd.cjs 0.30 kB / gzip: 0.16 kB ``` `package.json` پیشنهادی برای کتابخانه شما: ::: code-group ```json [package.json (ورودی تک)] { "name": "my-lib", "type": "module", "files": ["dist"], "main": "./dist/my-lib.umd.cjs", "module": "./dist/my-lib.js", "exports": { ".": { "import": "./dist/my-lib.js", "require": "./dist/my-lib.umd.cjs" } } } ``` ```json [package.json (ورودی‌های چندگانه)] { "name": "my-lib", "type": "module", "files": ["dist"], "main": "./dist/my-lib.cjs", "module": "./dist/my-lib.js", "exports": { ".": { "import": "./dist/my-lib.js", "require": "./dist/my-lib.cjs" }, "./secondary": { "import": "./dist/secondary.js", "require": "./dist/secondary.cjs" } } } ``` ::: ### پشتیبانی از CSS اگر کتابخانه شما CSS ایمپورت کند، این CSS به عنوان یک فایل CSS واحد در کنار فایل‌های JS ساخته‌شده بسته‌بندی می‌شود، مثلاً `dist/my-lib.css`. نام به طور پیش‌فرض به `build.lib.fileName` وابسته است، اما می‌توان آن را با [گزینه `build.lib.cssFileName`](/config/build-options.md#build-lib) تغییر داد. می‌توانید فایل CSS را در `package.json` خود اکسپورت کنید تا کاربران بتوانند آن را وارد کنند: ```json {12} { "name": "my-lib", "type": "module", "files": ["dist"], "main": "./dist/my-lib.umd.cjs", "module": "./dist/my-lib.js", "exports": { ".": { "import": "./dist/my-lib.js", "require": "./dist/my-lib.umd.cjs" }, "./style.css": "./dist/my-lib.css" } } ``` ::: tip پسوندهای فایل اگر `package.json` شامل `"type": "module"` نباشد، Vite برای سازگاری با Node.js پسوندهای متفاوتی تولید می‌کند. `js.` به `mjs.` و `cjs.` به `js.` تبدیل می‌شود. ::: ::: tip متغیرهای محیطی در حالت کتابخانه، تمام استفاده‌های [`*.import.meta.env`](./env-and-mode.md) در زمان ساخت برای تولید به صورت استاتیک جایگزین می‌شوند. با این حال، استفاده‌های `*.process.env` جایگزین نمی‌شوند تا مصرف‌کنندگان کتابخانه شما بتوانند آن‌ها را به صورت پویا تغییر دهند. اگر این رفتار مطلوب نیست، می‌توانید به عنوان مثال از `define: { 'process.env.NODE_ENV': '"production"' }‎` برای جایگزینی استاتیک آن‌ها استفاده کنید یا از [`esm-env`](https://github.com/benmccann/esm-env) برای سازگاری بهتر با باندلرها و ران‌تایم‌ها استفاده کنید. ::: ::: warning استفاده پیشرفته حالت کتابخانه شامل پیکربندی ساده و نظرشده‌ای برای کتابخانه‌های متمرکز بر مرورگر و فریم‌ورک‌های جاوااسکریپت است. اگر کتابخانه‌های غیرمرورگری می‌سازید یا به جریان‌های ساخت پیشرفته نیاز دارید، می‌توانید مستقیماً از [Rollup](https://rollupjs.org) یا [esbuild](https://esbuild.github.io) استفاده کنید. ::: ## گزینه‌های پیشرفته پایه {#advanced-base-options} ::: warning هشدار این ویژگی آزمایشی است. [بازخورد دهید](https://github.com/vitejs/vite/discussions/13834). ::: برای موارد استفاده پیشرفته، asset های مستقرشده و فایل‌های عمومی ممکن است در مسیرهای مختلفی قرار گیرند، برای مثال برای استفاده از استراتژی‌های کش متفاوت. کاربر ممکن است بخواهد در سه مسیر مختلف مستقر کند: * فایل‌های HTML ورودی تولیدشده (که ممکن است در طول SSR پردازش شوند) * asset های هش‌شده تولیدشده (JS ، CSS و انواع فایل‌های دیگر مانند تصاویر) * فایل‌های [عمومی](assets.md#the-public-directory) کپی‌شده یک [پایه](#public-base-path) استاتیک واحد در این سناریوها کافی نیست. Vite پشتیبانی آزمایشی برای گزینه‌های پیشرفته پایه در طول ساخت ارائه می‌دهد، با استفاده از `experimental.renderBuiltUrl`. ```ts twoslash import type { UserConfig } from 'vite' // prettier-ignore const config: UserConfig = { // ---cut-before--- experimental: { renderBuiltUrl(filename, { hostType }) { if (hostType === 'js') { return { runtime: `window.__toCdnUrl(${JSON.stringify(filename)})` } } else { return { relative: true } } }, }, // ---cut-after--- } ``` اگر asset های هش‌شده و فایل‌های عمومی با هم مستقر نشوند، گزینه‌ها برای هر گروه می‌توانند به طور مستقل با استفاده از `type` asset که در پارامتر دوم `context` به تابع داده شده است، تعریف شوند. ```ts twoslash import type { UserConfig } from 'vite' import path from 'node:path' // prettier-ignore const config: UserConfig = { // ---cut-before--- experimental: { renderBuiltUrl(filename, { hostId, hostType, type }) { if (type === 'public') { return 'https://www.domain.com/' + filename } else if (path.extname(hostId) === '.js') { return { runtime: `window.__assetsPath(${JSON.stringify(filename)})` } } else { return 'https://cdn.domain.com/assets/' + filename } }, }, // ---cut-after--- } ``` توجه داشته باشید که `filename` ارسالی یک URL رمزگشایی‌شده است، و اگر تابع یک رشته URL بازگرداند، باید آن هم رمزگشایی‌شده باشد. Vite هنگام رندر کردن URLها به طور خودکار رمزگذاری را مدیریت می‌کند. اگر یک آبجکت با `runtime` بازگردانده شود، رمزگذاری باید در صورت نیاز توسط خودتان مدیریت شود، زیرا کد ران‌تایم همان‌طور که هست رندر خواهد شد. --- --- url: /guide.md --- # شروع ## مرور کلی Vite (یک کلمه فرانسوی به معنای "سریع"، که `/vit/` تلفظ می‌شود، مانند "ویت") یک ابزار بیلد است که هدف آن ارائه تجربه توسعه سریع‌تر و سبک‌تر برای پروژه‌های وب مدرن است. این ابزار از دو بخش اصلی تشکیل شده است: یک سرور توسعه که [ویژگی‌های پیشرفته‌تری](./features) را برای [ماژول‌های ES بومی](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules) فراهم می‌کند. از جمله این ویژگی‌ها، [جایگزینی سریع ماژول (HMR)](./features#hot-module-replacement) با عملکردی بسیار بهینه است. * یک کامَند بیلد که کد شما را با [Rollup](https://rollupjs.org) باندل می‌کند، که آماده شده تا فایل‌های استاتیک بسیار بهینه‌شده برای پروداکشن بسازد. Vite با یک نگرش خاص طراحی شده و تنظیمات پیش‌فرض معقولی را ارائه می‌دهد. برای آشنایی با امکانات بیشتر، می‌توانید به [راهنمای ویژگی‌ها](./features) مراجعه کنید. همچنین، امکان پشتیبانی از فریم‌ورک‌ها و ادغام با سایر ابزارها از طریق [پلاگین‌ها](./using-plugins) وجود دارد. در [بخش تنظیمات](../config/) نیز توضیح داده‌ایم که چگونه Vite را متناسب با نیازهای پروژه خود سفارشی کنید. Vite همچنین از طریق [API پلاگین](./api-plugin) و [API جاوااسکریپت](./api-javascript) با پشتیبانی کامل از تایپ‌ها، به شدت قابل توسعه است. می‌توانید برای آشنایی بیشتر با دلایل پشت پروژه به بخش [چرا Vite](./why) مراجعه کنید. ## پشتیبانی مرورگر در طول فرآیند توسعه، Vite فرض می‌کند که از یک مرورگر مدرن استفاده می‌شود. یعنی مرورگری که از بیشتر قابلیت‌های جدید JavaScript و CSS پشتیبانی می‌کند. به همین دلیل، Vite هدف تبدیل کد را روی [`esnext`](https://esbuild.github.io/api/#target) تنظیم می‌کند. این کار باعث می‌شود کدها به شکل اصلی خود باقی بمانند و نیازی به تبدیل به نسخه‌های قدیمی‌تر نداشته باشند. در نتیجه، Vite ماژول‌ها را تا حد ممکن نزدیک به سورس اصلی ارائه می‌دهد. Vite برای راه‌اندازی سرور توسعه، مقداری کد رانتایم به پروژه اضافه می‌کند. این کدها از ویژگی‌هایی استفاده می‌کنند که در [Baseline](https://web-platform-dx.github.io/web-features/) در زمان هر نسخه اصلی جدید (مثلاً برای این نسخه در تاریخ ۱ مه ۲۰۲۵) در دسترس بوده‌اند. برای ساخت نسخه پروداکشن، Vite به‌طور پیش‌فرض مرورگرهایی را هدف قرار می‌دهد که در دسته [Baseline Widely Available](https://web-platform-dx.github.io/web-features/) قرار دارند، یعنی مرورگرهایی که حداقل ۲.۵ سال پیش منتشر شده‌اند. این هدف را می‌توان از طریق کانفیگ کاهش داد. علاوه‌براین، پشتیبانی از مرورگرهای قدیمی‌تر نیز از طریق افزونه رسمی [‎@vitejs/plugin-legacy](https://github.com/vitejs/vite/tree/main/packages/plugin-legacy) امکان‌پذیر است. برای جزئیات بیشتر به بخش [ساخت برای محیط پروداکشن](./build) مراجعه کنید. ## امتحان Vite به صورت آنلاین می‌توانید Vite را به صورت آنلاین در [StackBlitz](https://vite.new/) امتحان کنید. این ابزار، تنظیمات بیلد مبتنی بر Vite را مستقیماً در مرورگر شما اجرا می‌کند، بنابراین تقریباً با تنظیمات لوکال (local) مشابه است اما نیازی به نصب هیچ چیزی بر روی دستگاه شما ندارد. می‌توانید به `vite.new/{template}` بروید تا فریم‌ورک مورد نظر خود را انتخاب کنید. قالب‌های پشتیبانی شده عبارتند از: | JavaScript | TypeScript | | :---------------------------------: | :---------------------------------------: | | [vanilla](https://vite.new/vanilla) | [vanilla-ts](https://vite.new/vanilla-ts) | | [vue](https://vite.new/vue) | [vue-ts](https://vite.new/vue-ts) | | [react](https://vite.new/react) | [react-ts](https://vite.new/react-ts) | | [preact](https://vite.new/preact) | [preact-ts](https://vite.new/preact-ts) | | [lit](https://vite.new/lit) | [lit-ts](https://vite.new/lit-ts) | | [svelte](https://vite.new/svelte) | [svelte-ts](https://vite.new/svelte-ts) | | [solid](https://vite.new/solid) | [solid-ts](https://vite.new/solid-ts) | | [qwik](https://vite.new/qwik) | [qwik-ts](https://vite.new/qwik-ts) | ## ساخت اولین پروژه Vite شما ::: tip نکته سازگاری Vite به نسخه ۲۰.۱۹ یا بالاتر و همچنین ۲۲.۱۲ یا بالاتر از [Node.js](https://nodejs.org/en/) نیاز دارد. با این حال، برخی قالب‌ها برای کار نیاز به نسخه بالاتری از Node.js دارند. لطفاً اگر پکیج منیحر شما هشدار می‌دهد، Node.js را به‌روزرسانی کنید. ::: ::: code-group ```bash [npm] $ npm create vite@latest ``` ```bash [Yarn] $ yarn create vite ``` ```bash [pnpm] $ pnpm create vite ``` ```bash [Bun] $ bun create vite ``` ```bash [Deno] $ deno init --npm vite ``` ::: سپس مراحل را دنبال کنید! همچنین می‌توانید با استفاده از آپشن‌های اضافی خط فرمان، نام پروژه و قالب مورد نظر خود را مستقیماً مشخص کنید. به عنوان مثال، برای ایجاد یک پروژه Vite با Vue این دستور را اجرا کنید: ::: code-group ```bash [npm] # npm 7+ , دو خط تیره اضافی مورد نیاز است: $ npm create vite@latest my-vue-app -- --template vue ``` ```bash [Yarn] $ yarn create vite my-vue-app --template vue ``` ```bash [pnpm] $ pnpm create vite my-vue-app --template vue ``` ```bash [Bun] $ bun create vite my-vue-app --template vue ``` ```bash [Deno] $ deno init --npm vite my-vue-app --template vue ``` ::: برای جزئیات بیشتر درباره قالب‌های پشتیبانی شده به [create-vite](https://github.com/vitejs/vite/tree/main/packages/create-vite) مراجعه کنید: `vanilla` ، `vanilla-ts` ، `vue` ، `vue-ts` ، `react` ، `react-ts` ، `react-swc` ، `react-swc-ts` ، `preact` ، `preact-ts` ، `lit` ، `lit-ts` ، `svelte` ، `svelte-ts` ، `solid` ، `solid-ts` ، `qwik`، `qwik-ts`. می‌توانید از `.` برای نام پروژه استفاده کنید تا در دایرکتوری فعلی، ساختار پروژه ایجاد شود. ## قالب‌های ارائه شده توسط جامعه create-vite ابزاری است برای شروع سریع یک پروژه از یک قالب پایه برای فریم‌ورک‌های محبوب. می‌توانید Awesome Vite را برای [قالب‌های نگهداری شده توسط جامعه](https://github.com/vitejs/awesome-vite#templates) که شامل ابزارهای دیگر یا فریم‌ورک‌های مختلف هستند، بررسی کنید. برای استفاده قالبی که در `https://github.com/user/project` منتشر شده، می‌توانید آن را به صورت آنلاین با استفاده از `https://github.stackblitz.com/user/project` امتحان کنید (با اضافه کردن `‎.stackblitz` بعد از `github` به URL پروژه). همچنین می‌توانید از ابزاری مانند [degit](https://github.com/Rich-Harris/degit) برای ساخت پروژه خود با یکی از قالب‌ها استفاده کنید. با فرض اینکه پروژه در GitHub است و از `main` به عنوان برنچ پیش‌فرض استفاده می‌کند، می‌توان یک کپی محلی با این دستور ایجاد کرد: ```bash npx degit user/project#main my-project cd my-project npm install npm run dev ``` ## نصب دستی در پروژه خود، می‌توانید ابزار خط فرمان `vite` را با استفاده از دستور زیر نصب کنید: ::: code-group ```bash [npm] $ npm install -D vite ``` ```bash [Yarn] $ yarn add -D vite ``` ```bash [pnpm] $ pnpm add -D vite ``` ```bash [Bun] $ bun add -D vite ``` ```bash [Deno] $ deno add -D npm:vite ``` ::: و یک فایل `index.html` به شکل زیر ایجاد کنید: ```html

Hello Vite!

``` سپس دستور CLI مناسب را در ترمینال خود اجرا کنید: ::: code-group ```bash [npm] $ npx vite ``` ```bash [Yarn] $ yarn vite ``` ```bash [pnpm] $ pnpm vite ``` ```bash [Bun] $ bunx vite ``` ```bash [Deno] $ deno run -A npm:vite ``` ::: `index.html` در `http://localhost:5173` سرو می‌شود. ## `index.html` و ریشه (Root) پروژه یک نکته‌ای که ممکن است متوجه شده باشید این است که در یک پروژه Vite، فایل `index.html` در مرکز توجه قرار دارد به جای اینکه در داخل `public` پنهان شده باشد. این عمدی است: در طول توسعه، Vite یک سرور است و `index.html` نقطه ورود به برنامه شما است. Vite فایل `index.html` را به‌عنوان بخشی از گراف ماژول‌ها و یکی از منابع اصلی کد در نظر می‌گیرد. این ابزار تگ اسکریپت `‎ ``` برای غیرفعال کردن پردازش HTML در برخی المنت‌ها، می‌توانید ویژگی `vite-ignore` را به عنصر اضافه کنید که می‌تواند در هنگام ارجاع به asset های خارجی یا CDN مفید باشد. ## فریمورک‌ها تمام فریم‌ورک‌های مدرن با Vite یکپارچه‌سازی شده‌اند. بیشتر پلاگین‌های فریم‌ورک توسط تیم‌های هر فریم‌ورک نگهداری می‌شوند، به جز پلاگین‌های رسمی Vue و React Vite که توسط سازمان Vite نگهداری می‌شوند: * پشتیبانی از Vue از طریق [‎@vitejs/plugin-vue](https://github.com/vitejs/vite-plugin-vue/tree/main/packages/plugin-vue) * پشتیبانی از Vue JSX از طریق [‎@vitejs/plugin-vue-jsx](https://github.com/vitejs/vite-plugin-vue/tree/main/packages/plugin-vue-jsx) * پشتیبانی از React از طریق [‎@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/tree/main/packages/plugin-react) * پشتیبانی از React با استفاده از SWC از طریق [‎@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/tree/main/packages/plugin-react-swc) برای اطلاعات بیشتر، به [راهنمای پلاگین‌ها](https://vite.dev/plugins) مراجعه کنید. ## JSX فایل‌های `‎.jsx` و `‎.tsx` نیز به صورت پیش‌فرض پشتیبانی می‌شوند. ترنسپایل JSX نیز از طریق [esbuild](https://esbuild.github.io) انجام می‌شود. فریم‌ورک انتخابی شما به طور پیش‌فرض JSX را پیکربندی خواهد کرد (برای مثال، کاربران Vue باید از پلاگین رسمی [‎@vitejs/plugin-vue-jsx](https://github.com/vitejs/vite-plugin-vue/tree/main/packages/plugin-vue-jsx) استفاده کنند که ویژگی‌های خاص Vue 3 از جمله HMR، حل و فصل سراسری کامپوننت‌ها، دایرکتیوها و اسلات‌ها را فراهم می‌کند). اگر از JSX با فریم‌ورک خودتان استفاده می‌کنید، می‌توانید `jsxFactory` و `jsxFragment` سفارشی را با استفاده از گزینه [`esbuild`](/config/shared-options.md#esbuild) تنظیم کنید. به عنوان مثال، پلاگین Preact از این تنظیمات استفاده می‌کند: ```js twoslash [vite.config.js] import { defineConfig } from 'vite' export default defineConfig({ esbuild: { jsxFactory: 'h', jsxFragment: 'Fragment', }, }) ``` جزئیات بیشتر در [مستندات esbuild](https://esbuild.github.io/content-types/#jsx). می‌توانید از `jsxInject` (که یک گزینه مخصوص Vite است) برای تزریق کمک‌کننده‌های JSX استفاده کنید تا از ایمپورت دستی جلوگیری کنید: ```js twoslash [vite.config.js] import { defineConfig } from 'vite' export default defineConfig({ esbuild: { jsxInject: `import React from 'react'`, }, }) ``` ## CSS ایمپورت فایل‌های `‎.css` محتوای آن‌ها را از طریق یک تگ `