Skip to content

Commit

Permalink
SSR!!!!!!!!!!
Browse files Browse the repository at this point in the history
  • Loading branch information
cp-20 committed Mar 24, 2024
1 parent a3aaf61 commit 5493221
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 21 deletions.
6 changes: 4 additions & 2 deletions workspaces/app/src/pages/AuthorDetailPage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import invariant from 'tiny-invariant';

import { useAuthor } from '../../features/author/hooks/useAuthor';
import { BookListItem } from '../../features/book/components/BookListItem';
import { useBookList } from '../../features/book/hooks/useBookList';
import { Box } from '../../foundation/components/Box';
import { Flex } from '../../foundation/components/Flex';
import { Image } from '../../foundation/components/Image';
Expand Down Expand Up @@ -35,6 +36,7 @@ const AuthorDetailPage: React.FC = () => {
invariant(authorId);

const { data: author } = useAuthor({ params: { authorId } });
const { data: bookList } = useBookList({ query: { authorId } });

const imageUrl = `/raw-images/${author.image.id}_128x128.avif`;
const bookListA11yId = useId();
Expand Down Expand Up @@ -68,8 +70,8 @@ const AuthorDetailPage: React.FC = () => {
<Spacer height={Space * 2} />

<Flex align="center" as="ul" direction="column" justify="center">
{author.books.map((book) => (
<BookListItem key={book.id} bookId={book.id} />
{bookList.map((book) => (
<BookListItem key={book.id} book={book} />
))}
{author.books.length === 0 && (
<>
Expand Down
13 changes: 8 additions & 5 deletions workspaces/client/src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import $ from 'jquery';
import { Suspense } from 'react';
import ReactDOM from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom';
import { SWRConfig } from 'swr';
Expand All @@ -16,11 +17,13 @@ const main = async () => {
$(document).ready(() => {
ReactDOM.hydrateRoot(
$('#root').get(0)!,
<SWRConfig value={{ fallback, revalidateOnFocus: false, revalidateOnReconnect: false }}>
<BrowserRouter>
<ClientApp />
</BrowserRouter>
</SWRConfig>,
<Suspense fallback={<p>Loading</p>}>
<SWRConfig value={{ fallback, revalidateOnFocus: false, revalidateOnReconnect: false }}>
<BrowserRouter>
<ClientApp />
</BrowserRouter>
</SWRConfig>
</Suspense>,
);
});
};
Expand Down
67 changes: 53 additions & 14 deletions workspaces/server/src/routes/ssr/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,15 @@ import { Hono } from 'hono';
import { HTTPException } from 'hono/http-exception';
import jsesc from 'jsesc';
import moment from 'moment-timezone';
import { Suspense } from 'react';
import ReactDOMServer from 'react-dom/server';
import { StaticRouter } from 'react-router-dom/server';
import { ServerStyleSheet } from 'styled-components';
import { unstable_serialize } from 'swr';
import { SWRConfig, unstable_serialize } from 'swr';

import { authorApiClient } from '@wsh-2024/app/src/features/author/apiClient/authorApiClient';
import { bookApiClient } from '@wsh-2024/app/src/features/book/apiClient/bookApiClient';
import { episodeApiClient } from '@wsh-2024/app/src/features/episode/apiClient/episodeApiClient';
import { featureApiClient } from '@wsh-2024/app/src/features/feature/apiClient/featureApiClient';
import { rankingApiClient } from '@wsh-2024/app/src/features/ranking/apiClient/rankingApiClient';
import { releaseApiClient } from '@wsh-2024/app/src/features/release/apiClient/releaseApiClient';
Expand All @@ -19,23 +23,54 @@ import { INDEX_HTML_PATH } from '../../constants/paths';

const app = new Hono();

async function createInjectDataStr(): Promise<Record<string, unknown>> {
async function createInjectDataStr(path: string): Promise<Record<string, unknown>> {
const json: Record<string, unknown> = {};

{
if (path === '/') {
const dayOfWeek = getDayOfWeekStr(moment());
const releases = await releaseApiClient.fetch({ params: { dayOfWeek } });
const [releases, features, ranking] = await Promise.all([
releaseApiClient.fetch({ params: { dayOfWeek } }),
featureApiClient.fetchList({ query: {} }),
rankingApiClient.fetchList({ query: {} }),
]);
json[unstable_serialize(releaseApiClient.fetch$$key({ params: { dayOfWeek } }))] = releases;
json[unstable_serialize(featureApiClient.fetchList$$key({ query: {} }))] = features;
json[unstable_serialize(rankingApiClient.fetchList$$key({ query: {} }))] = ranking;
}

{
const features = await featureApiClient.fetchList({ query: {} });
json[unstable_serialize(featureApiClient.fetchList$$key({ query: {} }))] = features;
const bookDetail = path.match(/^\/books\/([^/]+)$/);
if (bookDetail != null) {
const [book, episodes] = await Promise.all([
bookApiClient.fetch({ params: { bookId: bookDetail[1]! } }),
episodeApiClient.fetchList({ query: { bookId: bookDetail[1]! } }),
]);
json[unstable_serialize(bookApiClient.fetch$$key({ params: { bookId: bookDetail[1]! } }))] = book;
json[unstable_serialize(episodeApiClient.fetchList$$key({ query: { bookId: bookDetail[1]! } }))] = episodes;
}

{
const ranking = await rankingApiClient.fetchList({ query: {} });
json[unstable_serialize(rankingApiClient.fetchList$$key({ query: {} }))] = ranking;
const episodeDetail = path.match(/^\/books\/([^/]+)\/episodes\/([^/]+)$/);
if (episodeDetail != null) {
const [episode, episodes] = await Promise.all([
episodeApiClient.fetch({ params: { episodeId: episodeDetail[2]! } }),
episodeApiClient.fetchList({ query: { bookId: episodeDetail[1]! } }),
]);
json[unstable_serialize(episodeApiClient.fetch$$key({ params: { episodeId: episodeDetail[2]! } }))] = episode;
json[unstable_serialize(episodeApiClient.fetchList$$key({ query: { bookId: episodeDetail[1]! } }))] = episodes;
}

const authorDetail = path.match(/^\/authors\/([^/]+)$/);
if (authorDetail != null) {
const [author, books] = await Promise.all([
authorApiClient.fetch({ params: { authorId: authorDetail[1]! } }),
bookApiClient.fetchList({ query: { authorId: authorDetail[1]! } }),
]);
json[unstable_serialize(authorApiClient.fetch$$key({ params: { authorId: authorDetail[1]! } }))] = author;
json[unstable_serialize(bookApiClient.fetchList$$key({ query: { authorId: authorDetail[1]! } }))] = books;
}

if (path === '/search') {
const bookList = await bookApiClient.fetchList({ query: {} });
json[unstable_serialize(bookApiClient.fetchList$$key({ query: {} }))] = bookList;
}

return json;
Expand Down Expand Up @@ -70,15 +105,19 @@ async function createHTML({
}

app.get('*', async (c) => {
const injectData = await createInjectDataStr();
const injectData = await createInjectDataStr(c.req.path);
const sheet = new ServerStyleSheet();

try {
const body = ReactDOMServer.renderToString(
sheet.collectStyles(
<StaticRouter location={c.req.path}>
<ClientApp />
</StaticRouter>,
<Suspense fallback={<p>Loading</p>}>
<SWRConfig value={{ fallback: injectData, revalidateOnFocus: false, revalidateOnReconnect: false }}>
<StaticRouter location={c.req.path}>
<ClientApp />
</StaticRouter>
</SWRConfig>
</Suspense>,
),
);

Expand Down

0 comments on commit 5493221

Please sign in to comment.