Skip to content

Commit

Permalink
Fix race condition with directive definitions (#4375)
Browse files Browse the repository at this point in the history
  • Loading branch information
matthewp authored Aug 22, 2022
1 parent 439f1d1 commit 5e82f6c
Show file tree
Hide file tree
Showing 16 changed files with 128 additions and 2 deletions.
5 changes: 5 additions & 0 deletions .changeset/smooth-nails-remain.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'astro': patch
---

Fixes race condition between directives being defined
5 changes: 5 additions & 0 deletions packages/astro/e2e/fixtures/hydration-race/astro.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import preact from '@astrojs/preact';

export default {
integrations: [preact()]
};
13 changes: 13 additions & 0 deletions packages/astro/e2e/fixtures/hydration-race/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"name": "@e2e/hydration-race",
"version": "0.0.0",
"private": true,
"scripts": {
"dev": "astro dev",
"build": "astro build"
},
"dependencies": {
"astro": "workspace:*",
"@astrojs/preact": "workspace:*"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
import One from './One.jsx';
---

<div>
<span>Before one</span>
<One name="One" client:idle />
</div>

Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
import Wrapper from './Wrapper.astro';
---

<Wrapper />
<slot />
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { h } from 'preact';

export default function({ name }) {
const inTheClient = import.meta.env.SSR ? '' : ' in the client'
return (
<div id={name.toLowerCase()}>Hello {name}{inTheClient}</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
import One from './One.jsx';
import Deeper from './Deeper.astro';
---


<One name="Two" client:visible />
<Deeper />
15 changes: 15 additions & 0 deletions packages/astro/e2e/fixtures/hydration-race/src/pages/slot.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
import Layout from '../components/Layout.astro';
import One from '../components/One.jsx';
---
<html>
<head>
<title>Testing</title>
</head>
<body>
<One name="Four" client:idle />
<Layout>
<One name="Three" client:visible />
</Layout>
</body>
</html>
36 changes: 36 additions & 0 deletions packages/astro/e2e/hydration-race.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { expect } from '@playwright/test';
import { testFactory } from './test-utils.js';

const test = testFactory({
root: './fixtures/hydration-race/',
});

let devServer;

test.beforeEach(async ({ astro }) => {
devServer = await astro.startDevServer();
});

test.afterEach(async () => {
await devServer.stop();
});

test.describe('Hydration race', () => {
test('Islands inside of slots hydrate', async ({ page, astro }) => {
await page.goto('/slot');

const html = await page.content();

const one = page.locator('#one');
await expect(one, 'updated text').toHaveText('Hello One in the client');

const two = page.locator('#two');
await expect(two, 'updated text').toHaveText('Hello Two in the client');

const three = page.locator('#three');
await expect(three, 'updated text').toHaveText('Hello Three in the client');

const four = page.locator('#four');
await expect(four, 'updated text').toHaveText('Hello Four in the client');
});
});
1 change: 1 addition & 0 deletions packages/astro/src/runtime/client/idle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@
setTimeout(cb, 200);
}
};
window.dispatchEvent(new Event('astro:idle'));
1 change: 1 addition & 0 deletions packages/astro/src/runtime/client/load.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
await hydrate();
})();
};
window.dispatchEvent(new Event('astro:load'));
1 change: 1 addition & 0 deletions packages/astro/src/runtime/client/media.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@
}
}
};
window.dispatchEvent(new Event('astro:media'));
1 change: 1 addition & 0 deletions packages/astro/src/runtime/client/only.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@
await hydrate();
})();
};
window.dispatchEvent(new Event('astro:only'));
1 change: 1 addition & 0 deletions packages/astro/src/runtime/client/visible.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@
io.observe(child);
}
};
window.dispatchEvent(new Event('astro:visible'));
12 changes: 10 additions & 2 deletions packages/astro/src/runtime/server/astro-island.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
type directiveAstroKeys = 'load' | 'idle' | 'visible' | 'media' | 'only';

declare const Astro: {
[k in directiveAstroKeys]: (
[k in directiveAstroKeys]?: (
fn: () => Promise<() => void>,
opts: Record<string, any>,
root: HTMLElement
Expand Down Expand Up @@ -57,8 +57,16 @@ declare const Astro: {
async childrenConnectedCallback() {
window.addEventListener('astro:hydrate', this.hydrate);
await import(this.getAttribute('before-hydration-url')!);
this.start();
}
start() {
const opts = JSON.parse(this.getAttribute('opts')!) as Record<string, any>;
Astro[this.getAttribute('client') as directiveAstroKeys](
const directive = this.getAttribute('client') as directiveAstroKeys;
if(Astro[directive] === undefined) {
window.addEventListener(`astro:${directive}`, () => this.start(), { once: true });
return;
}
Astro[directive]!(
async () => {
const rendererUrl = this.getAttribute('renderer-url');
const [componentModule, { default: hydrator }] = await Promise.all([
Expand Down
8 changes: 8 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 5e82f6c

Please sign in to comment.