Support integrations added in updateConfig() in astro:config:setup (#8672)

Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca>
This commit is contained in:
Chris Swithinbank 2023-09-27 21:17:27 +02:00 committed by GitHub
parent e8495c853b
commit 9b0114c7d3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 95 additions and 2 deletions

View file

@ -0,0 +1,34 @@
---
'astro': minor
---
Support adding integrations dynamically
Astro integrations can now themselves dynamically add and configure additional integrations during set-up. This makes it possible for integration authors to bundle integrations more intelligently for their users.
In the following example, a custom integration checks whether `@astrojs/sitemap` is already configured. If not, the integration adds Astros sitemap integration, passing any desired configuration options:
```ts
import sitemap from '@astrojs/sitemap';
import type { AstroIntegration } from 'astro';
const MyIntegration = (): AstroIntegration => {
return {
name: 'my-integration',
'astro:config:setup': ({ config, updateConfig }) => {
// Look for sitemap in user-configured integrations.
const userSitemap = config.integrations.find(
({ name }) => name === '@astrojs/sitemap'
);
if (!userSitemap) {
// If sitemap wasnt found, add it.
updateConfig({
integrations: [sitemap({ /* opts */ }],
});
}
},
};
};
```

View file

@ -75,7 +75,10 @@ export async function runHookConfigSetup({
let addedClientDirectives = new Map<string, Promise<string>>();
let astroJSXRenderer: AstroRenderer | null = null;
for (const integration of settings.config.integrations) {
// eslint-disable-next-line @typescript-eslint/prefer-for-of -- We need a for loop to be able to read integrations pushed while the loop is running.
for (let i = 0; i < updatedConfig.integrations.length; i++) {
const integration = updatedConfig.integrations[i];
/**
* By making integration hooks optional, Astro can now ignore null or undefined Integrations
* instead of giving an internal error most people can't read

View file

@ -1,5 +1,5 @@
import { expect } from 'chai';
import { runHookBuildSetup } from '../../../dist/integrations/index.js';
import { runHookBuildSetup, runHookConfigSetup } from '../../../dist/integrations/index.js';
import { validateSupportedFeatures } from '../../../dist/integrations/astroFeaturesValidation.js';
import { defaultLogger } from '../test-utils.js';
@ -29,6 +29,62 @@ describe('Integration API', () => {
});
expect(updatedViteConfig).to.haveOwnProperty('define');
});
it('runHookConfigSetup can update Astro config', async () => {
const site = 'https://test.com/';
const updatedSettings = await runHookConfigSetup({
logger: defaultLogger,
settings: {
config: {
integrations: [
{
name: 'test',
hooks: {
"astro:config:setup": ({ updateConfig }) => {
updateConfig({ site });
}
},
},
],
},
},
});
expect(updatedSettings.config.site).to.equal(site);
});
it('runHookConfigSetup runs integrations added by another integration', async () => {
const site = 'https://test.com/';
const updatedSettings = await runHookConfigSetup({
logger: defaultLogger,
settings: {
config: {
integrations: [
{
name: 'test',
hooks: {
"astro:config:setup": ({ updateConfig }) => {
updateConfig({
integrations: [{
name: 'dynamically-added',
hooks: {
// eslint-disable-next-line @typescript-eslint/no-shadow
"astro:config:setup": ({ updateConfig }) => {
updateConfig({ site });
}
},
}],
});
}
},
},
],
},
},
});
expect(updatedSettings.config.site).to.equal(site);
expect(updatedSettings.config.integrations.length).to.equal(2);
});
});
describe('Astro feature map', function () {