Skip to content

Commit d6e994a

Browse files
committed
react helmet async apply
1 parent 0fdc531 commit d6e994a

File tree

8 files changed

+116
-15
lines changed

8 files changed

+116
-15
lines changed

index.html

-2
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44
<meta charset="UTF-8" />
55
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
66
<meta http-equiv="X-UA-Compatible" content="ie=edge">
7-
<!--app-head-->
8-
<title><!--app-title--></title>
97
</head>
108
<body>
119
<div id="app"><!--app-html--></div>

package.json

+2
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
"react": "rc",
3232
"react-dom": "rc",
3333
"react-error-boundary": "^3.1.4",
34+
"react-helmet-async": "^1.2.2",
3435
"react-relay": "^13.0.2",
3536
"react-relay-network-modern": "^6.2.1",
3637
"react-ssr-prepass": "^1.5.0",
@@ -52,6 +53,7 @@
5253
"@types/node": "^17.0.15",
5354
"@types/react": "^17.0.39",
5455
"@types/react-dom": "^17.0.11",
56+
"@types/react-helmet-async": "^1.0.3",
5557
"@types/react-relay": "^13.0.1",
5658
"@types/relay-runtime": "^13.0.1",
5759
"@types/serve-static": "^1.13.10",

server/server-develop.ts

+15-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import fs from "fs";
22
import { createApp, Middleware, send } from "h3";
33
import { createServer } from "http";
4+
import { FilledContext } from "react-helmet-async";
45
import serveStatic from "serve-static";
56
import { ModuleNode } from "vite";
67
import {
@@ -48,6 +49,10 @@ export async function startDevServer() {
4849

4950
const url = req.url!!;
5051

52+
if (/^\/(api|graphql)/.test(url)) {
53+
return next();
54+
}
55+
5156
try {
5257
// 1. index.html 파일을 읽어들입니다.
5358
const indexHtml = fs.readFileSync(resolveApp("index.html"), "utf-8");
@@ -71,15 +76,23 @@ export async function startDevServer() {
7176

7277
const styles = collectCssUrls(modules);
7378

79+
const helmetContext = {} as FilledContext;
80+
7481
// 4. 앱의 HTML을 렌더링합니다.
7582
// 이는 entry-server.js에서 내보낸(Export) `render` 함수가
7683
// ReactDOMServer.renderToString()과 같은 적절한 프레임워크의 SSR API를 호출한다고 가정합니다.
77-
const appHtml = await render(url);
84+
const appHtml = await render(url, helmetContext);
85+
86+
const { helmet } = helmetContext;
87+
88+
// etc…
89+
7890

7991
// 5. 렌더링된 HTML을 템플릿에 주입합니다.
8092
const html = template
8193
.replace(`<!--app-title-->`, "React SSR")
82-
.replace(`<!--app-head-->`, styles)
94+
.replace(`</head>`, styles)
95+
.replace(`</head>`, helmet.title.toString())
8396
.replace(`<!--app-html-->`, appHtml);
8497

8598
// 6. 렌더링된 HTML을 응답으로 전송합니다.

server/server-production.ts

+4
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ export async function startProdServer() {
2828

2929
const url = req.url!!;
3030

31+
if (/^\/(api|graphql)/.test(url)) {
32+
return next();
33+
}
34+
3135
try {
3236
const template = fs.readFileSync(
3337
resolveApp("dist/client/index.html"),

src/AppRoot.tsx

+13-5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { StrictMode } from "react";
2+
import { FilledContext, Helmet, HelmetProvider } from "react-helmet-async";
23
import { RelayEnvironmentProvider } from "react-relay";
34
import "regenerator-runtime/runtime";
45
import { Environment } from "relay-runtime/lib/store/RelayStoreTypes";
@@ -9,17 +10,24 @@ import "./index.css";
910
export function AppRoot({
1011
router,
1112
relayEnvironment,
13+
helmetContext,
1214
}: {
1315
router: RouterProps;
1416
relayEnvironment: Environment;
17+
helmetContext?: FilledContext;
1518
}) {
1619
return (
1720
<StrictMode>
18-
<RelayEnvironmentProvider environment={relayEnvironment}>
19-
<RouterProvider router={router}>
20-
<App />
21-
</RouterProvider>
22-
</RelayEnvironmentProvider>
21+
<HelmetProvider context={helmetContext}>
22+
<RelayEnvironmentProvider environment={relayEnvironment}>
23+
<RouterProvider router={router}>
24+
<Helmet>
25+
<title>Hello Relay</title>
26+
</Helmet>
27+
<App />
28+
</RouterProvider>
29+
</RelayEnvironmentProvider>
30+
</HelmetProvider>
2331
</StrictMode>
2432
);
2533
}

src/entry-server.tsx

+13-4
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
import { createElement } from "react";
22
import { renderToString } from "react-dom/server";
3+
import { FilledContext } from "react-helmet-async";
34
import ssrPrepass from "react-ssr-prepass";
45
import { createMemoryRouter } from "yarr";
56
import { AppRoot } from "./AppRoot";
67
import { createRelayEnvironment } from "./relay/RelayEnvironment";
78
import { createRoutes } from "./routes";
89

9-
export async function render(url: string): Promise<string> {
10+
export async function render(
11+
url: string,
12+
helmetContext: FilledContext
13+
): Promise<string> {
1014
const relayEnvironment = createRelayEnvironment({});
1115

1216
const router = createMemoryRouter(
@@ -16,13 +20,18 @@ export async function render(url: string): Promise<string> {
1620
{ initialEntries: [url] }
1721
);
1822

19-
const element = createElement(AppRoot, { router, relayEnvironment });
23+
const element = createElement(AppRoot, {
24+
router,
25+
relayEnvironment,
26+
helmetContext,
27+
});
2028
await ssrPrepass(element);
2129

2230
const relayInitialData = relayEnvironment.getStore().getSource();
2331
const appHtml = renderToString(element);
24-
25-
return `${appHtml}<script>window.__PRELOADED_STATE__=${JSON.stringify(
32+
const preloadedState = `<script>window.__PRELOADED_STATE__=${JSON.stringify(
2633
relayInitialData
2734
)}</script>`;
35+
36+
return `${appHtml}${preloadedState}`;
2837
}

src/pages/Post.tsx

+9-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { Helmet } from "react-helmet-async";
12
import { graphql, PreloadedQuery, usePreloadedQuery } from "react-relay";
23
import { RouteProps } from "yarr";
34
import { PostQuery } from "./__generated__/PostQuery.graphql";
@@ -22,5 +23,12 @@ export const postQuery = graphql`
2223
export function PostPage({ preloaded }: PostPageProps) {
2324
const data = usePreloadedQuery(postQuery, preloaded.query);
2425

25-
return <div>{JSON.stringify(data.node, null, 2)}</div>;
26+
return (
27+
<div>
28+
<Helmet>
29+
<title>{data.node?.title}</title>
30+
</Helmet>
31+
{JSON.stringify(data.node, null, 2)}
32+
</div>
33+
);
2634
}

yarn.lock

+60-1
Original file line numberDiff line numberDiff line change
@@ -990,6 +990,15 @@ __metadata:
990990
languageName: node
991991
linkType: hard
992992

993+
"@types/react-helmet-async@npm:^1.0.3":
994+
version: 1.0.3
995+
resolution: "@types/react-helmet-async@npm:1.0.3"
996+
dependencies:
997+
react-helmet-async: "*"
998+
checksum: 420a1fcd84027079e736d263e79ee290b98fae955518dc9ce3203da1c11dacd6c8a0045050657b0d473991e3133b050ebc43131fad47ae7c79964a21cd44bacc
999+
languageName: node
1000+
linkType: hard
1001+
9931002
"@types/react-relay@npm:^13.0.1":
9941003
version: 13.0.1
9951004
resolution: "@types/react-relay@npm:13.0.1"
@@ -4334,7 +4343,7 @@ __metadata:
43344343
languageName: node
43354344
linkType: hard
43364345

4337-
"loose-envify@npm:^1.0.0, loose-envify@npm:^1.1.0, loose-envify@npm:^1.2.0":
4346+
"loose-envify@npm:^1.0.0, loose-envify@npm:^1.1.0, loose-envify@npm:^1.2.0, loose-envify@npm:^1.4.0":
43384347
version: 1.4.0
43394348
resolution: "loose-envify@npm:1.4.0"
43404349
dependencies:
@@ -5237,6 +5246,17 @@ __metadata:
52375246
languageName: node
52385247
linkType: hard
52395248

5249+
"prop-types@npm:^15.7.2":
5250+
version: 15.8.1
5251+
resolution: "prop-types@npm:15.8.1"
5252+
dependencies:
5253+
loose-envify: ^1.4.0
5254+
object-assign: ^4.1.1
5255+
react-is: ^16.13.1
5256+
checksum: c056d3f1c057cb7ff8344c645450e14f088a915d078dcda795041765047fa080d38e5d626560ccaac94a4e16e3aa15f3557c1a9a8d1174530955e992c675e459
5257+
languageName: node
5258+
linkType: hard
5259+
52405260
"pump@npm:^3.0.0":
52415261
version: 3.0.0
52425262
resolution: "pump@npm:3.0.0"
@@ -5306,6 +5326,36 @@ __metadata:
53065326
languageName: node
53075327
linkType: hard
53085328

5329+
"react-fast-compare@npm:^3.2.0":
5330+
version: 3.2.0
5331+
resolution: "react-fast-compare@npm:3.2.0"
5332+
checksum: 8ef272c825ae329f61633ce4ce7f15aa5b84e5214d88bc0823880236e03e985a13195befa2c7a4eda7db3b017dc7985729152d88445823f652403cf36c2b86aa
5333+
languageName: node
5334+
linkType: hard
5335+
5336+
"react-helmet-async@npm:*, react-helmet-async@npm:^1.2.2":
5337+
version: 1.2.2
5338+
resolution: "react-helmet-async@npm:1.2.2"
5339+
dependencies:
5340+
"@babel/runtime": ^7.12.5
5341+
invariant: ^2.2.4
5342+
prop-types: ^15.7.2
5343+
react-fast-compare: ^3.2.0
5344+
shallowequal: ^1.1.0
5345+
peerDependencies:
5346+
react: ^16.6.0 || ^17.0.0
5347+
react-dom: ^16.6.0 || ^17.0.0
5348+
checksum: 3251ab596143a48f9380a78a9e71f451ef729e25081bb4c1476561a1689eee23d650964e1518792bd44a8d24d95da1f9774b9b7ed80cae8eccc8119d7f5dd3f3
5349+
languageName: node
5350+
linkType: hard
5351+
5352+
"react-is@npm:^16.13.1":
5353+
version: 16.13.1
5354+
resolution: "react-is@npm:16.13.1"
5355+
checksum: f7a19ac3496de32ca9ae12aa030f00f14a3d45374f1ceca0af707c831b2a6098ef0d6bdae51bd437b0a306d7f01d4677fcc8de7c0d331eb47ad0f46130e53c5f
5356+
languageName: node
5357+
linkType: hard
5358+
53095359
"react-refresh@npm:^0.11.0":
53105360
version: 0.11.0
53115361
resolution: "react-refresh@npm:0.11.0"
@@ -5621,6 +5671,7 @@ __metadata:
56215671
"@types/node": ^17.0.15
56225672
"@types/react": ^17.0.39
56235673
"@types/react-dom": ^17.0.11
5674+
"@types/react-helmet-async": ^1.0.3
56245675
"@types/react-relay": ^13.0.1
56255676
"@types/relay-runtime": ^13.0.1
56265677
"@types/serve-static": ^1.13.10
@@ -5640,6 +5691,7 @@ __metadata:
56405691
react: rc
56415692
react-dom: rc
56425693
react-error-boundary: ^3.1.4
5694+
react-helmet-async: ^1.2.2
56435695
react-relay: ^13.0.2
56445696
react-relay-network-modern: ^6.2.1
56455697
react-ssr-prepass: ^1.5.0
@@ -5825,6 +5877,13 @@ __metadata:
58255877
languageName: node
58265878
linkType: hard
58275879

5880+
"shallowequal@npm:^1.1.0":
5881+
version: 1.1.0
5882+
resolution: "shallowequal@npm:1.1.0"
5883+
checksum: f4c1de0837f106d2dbbfd5d0720a5d059d1c66b42b580965c8f06bb1db684be8783538b684092648c981294bf817869f743a066538771dbecb293df78f765e00
5884+
languageName: node
5885+
linkType: hard
5886+
58285887
"shebang-command@npm:^1.2.0":
58295888
version: 1.2.0
58305889
resolution: "shebang-command@npm:1.2.0"

0 commit comments

Comments
 (0)