Skip to content

definePlugin

definePlugin allows you to create custom type-safe plugins that can extend integration hooks with additional parameters and functionality. This is an advanced utility for creating reusable plugin components that can be shared across multiple integrations or distributed as third-party packages.

For more practical examples of how to create your own plugins, check out the built-in plugins source code in the Astro Integration Kit repository.

When you use definePlugin, it:

  • Defines a named plugin: Creates a plugin with a specific name that can be used across multiple integrations
  • Sets up hook extensions: The setup() function defines which hooks the plugin extends and what additional parameters it provides
  • Provides type safety: Ensures that the additional parameters are properly typed and available in your integration hooks
  • Enables reusability: Allows the same plugin logic to be shared across different integrations
  1. Define your plugin

    Create a plugin with a unique name and setup function:

    definePlugin({
    name: "my-plugin",
    setup({ name }) {
    return {
    "astro:config:setup": (hookParams) => ({
    // Additional parameters to provide to this hook
    myUtility: (value: string) => {
    // Plugin implementation
    }
    })
    }
    }
    })
  2. Use it in your integration

    Add the plugin to your integration using withPlugins:

    export default defineIntegration({
    name: "my-integration",
    setup({ name }) {
    return withPlugins({
    name,
    plugins: [myPlugin],
    hooks: {
    "astro:config:setup": ({ myUtility }) => {
    // Use the plugin's functionality
    myUtility("some value");
    }
    }
    })
    }
    })

defineAllHooksPlugin is a variation of definePlugin that provides the same API across all Astro hooks. This is useful when you want to create a plugin that works with any hook, including future hooks or hooks added by other integrations.

Use defineAllHooksPlugin when:

  • Your plugin should work with any Astro hook
  • You want to support hooks added by other integrations (like @astrojs/db)
  • You want your plugin to be forward-compatible with future Astro versions

Instead of mapping specific hooks, you provide a factory function that receives the hook name:

defineAllHooksPlugin({
name: "my-plugin",
setup({ name }) {
return (hookName) => (hookParameters) => ({
doSomething: () => {
console.log(`Called from ${hookName} hook`);
}
});
}
})

When multiple plugins with the same name are provided, withPlugins automatically deduplicates them by keeping only the last occurrence. This prevents conflicts and ensures predictable behavior.

return withPlugins({
name,
plugins: [pluginA, pluginB, pluginA], // Only the last pluginA is kept
hooks: { /* ... */ }
})

Here’s a complete example of the built-in hasVitePlugin plugin to demonstrate real-world usage:

  1. Define the plugin

    package/plugins/has-vite-plugin.ts
    import type { AstroConfig } from "astro";
    import type { Plugin, PluginOption } from "vite";
    import { definePlugin } from "astro-integration-kit";
    import { hasVitePlugin, getPlugins } from "../utilities/has-vite-plugin.js";
    export const hasVitePluginPlugin = definePlugin({
    name: "hasVitePlugin",
    setup() {
    return {
    "astro:config:setup": (params) => {
    const currentPlugins = getPlugins(
    new Set(),
    params.config.vite?.plugins,
    );
    const { updateConfig, config } = params;
    params.updateConfig = (newConfig) => {
    config.vite.plugins = Array.from(
    getPlugins(currentPlugins, newConfig.vite?.plugins),
    );
    return updateConfig(newConfig);
    };
    return {
    hasVitePlugin: (plugin: string | PluginOption) =>
    hasVitePlugin(params, {
    plugin,
    }),
    };
    },
    };
    },
    });
  2. Use in integration

    my-integration/index.ts
    import { defineIntegration, withPlugins } from "astro-integration-kit";
    import { hasVitePluginPlugin } from "astro-integration-kit/plugins";
    export default defineIntegration({
    name: "my-integration",
    setup({ name }) {
    return withPlugins({
    name,
    plugins: [hasVitePluginPlugin],
    hooks: {
    "astro:config:setup": ({ hasVitePlugin }) => {
    // hasVitePlugin is provided by the hasVitePluginPlugin
    if (hasVitePlugin("some-plugin-name")) {
    // Plugin already exists
    }
    }
    }
    })
    }
    })