Skip to content

Commit

Permalink
feat: only shared plugins (#17289)
Browse files Browse the repository at this point in the history
  • Loading branch information
patak-dev authored May 23, 2024
1 parent d86553a commit e36f2f3
Show file tree
Hide file tree
Showing 9 changed files with 46 additions and 101 deletions.
53 changes: 18 additions & 35 deletions docs/guide/api-vite-environment.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ class DevEnvironment {
* Resolved plugins for this environment, including the ones
* created using the per-environment `create` hook
*/
plugins: EnvironmentPlugin[]
plugins: Plugin[]
/**
* Allows to resolve, load, and transform code through the
* environment plugins pipeline
Expand Down Expand Up @@ -579,19 +579,25 @@ The hook can choose to:
### Per-environment Plugins
A plugin can now also be a constructor to lazily create per-environment plugins.
A plugin can define what are the environments it should apply to with the `applyToEnvironment` function.
```js
function perEnvironmentPlugin() {
return (environment: Environment) => {
// Return a plugin, an array, a Promise, or a falsy value for each environment
if (!passesCondition(environment)) {
return undefined
}
return [
createEnvironmentPlugin(environment),
otherPlugin(environment)
]
const UnoCssPlugin = () => {
// shared global state
return {
buildStart() {
// init per environment state with WeakMap<Environment,Data>, this.environment
},
configureServer() {
// use global hooks normally
},
applyToEnvironment(environment) {
// return true if this plugin should be active in this environment
// if the function isn't provided, the plugin is active in all environments
},
resolveId(id, importer) {
// only called for environments this plugin apply to
},
}
}
```
Expand Down Expand Up @@ -881,29 +887,6 @@ function myPlugin() {
}
```
And for per-environment plugins:
```js
function myPlugin() {
// Share state among all environments in dev and build
const sharedState = ...

return {
name: 'with-environment-plugins',
environmentPlugins(environment) {
// Isolated state for each environment during dev and build
const isolatedState = ...
return {
name: 'per-environment-plugin',
transform(code, id) { ... },
}
},
// Opt-in into a single instance for all environments
sharedDuringBuild: true
}
}
```
## Backward Compatibility
The current Vite server API will be deprecated but keep working during the next major.
Expand Down
12 changes: 6 additions & 6 deletions packages/vite/src/node/__tests_dts__/plugin.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,38 @@
/**
* This is a developement only file for testing types.
* This is a development only file for testing types.
*/
import type { Plugin as RollupPlugin } from 'rollup'
import type { Equal, ExpectExtends, ExpectTrue } from '@type-challenges/utils'
import type { EnvironmentPlugin, PluginContextExtension } from '../plugin'
import type { Plugin, PluginContextExtension } from '../plugin'
import type { ROLLUP_HOOKS } from '../constants'
import type {
GetHookContextMap,
NonNeverKeys,
RollupPluginHooks,
} from '../typeUtils'

type EnvironmentPluginHooksContext = GetHookContextMap<EnvironmentPlugin>
type EnvironmentPluginHooksContext = GetHookContextMap<Plugin>
type EnvironmentPluginHooksContextMatched = {
[K in keyof EnvironmentPluginHooksContext]: EnvironmentPluginHooksContext[K] extends PluginContextExtension
? never
: false
}

type HooksMissingExtension = NonNeverKeys<EnvironmentPluginHooksContextMatched>
type HooksMissingInConstans = Exclude<
type HooksMissingInConstants = Exclude<
RollupPluginHooks,
(typeof ROLLUP_HOOKS)[number]
>

export type cases = [
// Ensure environment plugin hooks are superset of rollup plugin hooks
ExpectTrue<ExpectExtends<RollupPlugin, EnvironmentPlugin>>,
ExpectTrue<ExpectExtends<RollupPlugin, Plugin>>,

// Ensure all Rollup hooks have Vite's plugin context extension
ExpectTrue<Equal<HooksMissingExtension, never>>,

// Ensure the `ROLLUP_HOOKS` constant is up-to-date
ExpectTrue<Equal<HooksMissingInConstans, never>>,
ExpectTrue<Equal<HooksMissingInConstants, never>>,
]

export {}
6 changes: 3 additions & 3 deletions packages/vite/src/node/baseEnvironment.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import colors from 'picocolors'
import type { Logger } from './logger'
import type { ResolvedConfig, ResolvedEnvironmentOptions } from './config'
import type { EnvironmentPlugin } from './plugin'
import type { Plugin } from './plugin'

export class PartialEnvironment {
name: string
Expand Down Expand Up @@ -61,7 +61,7 @@ export class PartialEnvironment {
}

export class BaseEnvironment extends PartialEnvironment {
get plugins(): EnvironmentPlugin[] {
get plugins(): Plugin[] {
if (!this._plugins)
throw new Error(
`${this.name} environment.plugins called before initialized`,
Expand All @@ -72,7 +72,7 @@ export class BaseEnvironment extends PartialEnvironment {
/**
* @internal
*/
_plugins: EnvironmentPlugin[] | undefined
_plugins: Plugin[] | undefined
/**
* @internal
*/
Expand Down
3 changes: 2 additions & 1 deletion packages/vite/src/node/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1480,12 +1480,13 @@ export class BuildEnvironment extends BaseEnvironment {
super(name, config, options)
}

// TODO: This could be sync, discuss if applyToEnvironment should support async
async init(): Promise<void> {
if (this._initiated) {
return
}
this._initiated = true
this._plugins = await resolveEnvironmentPlugins(this)
this._plugins = resolveEnvironmentPlugins(this)
}
}

Expand Down
8 changes: 1 addition & 7 deletions packages/vite/src/node/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,7 @@ export type {
DevEnvironmentOptions,
ResolvedDevEnvironmentOptions,
} from './config'
export type {
EnvironmentPlugin,
Plugin,
EnvironmentPluginOptionArray,
PluginOption,
HookHandler,
} from './plugin'
export type { Plugin, PluginOption, HookHandler } from './plugin'
export type { FilterPattern } from './utils'
export type { CorsOptions, CorsOrigin, CommonServerOptions } from './http'
export type {
Expand Down
2 changes: 1 addition & 1 deletion packages/vite/src/node/optimizer/scan.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export class ScanEnvironment extends BaseEnvironment {
return
}
this._initiated = true
this._plugins = await resolveEnvironmentPlugins(this)
this._plugins = resolveEnvironmentPlugins(this)
this._pluginContainer = await createEnvironmentPluginContainer(
this,
this.plugins,
Expand Down
57 changes: 12 additions & 45 deletions packages/vite/src/node/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ declare module 'rollup' {
* Environment Plugins are closer to regular rollup plugins. They can't define
* app level hooks (like config, configResolved, configureServer, etc).
*/
export interface EnvironmentPlugin<A = any> extends RollupPlugin<A> {
export interface Plugin<A = any> extends RollupPlugin<A> {
/**
* Perform custom handling of HMR updates.
* The handler receives a context containing changed filename, timestamp, a
Expand Down Expand Up @@ -161,9 +161,6 @@ export interface EnvironmentPlugin<A = any> extends RollupPlugin<A> {
},
) => Promise<TransformResult> | TransformResult
>
}

export interface Plugin<A = any> extends EnvironmentPlugin<A> {
/**
* Opt-in this plugin into the shared plugins pipeline.
* For backward-compatibility, plugins are re-recreated for each environment
Expand Down Expand Up @@ -194,6 +191,11 @@ export interface Plugin<A = any> extends EnvironmentPlugin<A> {
| 'serve'
| 'build'
| ((this: void, config: UserConfig, env: ConfigEnv) => boolean)
/**
* Define environments where this plugin should be active
* By default, the plugin is active in all environments
*/
applyToEnvironment?: (environment: Environment) => boolean
/**
* Modify vite config before it's resolved. The hook can either mutate the
* passed-in config directly, or return a partial config object that will be
Expand Down Expand Up @@ -277,12 +279,6 @@ export interface Plugin<A = any> extends EnvironmentPlugin<A> {
* `{ order: 'pre', handler: hook }`
*/
transformIndexHtml?: IndexHtmlTransform
/**
* Inject per environment plugins after the shared plugin
*/
environmentPlugins?: (
environment: Environment,
) => EnvironmentPluginOptionArray

/**
* @deprecated
Expand All @@ -304,43 +300,14 @@ export type PluginWithRequiredHook<K extends keyof Plugin> = Plugin & {
}

type Thenable<T> = T | Promise<T>
type FalsyPlugin = false | null | undefined

export type EnvironmentPluginOption = Thenable<
EnvironmentPlugin | FalsyPlugin | EnvironmentPluginOption[]
>

export type EnvironmentPluginOptionArray = Thenable<
EnvironmentPluginOption[] | FalsyPlugin
>
type FalsyPlugin = false | null | undefined

export type PluginOption = Thenable<Plugin | FalsyPlugin | PluginOption[]>

export async function resolveEnvironmentPlugins(
environment: Environment,
): Promise<EnvironmentPlugin[]> {
const resolvedPlugins: EnvironmentPlugin[] = []
for (const plugin of environment.config.plugins) {
resolvedPlugins.push(plugin)
if (plugin.environmentPlugins) {
const environmentPlugins = await plugin.environmentPlugins(environment)
if (environmentPlugins) {
const newPlugins =
await asyncFlattenEnvironmentPlugins(environmentPlugins)
resolvedPlugins.push(...newPlugins)
}
}
}
return resolvedPlugins
}

async function asyncFlattenEnvironmentPlugins(
plugins: EnvironmentPluginOption[],
): Promise<EnvironmentPlugin[]> {
do {
plugins = ((await Promise.all(plugins)) as any[])
.flat(Infinity)
.filter(Boolean) as EnvironmentPluginOption[]
} while (plugins.some((v: any) => v?.then))
return plugins as EnvironmentPlugin[]
export function resolveEnvironmentPlugins(environment: Environment): Plugin[] {
return environment.config.plugins.filter(
(plugin) =>
!plugin.applyToEnvironment || plugin.applyToEnvironment(environment),
)
}
2 changes: 1 addition & 1 deletion packages/vite/src/node/server/environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ export class DevEnvironment extends BaseEnvironment {
return
}
this._initiated = true
this._plugins = await resolveEnvironmentPlugins(this)
this._plugins = resolveEnvironmentPlugins(this)
this._pluginContainer = await createEnvironmentPluginContainer(
this,
this._plugins,
Expand Down
4 changes: 2 additions & 2 deletions packages/vite/src/node/server/pluginContainer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ import { TraceMap, originalPositionFor } from '@jridgewell/trace-mapping'
import MagicString from 'magic-string'
import type { FSWatcher } from 'chokidar'
import colors from 'picocolors'
import type { EnvironmentPlugin, Plugin } from '../plugin'
import type { Plugin } from '../plugin'
import {
combineSourcemaps,
createDebugger,
Expand Down Expand Up @@ -149,7 +149,7 @@ type PluginContext = Omit<
*/
export async function createEnvironmentPluginContainer(
environment: Environment,
plugins: EnvironmentPlugin[],
plugins: Plugin[],
watcher?: FSWatcher,
): Promise<EnvironmentPluginContainer> {
const {
Expand Down

0 comments on commit e36f2f3

Please sign in to comment.