diff --git a/.changeset/two-geckos-rhyme.md b/.changeset/two-geckos-rhyme.md new file mode 100644 index 000000000..62f2946fc --- /dev/null +++ b/.changeset/two-geckos-rhyme.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Improving build validation and error messages for client hydration directives diff --git a/packages/astro/src/runtime/server/hydration.ts b/packages/astro/src/runtime/server/hydration.ts index 7767f2f66..a54bee6e6 100644 --- a/packages/astro/src/runtime/server/hydration.ts +++ b/packages/astro/src/runtime/server/hydration.ts @@ -31,6 +31,8 @@ export function serializeProps(value: any) { }); } +const HydrationDirectives = ['load', 'idle', 'media', 'visible', 'only']; + interface ExtractedProps { hydration: { directive: string; @@ -70,6 +72,17 @@ export function extractDirectives(inputProps: Record): Ext default: { extracted.hydration.directive = key.split(':')[1]; extracted.hydration.value = value; + + // throw an error if an invalid hydration directive was provided + if (HydrationDirectives.indexOf(extracted.hydration.directive) < 0) { + throw new Error(`Error: invalid hydration directive "${key}". Supported hydration methods: ${HydrationDirectives.map(d => `"client:${d}"`).join(', ')}`) + } + + // throw an error if the query wasn't provided for client:media + if (extracted.hydration.directive === 'media' && typeof extracted.hydration.value !== 'string') { + throw new Error('Error: Media query must be provided for "client:media", similar to client:media="(max-width: 600px)"') + } + break; } } diff --git a/packages/astro/test/errors.test.js b/packages/astro/test/errors.test.js index 207c67a51..9c9843e65 100644 --- a/packages/astro/test/errors.test.js +++ b/packages/astro/test/errors.test.js @@ -50,6 +50,36 @@ describe('Error display', () => { // TODO: improve stacktrace }); + + it('hydration error', async () => { + if (isMacOS) return; + + const res = await fixture.fetch('/astro-hydration-error'); + + // 500 returned + expect(res.status).to.equal(500); + + // error message contains error + const body = await res.text(); + + // error message contains error + expect(body).to.include('Error: invalid hydration directive'); + }); + + it('client:media error', async () => { + if (isMacOS) return; + + const res = await fixture.fetch('/astro-client-media-error'); + + // 500 returned + expect(res.status).to.equal(500); + + // error message contains error + const body = await res.text(); + + // error message contains error + expect(body).to.include('Error: Media query must be provided'); + }); }); describe('JS', () => { diff --git a/packages/astro/test/fixtures/errors/src/components/SvelteDirectiveError.svelte b/packages/astro/test/fixtures/errors/src/components/SvelteDirectiveError.svelte new file mode 100644 index 000000000..b07b120a2 --- /dev/null +++ b/packages/astro/test/fixtures/errors/src/components/SvelteDirectiveError.svelte @@ -0,0 +1,2 @@ +

I shouldn’t be here

+ \ No newline at end of file diff --git a/packages/astro/test/fixtures/errors/src/pages/astro-client-media-error.astro b/packages/astro/test/fixtures/errors/src/pages/astro-client-media-error.astro new file mode 100644 index 000000000..46bb9a2c4 --- /dev/null +++ b/packages/astro/test/fixtures/errors/src/pages/astro-client-media-error.astro @@ -0,0 +1,7 @@ +--- +import SvelteDirectiveError from '../components/SvelteDirectiveError.svelte'; +--- + +
+ +
\ No newline at end of file diff --git a/packages/astro/test/fixtures/errors/src/pages/astro-hydration-error.astro b/packages/astro/test/fixtures/errors/src/pages/astro-hydration-error.astro new file mode 100644 index 000000000..1852539eb --- /dev/null +++ b/packages/astro/test/fixtures/errors/src/pages/astro-hydration-error.astro @@ -0,0 +1,7 @@ +--- +import SvelteDirectiveError from '../components/SvelteDirectiveError.svelte'; +--- + +
+ +
\ No newline at end of file