استفاده از نمونههای Environment
Experimental
رابط Environment API هنوز در مرحلهی آزمایشی (experimental) هست. با این حال، ما تلاش میکنیم بین نسخههای اصلی (major) پایداری این APIها را حفظ کنیم تا جامعهی توسعهدهندگان بتوانند با آنها کار کرده و تجربیات خود را بر اساس آنها توسعه دهند. ما قصد داریم این APIهای جدید را در یکی از نسخههای اصلی آینده به حالت پایدار (stable) برسانیم. البته ممکن است در این فرآیند تغییرات شکننده (breaking changes) نیز اعمال شود، اما این کار زمانی انجام خواهد شد که پروژهها و کتابخانههای وابسته فرصت کافی برای آزمایش و ارزیابی این قابلیتهای جدید را داشته باشند.
منابع:
- بحث و گفتگو جایی که ما در حال جمعآوری نظرات درباره APIهای جدید هستیم.
- PR مربوط به Environment API جایی که API جدید پیادهسازی و بررسی شده است.
لطفاً نظرات و بازخوردهای خود را با ما به اشتراک بگذارید.
دسترسی به محیطها
در حالت توسعه (dev)، میتوان با استفاده از server.environments به محیطهای موجود در یک سرور توسعه دسترسی داشت:
// دریافت کنید configureServer سرور را ایجاد کنید یا آن را از هوک const server = await createServer(/* options */) const clientEnvironment = server.environments.client clientEnvironment.transformRequest(url) console.log(server.environments.ssr.moduleGraph)همچنین میتوانید از طریق پلاگینها به محیط فعلی دسترسی داشته باشید. برای جزئیات بیشتر، به API محیط برای پلاگینها مراجعه کنید.
کلاس DevEnvironment
در حالت توسعه (dev)، هر محیط یک نمونه از کلاس DevEnvironment است:
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<TransformResult | null> /** * یک درخواست را برای پردازش با اولویت پایین ثبت میکند. این کار * اطلاعاتی Vite برای جلوگیری از وابستگیهای زنجیرهای مفید است. سرور * دربارهی ماژولهای ایمپورت شده توسط درخواستهای دیگر دارد، بنابراین میتواند * گراف ماژول را از پیش آماده کند تا ماژولها هنگام درخواست، پردازش شده باشند */ async warmupRequest(url: string): Promise<void> }با DevEnvironmentContext به صورت زیر است:
interface DevEnvironmentContext { hot: boolean transport?: HotChannel | WebSocketServer options?: EnvironmentOptions remoteRunner?: { inlineSourceMap?: boolean } depsOptimizer?: DepsOptimizer }و با TransformResult به صورت زیر است:
interface TransformResult { code: string map: SourceMap | { mappings: '' } | null etag?: string deps?: string[] dynamicDeps?: string[] }یک نمونه از محیط در سرور Vite به شما امکان میدهد که یک URL را با استفاده از متد environment.transformRequest(url) پردازش کنید. این تابع از خط پردازش پلاگینها برای تبدیل url به یک شناسهی ماژول (id) استفاده میکند، آن را بارگذاری میکند (با خواندن فایل از فایل سیستم یا از طریق پلاگینی که یک ماژول مجازی را پیادهسازی کرده است) و سپس کد را تبدیل میکند. در حین تبدیل ماژول،ایمپورتهای آن و دیگر اطلاعات متادیتا در گراف ماژول محیط ثبت میشوند، با ایجاد یا بهروزرسانی نود ماژول مربوطه. پس از اتمام پردازش، نتیجهی تبدیل نیز در ماژول ذخیره میشود.
نامگذاری transformRequest
در نسخهی کنونی این پیشنهاد، از transformRequest(url) و warmupRequest(url) استفاده میکنیم تا درک و بحث دربارهی آن برای کاربرانی که به API فعلی Vite عادت دارند، آسانتر باشد. پیش از انتشار، میتوانیم فرصت را برای بازبینی این نامها نیز غنیمت بشماریم. برای مثال، ممکن است نام آن را به environment.processModule(url) یا environment.loadModule(url) تغییر دهیم، مشابه context.load(id) در پلاگینهای Rollup. در حال حاضر، حفظ نامهای فعلی و به تعویق انداختن این بحث را بهتر میدانیم.
گرافهای ماژول مجزا
هر محیط یک گراف ماژول ایزوله دارد. همه گرافهای ماژول امضای یکسانی دارند، بنابراین میتوان الگوریتمهای کلی برای پیمایش یا پیمایش گراف بدون وابستگی به محیط پیادهسازی کرد. مثال خوب آن hotUpdate است. وقتی یک فایل تغییر میکند، گراف ماژول هر محیط بررسی میشود تا ماژولهای تحت تأثیر را پیدا کند و HMR را به صورت مستقل برای هر محیط انجام دهد.
نکته
Vite نسخه ۵ یک گراف ماژول مشترک بین کلاینت و SSR داشت. اگر یک نود هنوز پردازش نشده یا باطل شده باشد، نمیتوان تشخیص داد که مربوط به محیط کلاینت، SSR، یا هر دو است. نودهای ماژول دارای برخی ویژگیهای پیشونددار هستند، مانند clientImportedModules و ssrImportedModules (بهعلاوه importedModules که اجتماع هر دو را برمیگرداند). فیلد importers همه ایمپورترهای مربوط به هر دو محیط کلاینت و SSR را برای هر نود ماژول شامل میشود. هر نود ماژول همچنین دارای transformResult و ssrTransformResult است. لایهای برای حفظ سازگاری به اکوسیستم اجازه میدهد تا از server.moduleGraph منسوخ شده به این مدل جدید مهاجرت کند.
هر ماژول توسط یک نمونه از EnvironmentModuleNode نشان داده میشود. ممکن است ماژولها در گراف بدون پردازش اولیه ثبت شوند (در این حالت، مقدار transformResult برابر null خواهد بود). فیلدهای importers و importedModules نیز پس از پردازش ماژول بهروزرسانی میشوند.
class EnvironmentModuleNode { environment: string url: string id: string | null = null file: string | null = null type: 'js' | 'css' importers = new Set<EnvironmentModuleNode>() importedModules = new Set<EnvironmentModuleNode>() importedBindings: Map<string, Set<string>> | null = null info?: ModuleInfo meta?: Record<string, any> transformResult: TransformResult | null = null acceptedHmrDeps = new Set<EnvironmentModuleNode>() acceptedHmrExports: Set<string> | null = null isSelfAccepting?: boolean lastHMRTimestamp = 0 lastInvalidationTimestamp = 0 }environment.moduleGraph is an instance of EnvironmentModuleGraph:
export class EnvironmentModuleGraph { environment: string urlToModuleMap = new Map<string, EnvironmentModuleNode>() idToModuleMap = new Map<string, EnvironmentModuleNode>() etagToModuleMap = new Map<string, EnvironmentModuleNode>() fileToModulesMap = new Map<string, Set<EnvironmentModuleNode>>() constructor( environment: string, resolveId: (url: string) => Promise<PartialResolvedId | null>, ) async getModuleByUrl( rawUrl: string, ): Promise<EnvironmentModuleNode | undefined> getModuleById(id: string): EnvironmentModuleNode | undefined getModulesByFile(file: string): Set<EnvironmentModuleNode> | undefined onFileChange(file: string): void onFileDelete(file: string): void invalidateModule( mod: EnvironmentModuleNode, seen: Set<EnvironmentModuleNode> = new Set(), timestamp: number = monotonicDateNow(), isHmr: boolean = false, ): void invalidateAll(): void async ensureEntryFromUrl( rawUrl: string, setIsSelfAccepting = true, ): Promise<EnvironmentModuleNode> createFileOnlyEntry(file: string): EnvironmentModuleNode async resolveUrl(url: string): Promise<ResolvedUrl> updateModuleTransformResult( mod: EnvironmentModuleNode, result: TransformResult | null, ): void getModuleByEtag(etag: string): EnvironmentModuleNode | undefined }