Skip to content

Commit

Permalink
feat: extended applyToEnvironment and perEnvironmentPlugin
Browse files Browse the repository at this point in the history
  • Loading branch information
patak-dev committed Oct 31, 2024
1 parent d002e7d commit bf389be
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 38 deletions.
32 changes: 31 additions & 1 deletion docs/guide/api-environment-plugins.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,8 @@ const UnoCssPlugin = () => {
// use global hooks normally
},
applyToEnvironment(environment) {
// return true if this plugin should be active in this environment
// return true if this plugin should be active in this environment, or return
// a new plugin to replace it.
// if the function isn't provided, the plugin is active in all environments
},
resolveId(id, importer) {
Expand All @@ -151,6 +152,35 @@ const UnoCssPlugin = () => {
}
```
If a plugin isn't environment aware and has state that isn't keyed on the current environment (as it is common in Rollup build plugins like `rollup-plugin-visualizer`), the `applyToEnvironment` hook allows to easily make it per-environment.
```js
import { visualizer } from 'rollup-plugin-visualizer'

export default defineConfig({
plugins: [
{
name: 'per-environment-visualizer',
applyToEnvironment() {
return visualizer()
},
},
],
})
```
Vite exports a `perEnvironmentPlugin` helper to simplify these cases where no other hooks are required:
```js
import { visualizer } from 'rollup-plugin-visualizer'

export default defineConfig({
plugins: [
perEnvironmentPlugin('per-environment-visualizer', () => visualizer()),
],
})
```
## Environment in build hooks
In the same way as during dev, plugin hooks also receive the environment instance during build, replacing the `ssr` boolean.
Expand Down
45 changes: 18 additions & 27 deletions packages/vite/src/node/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ import {
normalizePath,
partialEncodeURIPath,
} from './utils'
import { resolveEnvironmentPlugins } from './plugin'
import { perEnvironmentPlugin, resolveEnvironmentPlugins } from './plugin'
import { manifestPlugin } from './plugins/manifest'
import type { Logger } from './logger'
import { dataURIPlugin } from './plugins/dataUri'
Expand Down Expand Up @@ -466,34 +466,26 @@ export async function resolveBuildPlugins(config: ResolvedConfig): Promise<{
pre: Plugin[]
post: Plugin[]
}> {
const { commonjsOptions } = config.build
const usePluginCommonjs =
!Array.isArray(commonjsOptions.include) ||
commonjsOptions.include.length !== 0
return {
pre: [
completeSystemWrapPlugin(),
/**
* environment.config.build.commonjsOptions isn't currently supported
* when builder.sharedConfigBuild or builder.sharedPlugins enabled.
* To do it, we could inject one commonjs plugin per environment with
* an applyToEnvironment hook.
*/
...(usePluginCommonjs ? [commonjsPlugin(commonjsOptions)] : []),
perEnvironmentPlugin('commonjs', (environment) => {
const { commonjsOptions } = environment.config.build
const usePluginCommonjs =
!Array.isArray(commonjsOptions.include) ||
commonjsOptions.include.length !== 0
return usePluginCommonjs ? commonjsPlugin(commonjsOptions) : false
}),
dataURIPlugin(),
/**
* environment.config.build.rollupOptions.plugins isn't supported
* when builder.sharedConfigBuild or builder.sharedPlugins is enabled.
* To do it, we should add all these plugins to the global pipeline, each with
* an applyToEnvironment hook. It is similar to letting the user add per
* environment plugins giving them a environment.config.plugins option that
* we decided against.
* For backward compatibility, we are still injecting the rollup plugins
* defined in the default root build options.
*/
...((
await asyncFlatten(arraify(config.build.rollupOptions.plugins))
).filter(Boolean) as Plugin[]),
perEnvironmentPlugin(
'vite:rollup-options-plugins',
async (environment) =>
(
await asyncFlatten(
arraify(environment.config.build.rollupOptions.plugins),
)
).filter(Boolean) as Plugin[],
),
...(config.isWorker ? [webWorkerPostPlugin()] : []),
],
post: [
Expand Down Expand Up @@ -1457,13 +1449,12 @@ 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 = resolveEnvironmentPlugins(this)
this._plugins = await resolveEnvironmentPlugins(this)
}
}

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 @@ -63,7 +63,7 @@ export class ScanEnvironment extends BaseEnvironment {
return
}
this._initiated = true
this._plugins = resolveEnvironmentPlugins(this)
this._plugins = await resolveEnvironmentPlugins(this)
this._pluginContainer = await createEnvironmentPluginContainer(
this,
this.plugins,
Expand Down
45 changes: 37 additions & 8 deletions packages/vite/src/node/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import type { HmrContext, HotUpdateOptions } from './server/hmr'
import type { DevEnvironment } from './server/environment'
import type { Environment } from './environment'
import type { PreviewServerHook } from './preview'
import { arraify, asyncFlatten } from './utils'

/**
* Vite plugins extends the Rollup plugin interface with a few extra
Expand Down Expand Up @@ -204,7 +205,9 @@ export interface Plugin<A = any> extends RollupPlugin<A> {
* Define environments where this plugin should be active
* By default, the plugin is active in all environments
*/
applyToEnvironment?: (environment: Environment) => boolean
applyToEnvironment?: (
environment: Environment,
) => boolean | Promise<boolean> | PluginOption
/**
* 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 @@ -324,11 +327,37 @@ type FalsyPlugin = false | null | undefined

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

export function resolveEnvironmentPlugins(environment: Environment): Plugin[] {
return environment
.getTopLevelConfig()
.plugins.filter(
(plugin) =>
!plugin.applyToEnvironment || plugin.applyToEnvironment(environment),
)
export async function resolveEnvironmentPlugins(
environment: Environment,
): Promise<Plugin[]> {
const environmentPlugins: Plugin[] = []
for (const plugin of environment.getTopLevelConfig().plugins) {
if (plugin.applyToEnvironment) {
const applied = await plugin.applyToEnvironment(environment)
if (!applied) {
continue
}
if (applied !== true) {
environmentPlugins.push(
...((await asyncFlatten(arraify(applied))).filter(
Boolean,
) as Plugin[]),
)
}
}
environmentPlugins.push(plugin)
}
return environmentPlugins
}

export function perEnvironmentPlugin(
name: string,
applyToEnvironment: (
environment: Environment,
) => boolean | Promise<boolean> | PluginOption,
): Plugin {
return {
name,
applyToEnvironment,
}
}
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 @@ -158,7 +158,7 @@ export class DevEnvironment extends BaseEnvironment {
return
}
this._initiated = true
this._plugins = resolveEnvironmentPlugins(this)
this._plugins = await resolveEnvironmentPlugins(this)
this._pluginContainer = await createEnvironmentPluginContainer(
this,
this._plugins,
Expand Down

0 comments on commit bf389be

Please sign in to comment.