import type * as rolldown from "rolldown"; import type * as vite from "vite"; import { isSkippedEnvironment, type BasePluginOptions } from "./options.js"; export interface PluginInput { shared?: Omit, "name">; rolldown?: Omit, "name">; vite?: Omit, "name">; } export interface NullablePluginOutput { rolldown: (options: BasePluginOptions) => rolldown.Plugin | null; vite: (options: BasePluginOptions) => vite.Plugin | null; } export interface PluginOutput { rolldown: (options: BasePluginOptions) => rolldown.Plugin; vite: (options: BasePluginOptions) => vite.Plugin; } export function createPlugin( pluginName: TName, make: (options: BasePluginOptions) => PluginInput, ): PluginOutput; export function createPlugin( pluginName: TName, make: (options: BasePluginOptions) => PluginInput | undefined, ): NullablePluginOutput; export function createPlugin( pluginName: TName, make: (options: BasePluginOptions) => PluginInput | undefined, ): PluginOutput | NullablePluginOutput { const name = `distilled-cloudflare:${pluginName}`; return { rolldown: (options: BasePluginOptions) => { const plugin = make(options); if (!plugin) return null; return { name, ...plugin.shared, ...plugin.rolldown, }; }, vite: (options: BasePluginOptions) => { const plugin = make(options); if (!plugin) return null; const vitePlugin = { name, sharedDuringBuild: true, ...plugin.shared, ...plugin.vite, } as vite.Plugin; // Scope every per-environment hook (resolveId/load/transform/...) away // from the browser `client` environment and any framework-owned // Node-side environments listed in `skipEnvironments` (e.g. Astro's // `astro` and `prerender` environments). const applyToEnvironment = vitePlugin.applyToEnvironment; vitePlugin.applyToEnvironment = function (environment) { if (isSkippedEnvironment(options, environment.name)) return false; return applyToEnvironment ? applyToEnvironment.call(this, environment) : true; }; // `applyToEnvironment` only gates the per-environment plugin pipeline; // `configEnvironment` runs during config resolution for every // environment, so skipped environments must be filtered explicitly. const configEnvironment = vitePlugin.configEnvironment; if (configEnvironment && options.skipEnvironments?.length) { const handler = typeof configEnvironment === "function" ? configEnvironment : configEnvironment.handler; const wrapped: typeof handler = function (environmentName, ...args) { if (options.skipEnvironments?.includes(environmentName)) return; return handler.call(this, environmentName, ...args); }; vitePlugin.configEnvironment = typeof configEnvironment === "function" ? wrapped : { ...configEnvironment, handler: wrapped }; } return vitePlugin; }, }; }