Skip to content

defineIntegration

defineIntegration is a powerful wrapper around the standard Astro Integrations API. It allows integration authors to handle user options and global logic easily.

my-integration/index.ts
1
import { defineIntegration, addDts } from "astro-integration-kit"
2
import { z } from "astro/zod"
3
4
export default defineIntegration({
5
name: "my-integration",
6
optionsSchema: z.object({
7
virtualModuleId: z.string()
8
}),
9
setup({ options, name }) {
10
return {
11
hooks: {
12
"astro:config:setup": (params) => {
13
addDts(params, {
14
name,
15
content: `declare module ${JSON.stringify(options.virtualModuleId)} {}`
16
})
17
}
18
}
19
}
20
}
21
})

Defining an integration

To define an integration, use the defineIntegration utility:

my-integration/index.ts
1
import { defineIntegration } from "astro-integration-kit";
2
3
export default defineIntegration({
4
// ...
5
name: "my-integration"
6
})

It accepts a few arguments, whose usage is explained in the sections below.

Handling options and defaults

defineIntegration accepts an optionsSchema argument that is a zod schema.

my-integration/index.ts
1
import { defineIntegration } from "astro-integration-kit";
2
import { z } from "astro/zod";
3
4
export default defineIntegration({
5
// ...
6
optionsSchema: z.object({
7
/**
8
* A comment
9
*
10
* @default `"bar"`
11
*/
12
foo: z.string().optional().default("bar"),
13
}),
14
})

This way, you can:

  • Add proper documentation using JSDoc annotations
  • Provide defaults
  • Well, take full advantage of zod’s power!

Adding the logic with setup

If you’ve written an integration before by returning an AstroIntegration from a function, it’s exactly the same with setup! This is where all the logic lives:

my-integration/index.ts
1
import { defineIntegration } from "astro-integration-kit";
2
3
export default defineIntegration({
4
// ...
5
setup() {
6
return {hooks: {}}
7
}
8
})

It accepts an object with data from the integration definition:

my-integration/index.ts
1
import { defineIntegration } from "astro-integration-kit";
2
3
export default defineIntegration({
4
// ...
5
setup({ options, name }) {
6
return {hooks: {}}
7
}
8
})

In setup, you’ll want to add any logic that is shared between any hook, for example:

  • Calling createResolver
  • Save the config from astro:config:done to be used in later hooks

It needs to return Astro hooks.

Defining extra integration fields

Any extra property present on the return of setup will be present on the integration object returned by initializing the integration with the options.

You can use this to define fields you might want to access from outside your integration while having access to it’s internal state.

my-integration.ts
1
import { defineIntegration } from "astro-integration-kit";
2
3
export default defineIntegration({
4
// ...
5
setup() {
6
let counter = 0;
7
return {
8
hooks: {
9
"astro:config:setup": ({ logger }) => {
10
logger.info(`Counter: ${counter++}`);
11
},
12
},
13
api: {
14
get counter() {
15
return counter;
16
},
17
increment() {
18
counter++;
19
},
20
},
21
};
22
},
23
});
1
import { defineConfig } from "astro/config";
2
import myIntegration from "./my-integration";
3
4
const integration = myIntegration();
5
6
console.log(myIntegration.api.counter); // 0
7
8
myIntegration.api.increment();
9
10
console.log(myIntegration.api.counter); // 1
11
12
export default defineConfig({
13
// Will log "Counter: 1" during setup
14
integrations: [myIntegration],
15
});