Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/guide/api-environment-plugins.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ The hook can choose to:

## Per-environment State in Plugins

Given that the same plugin instance is used for different environments, the plugin state needs to be keyed with `this.environment`. This is the same pattern the ecosystem has already been using to keep state about modules using the `ssr` boolean as key to avoid mixing client and ssr modules state. A `Map<Environment, State>` can be used to keep the state for each environment separately. Note that for backward compatibility, `buildStart` and `buildEnd` are only called for the client environment without the `perEnvironmentStartEndDuringDev: true` flag.
Given that the same plugin instance is used for different environments, the plugin state needs to be keyed with `this.environment`. This is the same pattern the ecosystem has already been using to keep state about modules using the `ssr` boolean as key to avoid mixing client and ssr modules state. A `Map<Environment, State>` can be used to keep the state for each environment separately. Note that for backward compatibility, `buildStart` and `buildEnd` are only called for the client environment without the `perEnvironmentStartEndDuringDev: true` flag. Same for `watchChange` and the `perEnvironmentWatchChangeDuringDev: true` flag.

```js
function PerEnvironmentCountTransformedModulesPlugin() {
Expand Down
8 changes: 8 additions & 0 deletions packages/vite/src/node/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,14 @@ export interface Plugin<A = any> extends RollupPlugin<A> {
* @experimental
*/
perEnvironmentStartEndDuringDev?: boolean
/**
* Opt-in this plugin into per-environment watchChange during dev.
* For backward-compatibility, the watchChange hook is called only once during
* dev, for the client environment. Plugins can opt-in to be called
* per-environment, aligning with the watchChange hook behavior.
* @experimental
*/
perEnvironmentWatchChangeDuringDev?: boolean
/**
* Enforce plugin invocation tier similar to webpack loaders. Hooks ordering
* is still subject to the `order` property in the hook object.
Expand Down
28 changes: 22 additions & 6 deletions packages/vite/src/node/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,12 +174,19 @@ export interface ServerOptions extends CommonServerOptions {
| false
| ((sourcePath: string, sourcemapPath: string) => boolean)
/**
* Backward compatibility. The buildStart and buildEnd hooks were called only once for all
* environments. This option enables per-environment buildStart and buildEnd hooks.
* Backward compatibility. The buildStart and buildEnd hooks were called only once for
* the client environment. This option enables per-environment buildStart and buildEnd hooks.
* @default false
* @experimental
*/
perEnvironmentStartEndDuringDev?: boolean
/**
* Backward compatibility. The watchChange hook was called only once for the client environment.
* This option enables per-environment watchChange hooks.
* @default false
* @experimental
*/
perEnvironmentWatchChangeDuringDev?: boolean
/**
* Run HMR tasks, by default the HMR propagation is done in parallel for all environments
* @experimental
Expand Down Expand Up @@ -802,9 +809,13 @@ export async function _createServer(
file = normalizePath(file)
reloadOnTsconfigChange(server, file)

await pluginContainer.watchChange(file, {
event: isUnlink ? 'delete' : 'create',
})
await Promise.all(
Object.values(server.environments).map((environment) =>
environment.pluginContainer.watchChange(file, {
event: isUnlink ? 'delete' : 'create',
}),
),
)

if (publicDir && publicFiles) {
if (file.startsWith(publicDir)) {
Expand Down Expand Up @@ -836,7 +847,11 @@ export async function _createServer(
file = normalizePath(file)
reloadOnTsconfigChange(server, file)

await pluginContainer.watchChange(file, { event: 'update' })
await Promise.all(
Object.values(server.environments).map((environment) =>
environment.pluginContainer.watchChange(file, { event: 'update' }),
),
)
// invalidate module graph cache on file change
for (const environment of Object.values(server.environments)) {
environment.moduleGraph.onFileChange(file)
Expand Down Expand Up @@ -1104,6 +1119,7 @@ const _serverConfigDefaults = Object.freeze({
preTransformRequests: true,
// sourcemapIgnoreList
perEnvironmentStartEndDuringDev: false,
perEnvironmentWatchChangeDuringDev: false,
// hotUpdateEnvironments
} satisfies ServerOptions)
export const serverConfigDefaults: Readonly<Partial<ServerOptions>> =
Expand Down
8 changes: 7 additions & 1 deletion packages/vite/src/node/server/pluginContainer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -607,10 +607,15 @@ class EnvironmentPluginContainer<Env extends Environment = Environment> {
id: string,
change: { event: 'create' | 'update' | 'delete' },
): Promise<void> {
const config = this.environment.getTopLevelConfig()
await this.hookParallel(
'watchChange',
(plugin) => this._getPluginContext(plugin),
() => [id, change],
(plugin) =>
this.environment.name === 'client' ||
config.server.perEnvironmentWatchChangeDuringDev ||
plugin.perEnvironmentWatchChangeDuringDev,
)
}

Expand Down Expand Up @@ -1211,7 +1216,8 @@ class PluginContainer {
}

// For backward compatibility, buildStart and watchChange are called only for the client environment
// buildStart is called per environment for a plugin with the perEnvironmentStartEndDuring dev flag
// buildStart is called per environment for a plugin with the perEnvironmentStartEndDuringDev flag
// watchChange is called per environment for a plugin with the perEnvironmentWatchChangeDuringDev flag

async buildStart(_options?: InputOptions): Promise<void> {
return (
Expand Down