diff options
| author | 2023-09-27 21:17:27 +0200 | |
|---|---|---|
| committer | 2023-09-27 21:17:27 +0200 | |
| commit | 9b0114c7d3f82914f4443c865ac38d5859fbbceb (patch) | |
| tree | 70f0cf2a80f0d604d8b11a5708b5131a5ba1fd7b | |
| parent | e8495c853b0fad805173783b5260ab9fb9def2f0 (diff) | |
| download | astro-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.md | 34 | ||||
| -rw-r--r-- | packages/astro/src/integrations/index.ts | 5 | ||||
| -rw-r--r-- | packages/astro/test/units/integrations/api.test.js | 58 | 
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 () { | 
