Skip to content

Commit 9eb745c

Browse files
committed
Initial commit from create-remix
0 parents  commit 9eb745c

13 files changed

+11432
-0
lines changed

.eslintrc.cjs

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/** @type {import('eslint').Linter.Config} */
2+
module.exports = {
3+
extends: ["@remix-run/eslint-config", "@remix-run/eslint-config/node"],
4+
};

.gitignore

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
node_modules
2+
3+
/.cache
4+
/build
5+
/public/build
6+
.env

README.md

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Welcome to Remix!
2+
3+
- [Remix Docs](https://remix.run/docs)
4+
5+
## Development
6+
7+
From your terminal:
8+
9+
```sh
10+
npm run dev
11+
```
12+
13+
This starts your app in development mode, rebuilding assets on file changes.
14+
15+
## Deployment
16+
17+
First, build your app for production:
18+
19+
```sh
20+
npm run build
21+
```
22+
23+
Then run the app in production mode:
24+
25+
```sh
26+
npm start
27+
```
28+
29+
Now you'll need to pick a host to deploy it to.
30+
31+
### DIY
32+
33+
If you're familiar with deploying node applications, the built-in Remix app server is production-ready.
34+
35+
Make sure to deploy the output of `remix build`
36+
37+
- `build/`
38+
- `public/build/`

app/entry.client.tsx

+18
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+
});

app/entry.server.tsx

+137
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
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+
loadContext: AppLoadContext
23+
) {
24+
return isbot(request.headers.get("user-agent"))
25+
? handleBotRequest(
26+
request,
27+
responseStatusCode,
28+
responseHeaders,
29+
remixContext
30+
)
31+
: handleBrowserRequest(
32+
request,
33+
responseStatusCode,
34+
responseHeaders,
35+
remixContext
36+
);
37+
}
38+
39+
function handleBotRequest(
40+
request: Request,
41+
responseStatusCode: number,
42+
responseHeaders: Headers,
43+
remixContext: EntryContext
44+
) {
45+
return new Promise((resolve, reject) => {
46+
let shellRendered = false;
47+
const { pipe, abort } = renderToPipeableStream(
48+
<RemixServer
49+
context={remixContext}
50+
url={request.url}
51+
abortDelay={ABORT_DELAY}
52+
/>,
53+
{
54+
onAllReady() {
55+
shellRendered = true;
56+
const body = new PassThrough();
57+
const stream = createReadableStreamFromReadable(body);
58+
59+
responseHeaders.set("Content-Type", "text/html");
60+
61+
resolve(
62+
new Response(stream, {
63+
headers: responseHeaders,
64+
status: responseStatusCode,
65+
})
66+
);
67+
68+
pipe(body);
69+
},
70+
onShellError(error: unknown) {
71+
reject(error);
72+
},
73+
onError(error: unknown) {
74+
responseStatusCode = 500;
75+
// Log streaming rendering errors from inside the shell. Don't log
76+
// errors encountered during initial shell rendering since they'll
77+
// reject and get logged in handleDocumentRequest.
78+
if (shellRendered) {
79+
console.error(error);
80+
}
81+
},
82+
}
83+
);
84+
85+
setTimeout(abort, ABORT_DELAY);
86+
});
87+
}
88+
89+
function handleBrowserRequest(
90+
request: Request,
91+
responseStatusCode: number,
92+
responseHeaders: Headers,
93+
remixContext: EntryContext
94+
) {
95+
return new Promise((resolve, reject) => {
96+
let shellRendered = false;
97+
const { pipe, abort } = renderToPipeableStream(
98+
<RemixServer
99+
context={remixContext}
100+
url={request.url}
101+
abortDelay={ABORT_DELAY}
102+
/>,
103+
{
104+
onShellReady() {
105+
shellRendered = true;
106+
const body = new PassThrough();
107+
const stream = createReadableStreamFromReadable(body);
108+
109+
responseHeaders.set("Content-Type", "text/html");
110+
111+
resolve(
112+
new Response(stream, {
113+
headers: responseHeaders,
114+
status: responseStatusCode,
115+
})
116+
);
117+
118+
pipe(body);
119+
},
120+
onShellError(error: unknown) {
121+
reject(error);
122+
},
123+
onError(error: unknown) {
124+
responseStatusCode = 500;
125+
// Log streaming rendering errors from inside the shell. Don't log
126+
// errors encountered during initial shell rendering since they'll
127+
// reject and get logged in handleDocumentRequest.
128+
if (shellRendered) {
129+
console.error(error);
130+
}
131+
},
132+
}
133+
);
134+
135+
setTimeout(abort, ABORT_DELAY);
136+
});
137+
}

app/root.tsx

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { cssBundleHref } from "@remix-run/css-bundle";
2+
import type { LinksFunction } from "@remix-run/node";
3+
import {
4+
Links,
5+
LiveReload,
6+
Meta,
7+
Outlet,
8+
Scripts,
9+
ScrollRestoration,
10+
} from "@remix-run/react";
11+
12+
export const links: LinksFunction = () => [
13+
...(cssBundleHref ? [{ rel: "stylesheet", href: cssBundleHref }] : []),
14+
];
15+
16+
export default function App() {
17+
return (
18+
<html lang="en">
19+
<head>
20+
<meta charSet="utf-8" />
21+
<meta name="viewport" content="width=device-width, initial-scale=1" />
22+
<Meta />
23+
<Links />
24+
</head>
25+
<body>
26+
<Outlet />
27+
<ScrollRestoration />
28+
<Scripts />
29+
<LiveReload />
30+
</body>
31+
</html>
32+
);
33+
}

app/routes/_index.tsx

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import type { MetaFunction } from "@remix-run/node";
2+
3+
export const meta: MetaFunction = () => {
4+
return [
5+
{ title: "New Remix App" },
6+
{ name: "description", content: "Welcome to Remix!" },
7+
];
8+
};
9+
10+
export default function Index() {
11+
return (
12+
<div style={{ fontFamily: "system-ui, sans-serif", lineHeight: "1.8" }}>
13+
<h1>Welcome to Remix</h1>
14+
<ul>
15+
<li>
16+
<a
17+
target="_blank"
18+
href="https://remix.run/tutorials/blog"
19+
rel="noreferrer"
20+
>
21+
15m Quickstart Blog Tutorial
22+
</a>
23+
</li>
24+
<li>
25+
<a
26+
target="_blank"
27+
href="https://remix.run/tutorials/jokes"
28+
rel="noreferrer"
29+
>
30+
Deep Dive Jokes App Tutorial
31+
</a>
32+
</li>
33+
<li>
34+
<a target="_blank" href="https://remix.run/docs" rel="noreferrer">
35+
Remix Docs
36+
</a>
37+
</li>
38+
</ul>
39+
</div>
40+
);
41+
}

0 commit comments

Comments
 (0)