diff --git a/.changeset/wet-boats-carry.md b/.changeset/wet-boats-carry.md new file mode 100644 index 0000000000..1367ead658 --- /dev/null +++ b/.changeset/wet-boats-carry.md @@ -0,0 +1,15 @@ +--- +'@shopify/hydrogen': patch +--- + +Allow concatenating requests with a header. For example, if you want the route `/shop` to proxy render everything on `/products`, setup an API route at `/routes/shop.server.jsx` with the following: + +```jsx +export async function api(request) { + return new Request(new URL(request.url).origin + '/products', { + headers: { + 'Hydrogen-Concatenate': 'true', + }, + }); +} +``` diff --git a/packages/hydrogen/src/utilities/apiRoutes.ts b/packages/hydrogen/src/utilities/apiRoutes.ts index 4b97caa67b..27d691800e 100644 --- a/packages/hydrogen/src/utilities/apiRoutes.ts +++ b/packages/hydrogen/src/utilities/apiRoutes.ts @@ -299,7 +299,7 @@ export async function renderApiRoute( return new Request(getRscUrl(url, newUrl), { headers: response.headers, }); - } else { + } else if (!response.headers.get('hydrogen-concatenate')) { // This request was made by a native form presumably because the client components had yet to hydrate, // Because of this, we need to redirect instead of just rendering the response. // Doing so prevents odd refresh / back behavior. The redirect response also should *never* be cached. diff --git a/packages/playground/server-components/src/routes/concatenate.server.jsx b/packages/playground/server-components/src/routes/concatenate.server.jsx new file mode 100644 index 0000000000..00b03bbf60 --- /dev/null +++ b/packages/playground/server-components/src/routes/concatenate.server.jsx @@ -0,0 +1,7 @@ +export async function api(request) { + return new Request(new URL(request.url).origin + '/about', { + headers: { + 'Hydrogen-Concatenate': 'true', + }, + }); +} diff --git a/packages/playground/server-components/tests/e2e-test-cases.ts b/packages/playground/server-components/tests/e2e-test-cases.ts index 5dd7e76a24..f7739532bb 100644 --- a/packages/playground/server-components/tests/e2e-test-cases.ts +++ b/packages/playground/server-components/tests/e2e-test-cases.ts @@ -624,7 +624,7 @@ export default async function testCases({ expect(await page.textContent('*')).toContain('fname=sometext'); }); - it('can concatenate requests', async () => { + it('can concatenate form requests', async () => { await page.goto(getServerUrl() + '/html-form'); expect(await page.textContent('#counter')).toEqual('0'); await page.click('#increase'); @@ -633,6 +633,11 @@ export default async function testCases({ expect(await page.textContent('#counter')).toEqual('2'); }); + it('can concatenate requests', async () => { + await page.goto(getServerUrl() + '/concatenate'); + expect(await page.textContent('body')).toContain('About'); + }); + it('responds with RSC', async () => { const response = await page.request.post(getServerUrl() + '/account', { data: `username=alincoln%40example.com&password=somepass`,