知海

Environment 实例使用参考

vite-mainAPI 参考

使用 Environment 实例

:::info 发布候选版本
Environment API 总体上处于发布候选阶段。我们将在主版本之间保持 API 的稳定性,以便生态系统能够进行实验并在此基础上构建。但请注意,某些特定的 API 仍被视为实验性 API。

我们计划在未来的主版本中稳定这些新 API(可能包含破坏性变更),以便下游项目有时间体验新功能并对其进行验证。

资源:

欢迎分享您的反馈。

访问 Environment

在开发环境下,可以通过 server.environments 访问开发服务器中可用的 environment:

js 复制代码
// 创建服务器,或在 configureServer 钩子中获取
const server = await createServer(/* options */)

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

你也可以在插件中访问当前的 environment。更多详情请参阅 面向插件的 Environment API

DevEnvironment

在开发环境下,每个 environment 都是 DevEnvironment 类的实例:

ts 复制代码
class DevEnvironment {
  /**
   * Vite 服务器中 environment 的唯一标识符。
   * 默认情况下,Vite 会暴露 'client' 和 'ssr' 两个 environment。
   */
  name: string
  /**
   * 与目标运行时中关联的模块运行器进行消息收发的通信渠道。
   */
  hot: NormalizedHotChannel
  /**
   * 模块节点图,包含已处理模块之间的导入关系以及处理代码的缓存结果。
   */
  moduleGraph: EnvironmentModuleGraph
  /**
   * 针对该 environment 解析后的插件列表,包括使用
   * 按环境(per-environment)的 `create` 钩子创建的插件。
   */
  plugins: Plugin[]
  /**
   * 允许通过 environment 的插件流水线进行解析、加载和转换代码。
   */
  pluginContainer: EnvironmentPluginContainer
  /**
   * 针对该 environment 的解析后配置选项。服务器全局范围的选项
   * 作为所有 environment 的默认值,并且可以被覆盖
   * (例如 resolve conditions、external、optimizedDeps)。
   */
  config: ResolvedConfig & ResolvedDevEnvironmentOptions

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

  /**
   * 将 URL 解析为 id,加载它,并使用插件流水线处理代码。
   * 模块图也会相应更新。
   */
  async transformRequest(url: string): Promise<TransformResult | null>

  /**
   * 以低优先级注册一个请求进行处理。这对于避免瀑布式请求
   * (waterfalls)很有用。Vite 服务器拥有其他请求导入模块的
   * 相关信息,因此它可以预热模块图,使得模块在被请求时
   * 已经被处理完毕。
   */
  async warmupRequest(url: string): Promise<void>

  /**
   * 由模块运行器调用,用于检索指定模块的信息。
   * 内部会调用 `transformRequest` 并将结果包装为模块运行器
   * 能够理解的格式。
   * 此方法不适用于手动调用。
   */
  async fetchModule(
    id: string,
    importer?: string,
    options?: FetchFunctionOptions,
  ): Promise<FetchResult>
}

其中 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 实例允许你使用 environment.transformRequest(url) 方法处理 URL。此函数将使用插件流水线将 url 解析为模块 id,加载它(从文件系统读取文件或通过实现虚拟模块的插件读取),然后转换代码。在转换模块时,导入和其他元数据将通过创建或更新相应的模块节点记录到 environment 模块图中。处理完成后,转换结果也会存储在模块中。info transformRequest 命名
在当前版本的这个提案中,我们使用 transformRequest(url)warmupRequest(url),这便于熟悉 Vite 现有 API 的用户讨论和理解。在发布之前,我们可以借此机会重新审视这些名称。例如,它可以命名为 environment.processModule(url)environment.loadModule(url),借鉴 Rollup 插件钩子中 context.load(id) 的命名方式。目前,我们认为保留现有名称并推迟此讨论更为合适。

独立的模块图

每个 environment 都有一个独立的模块图。所有模块图具有相同的签名,因此可以实现通用算法来爬取或查询图,而无需依赖具体的 environment。hotUpdate 就是一个很好的例子。当文件被修改时,将使用每个 environment 的模块图来发现受影响的模块,并为每个 environment 独立执行 HMR。info
Vite v5 具有混合的 Client 和 SSR 模块图。给定一个未处理或已失效的节点,无法知道它对应的是 Client、SSR 还是两个 environment 共有的。模块节点具有一些带前缀的属性,如 clientImportedModulesssrImportedModules(以及返回两者并集的 importedModules)。importers 包含来自 Client 和 SSR environment 的每个模块节点的所有导入者。模块节点还具有 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 = 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
}

FetchResult

environment.fetchModule 方法返回一个 FetchResult,供模块运行器使用。FetchResultCachedFetchResultExternalFetchResultViteFetchResult 的联合类型。

CachedFetchResult 类似于 HTTP 状态码 304(未修改)。

ts 复制代码
export interface CachedFetchResult {
  /**
   * 如果模块在运行器中被缓存,这确认
   * 该模块在服务器端未被失效。
   */
  cache: true
}

ExternalFetchResult 指示模块运行器使用 ModuleEvaluator 上的 runExternalModule 方法导入模块。在这种情况下,默认的模块求值器将使用运行时的原生 import 而不是通过 Vite 处理文件。

ts 复制代码
export interface ExternalFetchResult {
  /**
   * 外部化模块的路径,以 file:// 开头。
   * 默认情况下,将通过动态 "import" 导入此路径,
   * 而不是由 Vite 转换并使用 Vite 运行器加载。
   */
  externalize: string
  /**
   * 模块的类型。用于判断导入语句是否正确。
   * 例如,如果某个变量实际上没有被导出,Vite 是否需要抛出错误。
   */
  type: 'module' | 'commonjs' | 'builtin' | 'network'
}

ViteFetchResult 返回当前模块的信息,包括要执行的 code 以及模块的 idfileurl

invalidate 字段指示模块运行器在再次执行模块之前使其失效,而不是从缓存中提供。这通常在触发 HMR 更新时为 true

ts 复制代码
export interface ViteFetchResult {
  /**
   * 将由 Vite 运行器求值的代码。
   * 默认情况下,这将被包装在一个异步函数中。
   */
  code: string
  /**
   * 模块在磁盘上的文件路径。
   * 这将被解析为 import.meta.url/filename。
   * 对于虚拟模块,这将是 `null`。
   */
  file: string | null
  /**
   * 服务器模块图中的模块 ID。
   */
  id: string
  /**
   * 导入时使用的模块 URL。
   */
  url: string
  /**
   * 使客户端模块失效。
   */
  invalidate: boolean
}

帮助我们改进文档

发现翻译问题或内容错误?请告诉我们。