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
类型签名
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
类在初始化时需要 root
和 fetchModule
选项。Vite 在 server
实例上公开 ssrFetchModule
,以便更轻松地与 Vite SSR 集成。Vite 还从其主入口点导出 fetchModule
- 它不像 ssrFetchModule
那样对代码如何运行做出任何假设,ssrFetchModule
预计代码使用 new Function
运行。这可以在这些函数返回的源映射中看到。
ViteRuntime
中的 Runner 负责执行代码。Vite 开箱即用地导出 ESModulesRunner
,它使用 new AsyncFunction
来运行代码。如果您使用的 JavaScript 运行时不支持不安全的评估,您可以提供自己的实现。
运行时公开的两个主要方法是 executeUrl
和 executeEntrypoint
。它们之间的唯一区别是,由 executeEntrypoint
执行的所有模块将在 HMR 触发 full-reload
事件时重新执行。请注意,Vite 运行时不会在发生这种情况时更新 exports
对象(它会覆盖它),如果您依赖于拥有最新的 exports
对象,则需要再次运行 executeUrl
或从 moduleCache
中获取模块。
示例用法
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
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
类型签名
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
类型签名
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。isReady
和 send
方法通常在触发自定义事件时调用(例如,import.meta.hot.send("my-event")
)。
onUpdate
仅在初始化新的运行时时调用一次。它传递了一个方法,该方法应该在连接触发 HMR 事件时调用。实现取决于连接类型(例如,它可以是 WebSocket
/EventEmitter
/MessageChannel
),但它通常看起来像这样
function onUpdate(callback) {
this.connection.on('hmr', (event) => callback(event.data))
}
回调被排队,它将等待当前更新解析完毕,然后再处理下一个更新。与浏览器实现不同,Vite 运行时中的 HMR 更新将等待所有监听器(例如,vite:beforeUpdate
/vite:beforeFullReload
)完成,然后再更新模块。
createViteRuntime
类型签名
async function createViteRuntime(
server: ViteDevServer,
options?: MainThreadRuntimeOptions,
): Promise<ViteRuntime>
示例用法
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
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
}