跳到內容

使用 Environment 實例

實驗性功能

環境 API 為實驗性功能。我們將在 Vite 6 期間保持 API 的穩定性,讓生態系統可以實驗並在其之上建構。我們計劃在 Vite 7 中穩定這些新的 API,並可能會有重大變更。

資源

請與我們分享您的回饋。

存取環境

在開發期間,開發伺服器中可用的環境可以使用 server.environments 存取

js
// create the server, or get it from the configureServer hook
const server = await createServer(/* options */)

const environment = server.environments.client
environment.transformRequest(url)
console.log(server.environments.ssr.moduleGraph)

您也可以從外掛存取目前的環境。請參閱外掛的環境 API以獲取更多詳細資訊。

DevEnvironment 類別

在開發期間,每個環境都是 DevEnvironment 類別的實例

ts
class DevEnvironment {
  /**
   * Unique identifier for the environment in a Vite server.
   * By default Vite exposes 'client' and 'ssr' environments.
   */
  name: string
  /**
   * Communication channel to send and receive messages from the
   * associated module runner in the target runtime.
   */
  hot: NormalizedHotChannel
  /**
   * Graph of module nodes, with the imported relationship between
   * processed modules and the cached result of the processed code.
   */
  moduleGraph: EnvironmentModuleGraph
  /**
   * Resolved plugins for this environment, including the ones
   * created using the per-environment `create` hook
   */
  plugins: Plugin[]
  /**
   * Allows to resolve, load, and transform code through the
   * environment plugins pipeline
   */
  pluginContainer: EnvironmentPluginContainer
  /**
   * Resolved config options for this environment. Options at the server
   * global scope are taken as defaults for all environments, and can
   * be overridden (resolve conditions, external, optimizedDeps)
   */
  config: ResolvedConfig & ResolvedDevEnvironmentOptions

  constructor(
    name: string,
    config: ResolvedConfig,
    context: DevEnvironmentContext,
  )

  /**
   * Resolve the URL to an id, load it, and process the code using the
   * plugins pipeline. The module graph is also updated.
   */
  async transformRequest(url: string): Promise<TransformResult | null>

  /**
   * Register a request to be processed with low priority. This is useful
   * to avoid waterfalls. The Vite server has information about the
   * imported modules by other requests, so it can warmup the module graph
   * so the modules are already processed when they are requested.
   */
  async warmupRequest(url: string): Promise<void>
}

其中 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 伺服器中的環境實例可讓您使用 environment.transformRequest(url) 方法處理 URL。此函式將使用外掛管線將 url 解析為模組 id、載入它(從檔案系統讀取檔案或透過實作虛擬模組的外掛),然後轉換程式碼。在轉換模組時,匯入和其他中繼資料將透過建立或更新相應的模組節點記錄在環境模組圖表中。處理完成後,轉換結果也會儲存在模組中。

transformRequest 命名

我們在這個提案的目前版本中使用 transformRequest(url)warmupRequest(url),以便對於習慣 Vite 目前 API 的使用者來說,更容易討論和理解。在發佈之前,我們也可以藉此機會檢閱這些名稱。例如,它可以命名為 environment.processModule(url)environment.loadModule(url),從 Rollup 在外掛鉤子中的 context.load(id) 中獲取靈感。目前,我們認為保留目前的名稱並延後此討論會比較好。

獨立的模組圖表

每個環境都有一個獨立的模組圖表。所有模組圖表都具有相同的簽名,因此可以實作泛型演算法來爬取或查詢圖表,而無需依賴環境。hotUpdate 就是一個很好的例子。當檔案被修改時,每個環境的模組圖表將用於發現受影響的模組,並為每個環境獨立執行 HMR。

資訊

Vite v5 有一個混合的客戶端和 SSR 模組圖表。給定一個未處理或失效的節點,不可能知道它對應於客戶端、SSR 或兩個環境。模組節點有一些帶有前綴的屬性,例如 clientImportedModulesssrImportedModules(以及返回兩者聯合的 importedModules)。importers 包含每個模組節點來自客戶端和 SSR 環境的所有匯入器。模組節點也有 transformResultssrTransformResult。一個向後相容層允許生態系統從已棄用的 server.moduleGraph 遷移。

每個模組都由一個 EnvironmentModuleNode 實例表示。模組可能會在未經處理的情況下註冊到圖表中(在這種情況下,transformResult 將為 null)。importersimportedModules 也會在模組處理後更新。

ts
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.moduleGraphEnvironmentModuleGraph 的實例

ts
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 = Date.now(),
    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
}

根據 MIT 授權發佈。(ccee3d7c)