Environment 实例使用参考
使用 Environment 实例
:::info 发布候选版本
Environment API 总体上处于发布候选阶段。我们将在主版本之间保持 API 的稳定性,以便生态系统能够进行实验并在此基础上构建。但请注意,某些特定的 API 仍被视为实验性 API。
我们计划在未来的主版本中稳定这些新 API(可能包含破坏性变更),以便下游项目有时间体验新功能并对其进行验证。
资源:
- 反馈讨论 我们在此收集关于新 API 的反馈。
- Environment API PR 新 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类的实例:
tsclass 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为:
tsinterface DevEnvironmentContext { hot: boolean transport?: HotChannel | WebSocketServer options?: EnvironmentOptions remoteRunner?: { inlineSourceMap?: boolean } depsOptimizer?: DepsOptimizer }
TransformResult为:
tsinterface 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 共有的。模块节点具有一些带前缀的属性,如clientImportedModules和ssrImportedModules(以及返回两者并集的importedModules)。importers包含来自 Client 和 SSR environment 的每个模块节点的所有导入者。模块节点还具有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<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 是 EnvironmentModuleGraph 的一个实例:
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,供模块运行器使用。FetchResult 是 CachedFetchResult、ExternalFetchResult 和 ViteFetchResult 的联合类型。
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 以及模块的 id、file 和 url。
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
}
帮助我们改进文档
发现翻译问题或内容错误?请告诉我们。
