外掛的環境 API
實驗性功能
環境 API 屬於實驗性功能。我們將在 Vite 6 中保持 API 的穩定性,讓生態系統可以進行實驗並在其基礎上建構。我們計劃在 Vite 7 中穩定這些新的 API,並可能進行重大變更。
資源
請與我們分享您的意見回饋。
在鉤子中存取目前的環境
在 Vite 6 之前,只有兩種環境(client
和 ssr
),因此 ssr
布林值足以識別 Vite API 中的目前環境。外掛鉤子在最後的選項參數中收到 ssr
布林值,而數個 API 預期會有選填的最後一個 ssr
參數,以將模組正確地關聯到正確的環境(例如 server.moduleGraph.getModuleByUrl(url, { ssr })
)。
隨著可設定環境的出現,我們現在可以使用統一的方式在外掛中存取其選項和實例。外掛鉤子現在在其上下文中公開 this.environment
,而先前預期會有 ssr
布林值的 API 現在已限定到適當的環境(例如 environment.moduleGraph.getModuleByUrl(url)
)。
Vite 伺服器具有共用的外掛管道,但是當處理模組時,始終是在給定環境的上下文中進行。environment
實例在外掛的上下文中可用。
外掛可以使用 environment
實例,根據環境的設定(可以使用 environment.config
存取)來變更處理模組的方式。
transform(code, id) {
console.log(this.environment.config.resolve.conditions)
}
使用鉤子註冊新環境
外掛可以在 config
鉤子中新增新環境(例如,為 RSC 建立單獨的模組圖)。
config(config: UserConfig) {
config.environments.rsc ??= {}
}
空物件足以註冊環境,以及來自根層級環境設定的預設值。
使用鉤子設定環境
在 config
鉤子執行時,尚未知道完整的環境清單,而且環境可能會受到來自根層級環境設定的預設值,或是透過 config.environments
記錄明確地影響。外掛應該使用 config
鉤子設定預設值。為了設定每個環境,它們可以使用新的 configEnvironment
鉤子。會針對每個環境呼叫此鉤子,並帶有其部分解析的設定,包括最終預設值的解析。
configEnvironment(name: string, options: EnvironmentOptions) {
if (name === 'rsc') {
options.resolve.conditions = // ...
hotUpdate
鉤子
- 類型:
(this: { environment: DevEnvironment }, options: HotUpdateOptions) => Array<EnvironmentModuleNode> | void | Promise<Array<EnvironmentModuleNode> | void>
- 另請參閱: HMR API
hotUpdate
鉤子允許外掛對給定環境執行自訂 HMR 更新處理。當檔案變更時,會依據 server.environments
中的順序,依序針對每個環境執行 HMR 演算法,因此會多次呼叫 hotUpdate
鉤子。此鉤子會收到具有下列簽章的上下文物件
interface HotUpdateOptions {
type: 'create' | 'update' | 'delete'
file: string
timestamp: number
modules: Array<EnvironmentModuleNode>
read: () => string | Promise<string>
server: ViteDevServer
}
this.environment
是目前正在處理檔案更新的模組執行環境。modules
是此環境中受變更檔案影響的模組陣列。它是陣列,因為單一檔案可能會對應到多個服務的模組(例如 Vue SFC)。read
是傳回檔案內容的非同步讀取函式。提供此函式的原因是,在某些系統上,檔案變更回呼可能會在編輯器完成更新檔案之前太快觸發,而直接的fs.readFile
將會傳回空的內容。傳入的讀取函式會標準化此行為。
此鉤子可以選擇
篩選並縮小受影響的模組清單,以便 HMR 更準確。
傳回空陣列並執行完整重新載入
jshotUpdate({ modules, timestamp }) { if (this.environment.name !== 'client') return // Invalidate modules manually const invalidatedModules = new Set() for (const mod of modules) { this.environment.moduleGraph.invalidateModule( mod, invalidatedModules, timestamp, true ) } this.environment.hot.send({ type: 'full-reload' }) return [] }
傳回空陣列並透過傳送自訂事件到用戶端來執行完整的自訂 HMR 處理
jshotUpdate() { if (this.environment.name !== 'client') return this.environment.hot.send({ type: 'custom', event: 'special-update', data: {} }) return [] }
用戶端程式碼應該使用 HMR API 來註冊對應的處理常式(這可以由相同外掛的
transform
鉤子注入)jsif (import.meta.hot) { import.meta.hot.on('special-update', (data) => { // perform custom update }) }
每個環境的外掛
外掛可以使用 applyToEnvironment
函式來定義它應該套用至哪些環境。
const UnoCssPlugin = () => {
// shared global state
return {
buildStart() {
// init per environment state with WeakMap<Environment,Data>
// using this.environment
},
configureServer() {
// use global hooks normally
},
applyToEnvironment(environment) {
// return true if this plugin should be active in this environment,
// or return a new plugin to replace it.
// if the hook is not used, the plugin is active in all environments
},
resolveId(id, importer) {
// only called for environments this plugin apply to
},
}
}
如果外掛沒有環境意識,而且其狀態未以目前的環境做為索引鍵,則 applyToEnvironment
鉤子允許輕鬆地使其成為每個環境的外掛。
import { nonShareablePlugin } from 'non-shareable-plugin'
export default defineConfig({
plugins: [
{
name: 'per-environment-plugin',
applyToEnvironment(environment) {
return nonShareablePlugin({ outputName: environment.name })
},
},
],
})
Vite 會匯出 perEnvironmentPlugin
協助程式,以簡化這些不需要其他鉤子的情況
import { nonShareablePlugin } from 'non-shareable-plugin'
export default defineConfig({
plugins: [
perEnvironmentPlugin('per-environment-plugin', (environment) =>
nonShareablePlugin({ outputName: environment.name }),
),
],
})
建置鉤子中的環境
就像在開發期間一樣,外掛鉤子也會在建置期間接收環境實例,取代 ssr
布林值。這也適用於 renderChunk
、generateBundle
和其他僅限建置的鉤子。
建置期間共用的外掛
在 Vite 6 之前,外掛管道在開發期間和建置期間以不同的方式運作
- 在開發期間:外掛會共用
- 在建置期間:外掛會針對每個環境隔離(在不同的程序中:
vite build
,然後是vite build --ssr
)。
這迫使框架在 client
建置和 ssr
建置之間,透過寫入檔案系統的資訊清單檔案來共用狀態。在 Vite 6 中,我們現在在單一程序中建置所有環境,因此外掛管道和環境間通訊的方式可以與開發對齊。
在未來的主要版本(Vite 7 或 8)中,我們的目標是完全對齊
- 在開發和建置期間:外掛會共用,並具有每個環境的篩選
在建置期間也會共用單一的 ResolvedConfig
實例,允許在整個應用程式建置程序層級進行快取,就像我們在開發期間使用 WeakMap<ResolvedConfig, CachedData>
所做的一樣。
對於 Vite 6,我們需要採取較小的步驟來保持回溯相容性。生態系統外掛目前使用 config.build
而不是 environment.config.build
來存取設定,因此我們需要預設針對每個環境建立新的 ResolvedConfig
。專案可以選擇加入共用完整的設定和外掛管道,將 builder.sharedConfigBuild
設定為 true
。
此選項起初只會適用於一小部分的專案,因此外掛作者可以選擇加入,以透過將 sharedDuringBuild
旗標設定為 true
來共用特定外掛。這允許輕鬆地共用一般外掛的狀態
function myPlugin() {
// Share state among all environments in dev and build
const sharedState = ...
return {
name: 'shared-plugin',
transform(code, id) { ... },
// Opt-in into a single instance for all environments
sharedDuringBuild: true,
}
}