Skip to content

Commit 0e6fbcb

Browse files
committed
build: use vite instead of remix server
1 parent 444e27a commit 0e6fbcb

18 files changed

+1468
-116
lines changed

apps/books-app/.eslintignore

Lines changed: 0 additions & 2 deletions
This file was deleted.

apps/books-app/.eslintrc.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"extends": ["../../.eslintrc.json"],
3-
"ignorePatterns": ["!**/*"],
3+
"ignorePatterns": ["!**/*", "build", "public/build", "node_modules"],
44
"overrides": [
55
{
66
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],

apps/books-app/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
.cache
22
build
33
public/build
4+
.env

apps/books-app/CHANGELOG.md

Lines changed: 0 additions & 48 deletions
This file was deleted.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/**
2+
* By default, Remix will handle hydrating your app on the client for you.
3+
* You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` ✨
4+
* For more information, see https://remix.run/file-conventions/entry.client
5+
*/
6+
7+
import { RemixBrowser } from '@remix-run/react';
8+
import { startTransition, StrictMode } from 'react';
9+
import { hydrateRoot } from 'react-dom/client';
10+
11+
startTransition(() => {
12+
hydrateRoot(
13+
document,
14+
<StrictMode>
15+
<RemixBrowser />
16+
</StrictMode>
17+
);
18+
});
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
/**
2+
* By default, Remix will handle generating the HTTP Response for you.
3+
* You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` ✨
4+
* For more information, see https://remix.run/file-conventions/entry.server
5+
*/
6+
7+
import { PassThrough } from 'node:stream';
8+
9+
import type { AppLoadContext, EntryContext } from '@remix-run/node';
10+
import { createReadableStreamFromReadable } from '@remix-run/node';
11+
import { RemixServer } from '@remix-run/react';
12+
import { isbot } from 'isbot';
13+
import { renderToPipeableStream } from 'react-dom/server';
14+
15+
const ABORT_DELAY = 5_000;
16+
17+
export default function handleRequest(
18+
request: Request,
19+
responseStatusCode: number,
20+
responseHeaders: Headers,
21+
remixContext: EntryContext,
22+
// This is ignored so we can keep it in the template for visibility. Feel
23+
// free to delete this parameter in your app if you're not using it!
24+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
25+
loadContext: AppLoadContext
26+
) {
27+
return isbot(request.headers.get('user-agent') || '')
28+
? handleBotRequest(
29+
request,
30+
responseStatusCode,
31+
responseHeaders,
32+
remixContext
33+
)
34+
: handleBrowserRequest(
35+
request,
36+
responseStatusCode,
37+
responseHeaders,
38+
remixContext
39+
);
40+
}
41+
42+
function handleBotRequest(
43+
request: Request,
44+
responseStatusCode: number,
45+
responseHeaders: Headers,
46+
remixContext: EntryContext
47+
) {
48+
return new Promise((resolve, reject) => {
49+
let shellRendered = false;
50+
const { pipe, abort } = renderToPipeableStream(
51+
<RemixServer
52+
context={remixContext}
53+
url={request.url}
54+
abortDelay={ABORT_DELAY}
55+
/>,
56+
{
57+
onAllReady() {
58+
shellRendered = true;
59+
const body = new PassThrough();
60+
const stream = createReadableStreamFromReadable(body);
61+
62+
responseHeaders.set('Content-Type', 'text/html');
63+
64+
resolve(
65+
new Response(stream, {
66+
headers: responseHeaders,
67+
status: responseStatusCode,
68+
})
69+
);
70+
71+
pipe(body);
72+
},
73+
onShellError(error: unknown) {
74+
reject(error);
75+
},
76+
onError(error: unknown) {
77+
responseStatusCode = 500;
78+
// Log streaming rendering errors from inside the shell. Don't log
79+
// errors encountered during initial shell rendering since they'll
80+
// reject and get logged in handleDocumentRequest.
81+
if (shellRendered) {
82+
console.error(error);
83+
}
84+
},
85+
}
86+
);
87+
88+
setTimeout(abort, ABORT_DELAY);
89+
});
90+
}
91+
92+
function handleBrowserRequest(
93+
request: Request,
94+
responseStatusCode: number,
95+
responseHeaders: Headers,
96+
remixContext: EntryContext
97+
) {
98+
return new Promise((resolve, reject) => {
99+
let shellRendered = false;
100+
const { pipe, abort } = renderToPipeableStream(
101+
<RemixServer
102+
context={remixContext}
103+
url={request.url}
104+
abortDelay={ABORT_DELAY}
105+
/>,
106+
{
107+
onShellReady() {
108+
shellRendered = true;
109+
const body = new PassThrough();
110+
const stream = createReadableStreamFromReadable(body);
111+
112+
responseHeaders.set('Content-Type', 'text/html');
113+
114+
resolve(
115+
new Response(stream, {
116+
headers: responseHeaders,
117+
status: responseStatusCode,
118+
})
119+
);
120+
121+
pipe(body);
122+
},
123+
onShellError(error: unknown) {
124+
reject(error);
125+
},
126+
onError(error: unknown) {
127+
responseStatusCode = 500;
128+
// Log streaming rendering errors from inside the shell. Don't log
129+
// errors encountered during initial shell rendering since they'll
130+
// reject and get logged in handleDocumentRequest.
131+
if (shellRendered) {
132+
console.error(error);
133+
}
134+
},
135+
}
136+
);
137+
138+
setTimeout(abort, ABORT_DELAY);
139+
});
140+
}

0 commit comments

Comments
 (0)