Vite Runtime API
底層 API
此 API 在 Vite 5.1 中作為實驗性功能推出。它被加入以 收集回饋。可能會發生重大變更,因此在使用時務必將 Vite 版本固定為 ~5.1.0
。這是專為函式庫和框架作者設計的底層 API。如果您的目標是建立應用程式,請務必先查看 Awesome Vite SSR 中的高階 SSR 外掛程式和工具。
目前,此 API 正在作為 環境 API 進行修改,並在 ^6.0.0-alpha.0
中發布。
「Vite Runtime」是一個工具,允許透過先使用 Vite 外掛程式處理任何程式碼來執行該程式碼。它不同於 server.ssrLoadModule
,因為執行時間實作與伺服器分離。這允許函式庫和框架作者實作伺服器和執行時間之間自己的通訊層。
此功能的目標之一是提供一個可自訂的 API 來處理和執行程式碼。Vite 提供了足夠的工具來開箱即用 Vite Runtime,但如果使用者的需求與 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
不同,它不會對程式碼的執行方式做出任何假設,後者預期程式碼會使用 new Function
執行。這可以在這些函式傳回的原始碼對應中看到。
ViteRuntime
中的執行器負責執行程式碼。Vite 開箱即用地匯出 ESModulesRunner
,它使用 new AsyncFunction
來執行程式碼。如果您使用的 JavaScript 執行時間不支援不安全的評估,您可以提供自己的實作。
執行時間公開的兩個主要方法是 executeUrl
和 executeEntrypoint
。它們之間唯一的差別是,如果 HMR 觸發 full-reload
事件,那麼由 executeEntrypoint
執行的所有模組都將重新執行。請注意,當發生這種情況時,Vite Runtime 不會更新 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
自動完成的。如果你的執行器實作沒有此限制,你應直接使用從 vite
匯出的 fetchModule
。
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。通常在觸發自訂事件(例如,import.meta.hot.send("my-event")
)時會呼叫 isReady
和 send
方法。
僅在初始化新的執行時間時會呼叫 onUpdate
。它傳遞一個方法,該方法應在連線觸發 HMR 事件時呼叫。實作取決於連線類型(例如,它可以是 WebSocket
/EventEmitter
/MessageChannel
),但通常看起來像這樣
function onUpdate(callback) {
this.connection.on('hmr', (event) => callback(event.data))
}
會排隊處理回呼,它會等到目前更新已解決後才會處理下一個更新。與瀏覽器實作不同,Vite Runtime 中的 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
}