Skip to content

Commit bdafbd4

Browse files
committed
fix: regression or integration execution ordering
Signed-off-by: Andres Correa Casablanca <andreu@kindspells.dev>
1 parent adf105b commit bdafbd4

File tree

12 files changed

+678
-1125
lines changed

12 files changed

+678
-1125
lines changed

@kindspells/astro-shield/package.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -63,15 +63,15 @@
6363
"astro": "^4.0.0"
6464
},
6565
"devDependencies": {
66-
"@types/node": "^22.7.4",
67-
"astro": "^4.15.11",
66+
"@types/node": "^22.8.6",
67+
"astro": "^4.16.8",
6868
"get-tsconfig": "^4.8.1",
69-
"rollup": "^4.24.0",
69+
"rollup": "^4.24.3",
7070
"rollup-plugin-dts": "^6.1.1",
7171
"rollup-plugin-esbuild": "^6.1.1",
72-
"typescript": "^5.6.2",
73-
"vite": "^5.4.8",
74-
"vitest": "^2.1.2"
72+
"typescript": "^5.6.3",
73+
"vite": "^5.4.10",
74+
"vitest": "^2.1.4"
7575
},
7676
"repository": {
7777
"type": "git",

@kindspells/astro-shield/src/core.mts

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -996,7 +996,7 @@ export const getViteMiddlewarePlugin = (
996996
}
997997
}
998998

999-
const getAstroBuildDone = (
999+
export const getAstroBuildDone = (
10001000
state: IntegrationState,
10011001
sri: Required<SRIOptions>,
10021002
securityHeaders: SecurityHeadersOptions | undefined,
@@ -1042,15 +1042,21 @@ export const getAstroConfigSetup = (
10421042
})
10431043
}
10441044

1045-
updateConfig({
1046-
integrations: [
1047-
{
1048-
name: '@kindspells/astro-shield-post-config-setup',
1049-
hooks: {
1050-
'astro:build:done': getAstroBuildDone(state, sri, securityHeaders),
1045+
if (state.delayTransform) {
1046+
updateConfig({
1047+
integrations: [
1048+
{
1049+
name: '@kindspells/astro-shield-post-config-setup',
1050+
hooks: {
1051+
'astro:build:done': getAstroBuildDone(
1052+
state,
1053+
sri,
1054+
securityHeaders,
1055+
),
1056+
},
10511057
},
1052-
},
1053-
],
1054-
})
1058+
],
1059+
})
1060+
}
10551061
}
10561062
}

@kindspells/astro-shield/src/e2e/fixtures/dynamic/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
"license": "MIT",
1212
"dependencies": {
1313
"@astrojs/node": "^8.3.4",
14-
"astro": "^4.15.11"
14+
"astro": "^4.16.8"
1515
},
1616
"devDependencies": {
1717
"@kindspells/astro-shield": "workspace:*"

@kindspells/astro-shield/src/e2e/fixtures/hybrid/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
"license": "MIT",
1010
"dependencies": {
1111
"@astrojs/node": "^8.3.4",
12-
"astro": "^4.15.11"
12+
"astro": "^4.16.8"
1313
},
1414
"devDependencies": {
1515
"@kindspells/astro-shield": "workspace:*"

@kindspells/astro-shield/src/e2e/fixtures/hybrid2/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
"license": "MIT",
1010
"dependencies": {
1111
"@astrojs/node": "^8.3.4",
12-
"astro": "^4.15.11"
12+
"astro": "^4.16.8"
1313
},
1414
"devDependencies": {
1515
"@kindspells/astro-shield": "workspace:*"

@kindspells/astro-shield/src/e2e/fixtures/hybrid3/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
"license": "MIT",
1010
"dependencies": {
1111
"@astrojs/node": "^8.3.4",
12-
"astro": "^4.15.11"
12+
"astro": "^4.16.8"
1313
},
1414
"devDependencies": {
1515
"@kindspells/astro-shield": "workspace:*"

@kindspells/astro-shield/src/e2e/fixtures/static/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
},
99
"license": "MIT",
1010
"dependencies": {
11-
"astro": "^4.15.11"
11+
"astro": "^4.16.8"
1212
},
1313
"devDependencies": {
1414
"@kindspells/astro-shield": "workspace:*"

@kindspells/astro-shield/src/main.mts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
import type { AstroIntegration } from 'astro'
88

9-
import { getAstroConfigSetup } from '#as/core'
9+
import { getAstroBuildDone, getAstroConfigSetup } from '#as/core'
1010
import type { IntegrationState, ShieldOptions, SRIOptions } from './types.mts'
1111

1212
const logWarn = (msg: string): void =>
@@ -15,10 +15,10 @@ const logWarn = (msg: string): void =>
1515
// Integration
1616
// -----------------------------------------------------------------------------
1717
export const shield = ({
18+
delayTransform,
1819
securityHeaders,
1920
sri,
2021
}: ShieldOptions): AstroIntegration => {
21-
// We need to merge the deprecated options into the new object
2222
const _sri = {
2323
enableMiddleware: sri?.enableMiddleware ?? false,
2424
enableStatic: sri?.enableStatic ?? true,
@@ -35,12 +35,24 @@ export const shield = ({
3535
logWarn('`sri.hashesModule` is ignored when `sri.enableStatic` is `false`')
3636
}
3737

38-
const state: IntegrationState = { config: {} }
38+
const _delayTransform =
39+
delayTransform ??
40+
securityHeaders?.enableOnStaticPages?.provider === 'vercel'
41+
42+
const state: IntegrationState = {
43+
delayTransform: _delayTransform,
44+
config: {},
45+
}
3946

4047
return {
4148
name: '@kindspells/astro-shield',
4249
hooks: {
4350
'astro:config:setup': getAstroConfigSetup(state, _sri, securityHeaders),
51+
...(_delayTransform
52+
? undefined
53+
: {
54+
'astro:build:done': getAstroBuildDone(state, _sri, securityHeaders),
55+
}),
4456
},
4557
} satisfies AstroIntegration
4658
}

@kindspells/astro-shield/src/tests/main.test.mts

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,26 +10,33 @@ import { describe, expect, it } from 'vitest'
1010
import defaultIntegrationExport, { shield } from '../main.mts'
1111

1212
describe('sriCSP', () => {
13-
it('is exported as default', () => {
14-
expect(defaultIntegrationExport).toBe(shield)
15-
expect(shield).toBeInstanceOf(Function)
16-
})
13+
const defaultIntegrationKeys = [
14+
'astro:build:done',
15+
'astro:config:setup',
16+
] as Readonly<['astro:build:done', 'astro:config:setup']>
1717

1818
const checkIntegration = (
1919
integration: AstroIntegration,
20-
keys: (keyof AstroIntegration['hooks'])[] = ['astro:config:setup'] as const,
20+
keys: Readonly<
21+
(keyof AstroIntegration['hooks'])[]
22+
> = defaultIntegrationKeys,
2123
) => {
2224
expect(Object.keys(integration).sort()).toEqual(['hooks', 'name'])
2325
expect(integration.name).toBe('@kindspells/astro-shield')
2426

25-
const sortedKeys = keys.sort()
27+
const sortedKeys = keys.slice().sort() // TODO: use toSorted when widely available
2628
expect(Object.keys(integration.hooks).sort()).toEqual(sortedKeys)
2729
for (const key of sortedKeys) {
2830
expect(integration.hooks[key]).toBeTruthy()
2931
expect(integration.hooks[key]).toBeInstanceOf(Function)
3032
}
3133
}
3234

35+
it('is exported as default', () => {
36+
expect(defaultIntegrationExport).toBe(shield)
37+
expect(shield).toBeInstanceOf(Function)
38+
})
39+
3340
it('returns a valid AstroIntegration object for default config', () => {
3441
const integration = shield({})
3542
checkIntegration(integration)
@@ -44,12 +51,12 @@ describe('sriCSP', () => {
4451
const integration = shield({ sri: { enableStatic: false } })
4552

4653
// NOTE: it is too much work to verify that those hooks will do nothing
47-
checkIntegration(integration, ['astro:config:setup'])
54+
checkIntegration(integration, defaultIntegrationKeys)
4855
})
4956

5057
it('returns hooks for static & dynamic content when we enable middleware', () => {
5158
const integration = shield({ sri: { enableMiddleware: true } })
52-
checkIntegration(integration, ['astro:config:setup'])
59+
checkIntegration(integration, defaultIntegrationKeys)
5360
})
5461

5562
it('returns hooks only for dynamic content when we enable middleware and disable static sri', () => {
@@ -59,6 +66,20 @@ describe('sriCSP', () => {
5966
enableMiddleware: true,
6067
},
6168
})
69+
checkIntegration(integration, defaultIntegrationKeys)
70+
})
71+
72+
it('removes build:done from base config when delayTransform=true', () => {
73+
const integration = shield({
74+
delayTransform: true,
75+
})
6276
checkIntegration(integration, ['astro:config:setup'])
6377
})
78+
79+
it('keeps build:done in base config when delayTransform=false', () => {
80+
const integration = shield({
81+
delayTransform: false,
82+
})
83+
checkIntegration(integration, ['astro:build:done', 'astro:config:setup'])
84+
})
6485
})

@kindspells/astro-shield/src/types.mts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,20 @@ export type SecurityHeadersOptions = {
132132
}
133133

134134
export type ShieldOptions = {
135+
/**
136+
* When set to `true`, the transformation of static pages will be delayed to
137+
* be executed as late as possible in the build process. This might be
138+
* necessary in case you are using many integrations that transform the HTML
139+
* output.
140+
*
141+
* If not set and any of the following conditions are met, then this option
142+
* will be automatically set to `true`:
143+
* - securityHeaders.enableOnStaticPages is set to `{ provider: 'vercel' }`
144+
*
145+
* Defaults to `false`.
146+
*/
147+
delayTransform?: boolean
148+
135149
/**
136150
* Options related to Subresource Integrity (SRI).
137151
*/
@@ -176,4 +190,7 @@ export type HashesCollection = {
176190
perResourceSriHashes: MiddlewareHashes
177191
}
178192

179-
export type IntegrationState = { config: Partial<AstroConfig> }
193+
export type IntegrationState = {
194+
delayTransform: boolean
195+
config: Partial<AstroConfig>
196+
}

0 commit comments

Comments
 (0)