Skip to content

Commit

Permalink
fix(request-state): remove data race on early state load (#179)
Browse files Browse the repository at this point in the history
Co-authored-by: Luiz Ferraz <[email protected]>
  • Loading branch information
MWGuy and Fryuni authored Dec 10, 2024
1 parent f2e76e2 commit 4870d82
Show file tree
Hide file tree
Showing 4 changed files with 29 additions and 27 deletions.
5 changes: 5 additions & 0 deletions .changeset/neat-panthers-notice.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@inox-tools/request-state': minor
---

Fixes flash of page with unsynchronized state due to response streaming.
4 changes: 4 additions & 0 deletions docs/src/content/docs/request-nanostores.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,10 @@ $comments.set(await loadCommentsForArticle());
<Comments client:load />
```

## Caveats

Enabling Request-Scoped Nanostores disables [response streaming](https://docs.astro.build/en/recipes/streaming-improve-page-performance/). This behavior caused by [request-state](/request-state) package that prevents race condition where nanostores not initialized before client components starts hydrating.

## License

Request Nanostores is available under the MIT license.
4 changes: 4 additions & 0 deletions docs/src/content/docs/request-state.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,10 @@ document.addEventListener('@it-astro:server-state-loaded', (event) => {
});
```

## Caveats

Enabling Request State disables [response streaming](https://docs.astro.build/en/recipes/streaming-improve-page-performance/). The entire application state must be generated before shipping closing head tag to the client. This behavior prevents data race when client components start hydrating before entire document is loaded.

## License

Astro Request State is available under the MIT license.
43 changes: 16 additions & 27 deletions packages/request-state/src/runtime/middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,31 +13,20 @@ export const onRequest = defineMiddleware(async (_, next) => {

if (mediaType !== 'text/html' && !mediaType.startsWith('text/html+')) return result;

const newBody = result.body
?.pipeThrough(new TextDecoderStream())
.pipeThrough(injectState(getState))
.pipeThrough(new TextEncoderStream());

return new Response(newBody, result);
const originalBody = await result.text();

const headCloseIndex = originalBody.indexOf('</head>');
if (headCloseIndex > -1) {
const state = getState();
if (state) {
const stateScript = `<script id="it-astro-state" type="application/json+devalue">${state}</script>`;

return new Response(
originalBody.slice(0, headCloseIndex) + stateScript + originalBody.slice(headCloseIndex),
result
);
}
}

return new Response(originalBody, result);
});

function injectState(getState: () => string | false) {
let injected = false;
return new TransformStream({
transform(chunk, controller) {
if (!injected) {
const bodyCloseIndex = chunk.indexOf('</body>');
if (bodyCloseIndex > -1) {
const state = getState();
if (state) {
const stateScript = `<script id="it-astro-state" type="application/json+devalue">${state}</script>`;

chunk = chunk.slice(0, bodyCloseIndex) + stateScript + chunk.slice(bodyCloseIndex);
}
injected = true;
}
}
controller.enqueue(chunk);
},
});
}

0 comments on commit 4870d82

Please sign in to comment.