跳至内容

Vite 运行时 API

低级 API

此 API 在 Vite 5.1 中作为实验性功能引入。它被添加到 收集反馈。可能会出现重大更改,因此在使用它时请确保将 Vite 版本固定到 ~5.1.0。这是一个低级 API,专为库和框架作者设计。如果您想创建一个应用程序,请务必先查看 Awesome Vite SSR 部分 中的更高级别的 SSR 插件和工具。

目前,该 API 正在被修改为 环境 API,该 API 在 ^6.0.0-alpha.0 中发布。

“Vite 运行时”是一个工具,它允许通过先使用 Vite 插件处理代码来运行任何代码。它不同于 server.ssrLoadModule,因为运行时实现与服务器分离。这允许库和框架作者在服务器和运行时之间实现自己的通信层。

此功能的目标之一是提供一个可定制的 API 来处理和运行代码。Vite 提供了足够的工具来开箱即用地使用 Vite 运行时,但如果用户的需求与 Vite 的内置实现不一致,用户可以对其进行扩展。

除非另有说明,所有 API 都可以从 vite/runtime 中导入。

ViteRuntime

类型签名

ts
export class ViteRuntime {
  constructor(
    public options: ViteRuntimeOptions,
    public runner: ViteModuleRunner,
    private debug?: ViteRuntimeDebugger,
  ) {}
  /**
   * URL to execute. Accepts file path, server path, or id relative to the root.
   */
  public async executeUrl<T = any>(url: string): Promise<T>
  /**
   * Entry point URL to execute. Accepts file path, server path or id relative to the root.
   * In the case of a full reload triggered by HMR, this is the module that will be reloaded.
   * If this method is called multiple times, all entry points will be reloaded one at a time.
   */
  public async executeEntrypoint<T = any>(url: string): Promise<T>
  /**
   * Clear all caches including HMR listeners.
   */
  public clearCache(): void
  /**
   * Clears all caches, removes all HMR listeners, and resets source map support.
   * This method doesn't stop the HMR connection.
   */
  public async destroy(): Promise<void>
  /**
   * Returns `true` if the runtime has been destroyed by calling `destroy()` method.
   */
  public isDestroyed(): boolean
}

高级用法

如果您只是从 server.ssrLoadModule 迁移,并且想要支持 HMR,请考虑使用 createViteRuntime 代替。

ViteRuntime 类在初始化时需要 rootfetchModule 选项。Vite 在 server 实例上公开 ssrFetchModule,以便更轻松地与 Vite SSR 集成。Vite 还从其主入口点导出 fetchModule - 它不像 ssrFetchModule 那样对代码如何运行做出任何假设,ssrFetchModule 预计代码使用 new Function 运行。这可以在这些函数返回的源映射中看到。

ViteRuntime 中的 Runner 负责执行代码。Vite 开箱即用地导出 ESModulesRunner,它使用 new AsyncFunction 来运行代码。如果您使用的 JavaScript 运行时不支持不安全的评估,您可以提供自己的实现。

运行时公开的两个主要方法是 executeUrlexecuteEntrypoint。它们之间的唯一区别是,由 executeEntrypoint 执行的所有模块将在 HMR 触发 full-reload 事件时重新执行。请注意,Vite 运行时不会在发生这种情况时更新 exports 对象(它会覆盖它),如果您依赖于拥有最新的 exports 对象,则需要再次运行 executeUrl 或从 moduleCache 中获取模块。

示例用法

js
import { ViteRuntime, ESModulesRunner } from 'vite/runtime'
import { root, fetchModule } from './rpc-implementation.js'

const runtime = new ViteRuntime(
  {
    root,
    fetchModule,
    // you can also provide hmr.connection to support HMR
  },
  new ESModulesRunner(),
)

await runtime.executeEntrypoint('/src/entry-point.js')

ViteRuntimeOptions

ts
export interface ViteRuntimeOptions {
  /**
   * Root of the project
   */
  root: string
  /**
   * A method to get the information about the module.
   * For SSR, Vite exposes `server.ssrFetchModule` function that you can use here.
   * For other runtime use cases, Vite also exposes `fetchModule` from its main entry point.
   */
  fetchModule: FetchFunction
  /**
   * 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.
   */
  hmr?:
    | false
    | {
        /**
         * Configure how HMR communicates between the client and the server.
         */
        connection: HMRRuntimeConnection
        /**
         * Configure HMR logger.
         */
        logger?: false | HMRLogger
      }
  /**
   * Custom module cache. If not provided, it creates a separate module cache for each ViteRuntime instance.
   */
  moduleCache?: ModuleCacheMap
}

ViteModuleRunner

类型签名

ts
export interface ViteModuleRunner {
  /**
   * Run code that was transformed by Vite.
   * @param context Function context
   * @param code Transformed code
   * @param id ID that was used to fetch the module
   */
  runViteModule(
    context: ViteRuntimeModuleContext,
    code: string,
    id: string,
  ): Promise<any>
  /**
   * Run externalized module.
   * @param file File URL to the external module
   */
  runExternalModule(file: string): Promise<any>
}

Vite 默认情况下导出 ESModulesRunner,它实现了此接口。它使用 new AsyncFunction 来运行代码,因此如果代码包含内联源映射,它应该包含 2 行偏移量 以适应添加的新行。这是由 server.ssrFetchModule 自动完成的。如果您的 Runner 实现没有此约束,您应该直接使用 fetchModule(从 vite 导出)。

HMRRuntimeConnection

类型签名

ts
export interface HMRRuntimeConnection {
  /**
   * Checked before sending messages to the client.
   */
  isReady(): boolean
  /**
   * Send message to the client.
   */
  send(message: string): void
  /**
   * Configure how HMR is handled when this connection triggers an update.
   * This method expects that connection will start listening for HMR updates and call this callback when it's received.
   */
  onUpdate(callback: (payload: HMRPayload) => void): void
}

此接口定义了如何建立 HMR 通信。Vite 从主入口点导出 ServerHMRConnector 来支持 Vite SSR 期间的 HMR。isReadysend 方法通常在触发自定义事件时调用(例如,import.meta.hot.send("my-event"))。

onUpdate 仅在初始化新的运行时时调用一次。它传递了一个方法,该方法应该在连接触发 HMR 事件时调用。实现取决于连接类型(例如,它可以是 WebSocket/EventEmitter/MessageChannel),但它通常看起来像这样

js
function onUpdate(callback) {
  this.connection.on('hmr', (event) => callback(event.data))
}

回调被排队,它将等待当前更新解析完毕,然后再处理下一个更新。与浏览器实现不同,Vite 运行时中的 HMR 更新将等待所有监听器(例如,vite:beforeUpdate/vite:beforeFullReload)完成,然后再更新模块。

createViteRuntime

类型签名

ts
async function createViteRuntime(
  server: ViteDevServer,
  options?: MainThreadRuntimeOptions,
): Promise<ViteRuntime>

示例用法

js
import { createServer } from 'vite'

const __dirname = fileURLToPath(new URL('.', import.meta.url))

;(async () => {
  const server = await createServer({
    root: __dirname,
  })
  await server.listen()

  const runtime = await createViteRuntime(server)
  await runtime.executeEntrypoint('/src/entry-point.js')
})()

此方法可以轻松替换 server.ssrLoadModule。与 ssrLoadModule 不同,createViteRuntime 开箱即用地提供 HMR 支持。您可以传递 options 来定制 SSR 运行时的行为,以满足您的需求。

MainThreadRuntimeOptions

ts
export interface MainThreadRuntimeOptions
  extends Omit<ViteRuntimeOptions, 'root' | 'fetchModule' | 'hmr'> {
  /**
   * Disable HMR or configure HMR logger.
   */
  hmr?:
    | false
    | {
        logger?: false | HMRLogger
      }
  /**
   * Provide a custom module runner. This controls how the code is executed.
   */
  runner?: ViteModuleRunner
}