Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(feat) return updated config in integration hooks #9013

Merged
merged 11 commits into from
Nov 30, 2023
5 changes: 5 additions & 0 deletions .changeset/wild-boats-wait.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'astro': patch
---

Returns updated config in integration hooks
bluwy marked this conversation as resolved.
Show resolved Hide resolved
10 changes: 9 additions & 1 deletion packages/astro/src/@types/astro.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2055,6 +2055,14 @@ export interface SSRLoadedRenderer extends AstroRenderer {
};
}

export type DeepPartial<T> = {
nerdoza marked this conversation as resolved.
Show resolved Hide resolved
[P in keyof T]?: T[P] extends (infer U)[]
? DeepPartial<U>[]
: T[P] extends object | undefined
? DeepPartial<T[P]>
: T[P];
};

export type HookParameters<
Hook extends keyof AstroIntegration['hooks'],
Fn = AstroIntegration['hooks'][Hook],
Expand All @@ -2069,7 +2077,7 @@ export interface AstroIntegration {
config: AstroConfig;
command: 'dev' | 'build' | 'preview';
isRestart: boolean;
updateConfig: (newConfig: Record<string, any>) => void;
updateConfig: (newConfig: DeepPartial<AstroConfig>) => AstroConfig;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This certainly is a lot better than before, but it could maybe give a false sense of safety. {} is technically Partial<URL>, for example.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be an edge case admittedly, and the runtime logic might actually handle it too. I'll take a closer look when I can, but I'm not blocking a merge.

addRenderer: (renderer: AstroRenderer) => void;
addWatchFile: (path: URL | string) => void;
injectScript: (stage: InjectedScriptStage, content: string) => void;
Expand Down
2 changes: 2 additions & 0 deletions packages/astro/src/integrations/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ export async function runHookConfigSetup({
},
updateConfig: (newConfig) => {
updatedConfig = mergeConfig(updatedConfig, newConfig) as AstroConfig;
return { ...updatedConfig };
},
injectRoute: (injectRoute) => {
updatedSettings.injectedRoutes.push(injectRoute);
Expand Down Expand Up @@ -360,6 +361,7 @@ export async function runHookBuildSetup({
target,
updateConfig: (newConfig) => {
updatedConfig = mergeConfig(updatedConfig, newConfig);
return { ...updatedConfig };
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this a spread? Does it need to be cloned?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's spread in the original declaration for updatedConfig, so I'm just maintaining consistency. The object is pretty deep so this feels like it should either be a true clone or a read-only object, but those both seem a bit outside the scope of this issue.

Ref:

let updatedConfig: AstroConfig = { ...settings.config };
let updatedSettings: AstroSettings = { ...settings, config: updatedConfig };
let addedClientDirectives = new Map<string, Promise<string>>();
let astroJSXRenderer: AstroRenderer | null = null;

},
logger: getLogger(integration, logger),
}),
Expand Down
27 changes: 27 additions & 0 deletions packages/astro/test/units/integrations/api.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,33 @@ describe('Integration API', () => {
expect(updatedViteConfig).to.haveOwnProperty('define');
});

it('runHookBuildSetup should return updated config', async () => {
let updatedInternalConfig;
const updatedViteConfig = await runHookBuildSetup({
config: {
integrations: [
{
name: 'test',
hooks: {
'astro:build:setup'({ updateConfig }) {
updatedInternalConfig = updateConfig({
define: {
foo: 'bar',
},
});
},
},
},
],
},
vite: {},
logger: defaultLogger,
pages: new Map(),
target: 'server',
});
expect(updatedViteConfig).to.be.deep.equal(updatedInternalConfig);
});

it('runHookConfigSetup can update Astro config', async () => {
const site = 'https://test.com/';
const updatedSettings = await runHookConfigSetup({
Expand Down
4 changes: 2 additions & 2 deletions packages/integrations/solid/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { AstroIntegration, AstroRenderer } from 'astro';
import type { AstroConfig, AstroIntegration, AstroRenderer, DeepPartial } from 'astro';
import solid, { type Options as ViteSolidPluginOptions } from 'vite-plugin-solid';

async function getViteConfiguration(isDev: boolean, { include, exclude }: Options = {}) {
Expand Down Expand Up @@ -34,7 +34,7 @@ async function getViteConfiguration(isDev: boolean, { include, exclude }: Option
ssr: {
external: ['babel-preset-solid'],
},
};
} satisfies DeepPartial<AstroConfig['vite']>;
}

function getRenderer(): AstroRenderer {
Expand Down
Loading