feat: SPA redirect
This commit is contained in:
parent
293a065ff7
commit
3fdcf6815b
|
@ -1,7 +1,7 @@
|
|||
import React, {Suspense, useState} from 'react';
|
||||
// @ts-ignore
|
||||
import {createRoot} from 'react-dom';
|
||||
import {BrowserRouter} from 'react-router-dom';
|
||||
import {BrowserRouter, Redirect} from 'react-router-dom';
|
||||
import type {ClientHandler} from './types';
|
||||
import {ErrorBoundary} from 'react-error-boundary';
|
||||
import {HelmetProvider} from 'react-helmet-async';
|
||||
|
@ -35,7 +35,8 @@ function Content({clientWrapper: ClientWrapper}: {clientWrapper: any}) {
|
|||
pathname: window.location.pathname,
|
||||
search: window.location.search,
|
||||
});
|
||||
const response = useServerResponse(serverState);
|
||||
|
||||
const response = useServerResponse(serverState).read();
|
||||
|
||||
return (
|
||||
<ServerStateProvider
|
||||
|
@ -46,8 +47,12 @@ function Content({clientWrapper: ClientWrapper}: {clientWrapper: any}) {
|
|||
<HelmetProvider>
|
||||
<BrowserRouter>
|
||||
<ServerStateRouter />
|
||||
{/* @ts-ignore */}
|
||||
<ClientWrapper>{response.read()}</ClientWrapper>
|
||||
{response.redirect ? (
|
||||
<Redirect to={response.redirect} />
|
||||
) : (
|
||||
/* @ts-ignore */
|
||||
<ClientWrapper>{response}</ClientWrapper>
|
||||
)}
|
||||
</BrowserRouter>
|
||||
</HelmetProvider>
|
||||
</QueryProvider>
|
||||
|
|
|
@ -20,6 +20,7 @@ import {ServerComponentResponse} from './framework/Hydration/ServerComponentResp
|
|||
import {ServerComponentRequest} from './framework/Hydration/ServerComponentRequest.server';
|
||||
import {dehydrate} from 'react-query/hydration';
|
||||
import {getCacheControlHeader} from './framework/cache';
|
||||
import type {ServerResponse} from 'http';
|
||||
|
||||
/**
|
||||
* react-dom/unstable-fizz provides different entrypoints based on runtime:
|
||||
|
@ -118,25 +119,11 @@ const renderHydrogen: ServerHandler = (App, hook) => {
|
|||
componentResponse.cacheControlHeader
|
||||
);
|
||||
|
||||
const {customHead} = componentResponse;
|
||||
if (customHead) {
|
||||
if (customHead.headers) {
|
||||
for (const [key, value] of Object.entries(customHead.headers)) {
|
||||
response.setHeader(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
if (customHead.statusText) {
|
||||
response.statusMessage = customHead.statusText;
|
||||
}
|
||||
|
||||
if (customHead.status) {
|
||||
response.statusCode = customHead.status;
|
||||
|
||||
if (response.statusCode >= 300 && response.statusCode < 400) {
|
||||
// Redirect
|
||||
return response.end();
|
||||
}
|
||||
if (componentResponse.customHead) {
|
||||
writeHeadToServerResponse(componentResponse, response);
|
||||
if (response.statusCode >= 300 && response.statusCode < 400) {
|
||||
// Redirect
|
||||
return response.end();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -227,6 +214,15 @@ const renderHydrogen: ServerHandler = (App, hook) => {
|
|||
* `template` and `script` tags inserted and rendered as part of the hydration response.
|
||||
*/
|
||||
onCompleteAll() {
|
||||
if (componentResponse.customHead) {
|
||||
writeHeadToServerResponse(componentResponse, response);
|
||||
if (response.statusCode >= 300 && response.statusCode < 400) {
|
||||
// Redirect: mock status to bypass fetch opaque responses
|
||||
response.statusCode = 299;
|
||||
return response.end();
|
||||
}
|
||||
}
|
||||
|
||||
// Tell React to start writing to the writer
|
||||
startWriting();
|
||||
|
||||
|
@ -454,4 +450,23 @@ async function renderAppFromStringWithPrepass(
|
|||
: body;
|
||||
}
|
||||
|
||||
export function writeHeadToServerResponse(
|
||||
{customHead = {}}: ServerComponentResponse,
|
||||
serverResponse: ServerResponse
|
||||
) {
|
||||
if (customHead.headers) {
|
||||
for (const [key, value] of Object.entries(customHead.headers)) {
|
||||
serverResponse.setHeader(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
if (customHead.statusText) {
|
||||
serverResponse.statusMessage = customHead.statusText;
|
||||
}
|
||||
|
||||
if (customHead.status) {
|
||||
serverResponse.statusCode = customHead.status;
|
||||
}
|
||||
}
|
||||
|
||||
export default renderHydrogen;
|
||||
|
|
|
@ -35,10 +35,13 @@ function createFromFetch(fetchPromise: Promise<any>) {
|
|||
if (!response.ok) {
|
||||
throw new Error(`Hydration request failed: ${response.statusText}`);
|
||||
}
|
||||
return response.text();
|
||||
})
|
||||
.then((payload) => {
|
||||
return convertHydrationResponseToReactComponents(payload);
|
||||
|
||||
// Mocked status to bypass fetch opaque responses
|
||||
if (response.status === 299) {
|
||||
return {redirect: response.headers.get('location')};
|
||||
}
|
||||
|
||||
return response.text().then(convertHydrationResponseToReactComponents);
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error(e);
|
||||
|
|
Loading…
Reference in a new issue