summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Chris Swithinbank <swithinbank@gmail.com> 2023-09-27 21:17:27 +0200
committerGravatar GitHub <noreply@github.com> 2023-09-27 21:17:27 +0200
commit9b0114c7d3f82914f4443c865ac38d5859fbbceb (patch)
tree70f0cf2a80f0d604d8b11a5708b5131a5ba1fd7b
parente8495c853b0fad805173783b5260ab9fb9def2f0 (diff)
downloadastro-9b0114c7d3f82914f4443c865ac38d5859fbbceb.tar.gz
astro-9b0114c7d3f82914f4443c865ac38d5859fbbceb.tar.zst
astro-9b0114c7d3f82914f4443c865ac38d5859fbbceb.zip
Support integrations added in updateConfig() in astro:config:setup (#8672)
Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca>
-rw-r--r--.changeset/cold-schools-yell.md34
-rw-r--r--packages/astro/src/integrations/index.ts5
-rw-r--r--packages/astro/test/units/integrations/api.test.js58
3 files changed, 95 insertions, 2 deletions
diff --git a/.changeset/cold-schools-yell.md b/.changeset/cold-schools-yell.md
new file mode 100644
index 000000000..7d6b4f381
--- /dev/null
+++ b/.changeset/cold-schools-yell.md
@@ -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 Astro’s 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 wasn’t found, add it.
+ updateConfig({
+ integrations: [sitemap({ /* opts */ }],
+ });
+ }
+ },
+ };
+};
+```
diff --git a/packages/astro/src/integrations/index.ts b/packages/astro/src/integrations/index.ts
index c5c92a4e4..8d557cae7 100644
--- a/packages/astro/src/integrations/index.ts
+++ b/packages/astro/src/integrations/index.ts
@@ -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
diff --git a/packages/astro/test/units/integrations/api.test.js b/packages/astro/test/units/integrations/api.test.js
index 0a7d57929..0940a78f7 100644
--- a/packages/astro/test/units/integrations/api.test.js
+++ b/packages/astro/test/units/integrations/api.test.js
@@ -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 () {