Skip to content

Commit f71172a

Browse files
committed
feat: add remix-3 app demo
1 parent 9d7d56c commit f71172a

5 files changed

Lines changed: 148 additions & 0 deletions

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ steps.
88
* [Hono 4](./hono-4/)
99
* [Lit 3](./lit-3/)
1010
* [Preact 10](./preact-10/)
11+
* [Remix 3](./remix-3/)
1112
* [Solid 1](./solid-1/)
1213
* [Svelte 5](./svelte-5/)
1314
* [Vue 3](./vue-3/)

deno.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
"./hono-*",
55
"./lit-*",
66
"./preact-*",
7+
"./remix-*",
78
"./solid-*",
89
"./svelte-*",
910
"./vue-*"

remix-3/deno.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"imports": {
3+
"@remix-run/dom": "https://esm.sh/*@remix-run/dom@0.0.0-experimental-remix-jam.6?dev",
4+
"@remix-run/dom/": "https://esm.sh/*@remix-run/dom@0.0.0-experimental-remix-jam.6&dev/",
5+
"@remix-run/events": "https://esm.sh/*@remix-run/events@0.0.0-experimental-remix-jam.1?dev",
6+
"@remix-run/events/": "https://esm.sh/*@remix-run/events@0.0.0-experimental-remix-jam.1&dev/",
7+
"@remix-run/style": "https://esm.sh/*@remix-run/style@0.0.0-experimental-remix-jam.1?dev"
8+
}
9+
}

remix-3/index.html

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<!doctype html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>Buildless Remix 3 app</title>
7+
<script type="importmap">
8+
{
9+
"imports": {
10+
"@remix-run/dom": "https://esm.sh/*@remix-run/dom@0.0.0-experimental-remix-jam.6?dev",
11+
"@remix-run/dom/": "https://esm.sh/*@remix-run/dom@0.0.0-experimental-remix-jam.6&dev/",
12+
"@remix-run/events": "https://esm.sh/*@remix-run/events@0.0.0-experimental-remix-jam.1?dev",
13+
"@remix-run/events/": "https://esm.sh/*@remix-run/events@0.0.0-experimental-remix-jam.1&dev/",
14+
"@remix-run/style": "https://esm.sh/*@remix-run/style@0.0.0-experimental-remix-jam.1?dev"
15+
}
16+
}
17+
</script>
18+
<script type="module">
19+
import {
20+
availablePresets,
21+
registerPreset,
22+
} from "https://esm.sh/@babel/standalone@7.28.1";
23+
24+
registerPreset("jsx", {
25+
presets: [[availablePresets["react"], { runtime: "automatic" }]],
26+
});
27+
</script>
28+
<!-- `data-plugins=""` attribute is required for @babel/standalone@7.28.1 -->
29+
<script
30+
type="text/babel"
31+
data-presets="jsx,typescript"
32+
data-plugins=""
33+
data-type="module"
34+
src="./main.tsx"
35+
></script>
36+
</head>
37+
<body></body>
38+
</html>

remix-3/main.tsx

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/** @jsxImportSource @remix-run/dom */
2+
3+
import { createRoot, type Remix } from "@remix-run/dom";
4+
import { dom } from "@remix-run/events";
5+
import type { User } from "jsonplaceholder-types/types/user";
6+
import type { Post } from "jsonplaceholder-types/types/post";
7+
8+
function isAbortError(
9+
error: unknown,
10+
): error is DOMException & { name: "AbortError" } {
11+
return error instanceof DOMException && error.name === "AbortError";
12+
}
13+
14+
function App(this: Remix.Handle) {
15+
let selectedUserId: number | undefined;
16+
let users: User[] | undefined;
17+
let posts: Post[] | undefined;
18+
let loadingUsers = false;
19+
let loadingPosts = false;
20+
21+
const fetchUsers: Remix.Task = async (signal) => {
22+
loadingUsers = true;
23+
try {
24+
const response = await fetch(
25+
"https://jsonplaceholder.typicode.com/users",
26+
{ signal },
27+
);
28+
users = await response.json() as User[];
29+
this.update();
30+
} catch (error) {
31+
if (!isAbortError(error)) {
32+
throw error;
33+
}
34+
} finally {
35+
loadingUsers = false;
36+
}
37+
};
38+
39+
const fetchPosts: Remix.Task = async (signal) => {
40+
loadingPosts = true;
41+
try {
42+
const response = await fetch(
43+
`https://jsonplaceholder.typicode.com/posts?userId=${selectedUserId}`,
44+
{ signal },
45+
);
46+
posts = await response.json() as Post[];
47+
this.update();
48+
} catch (error) {
49+
if (!isAbortError(error)) {
50+
throw error;
51+
}
52+
} finally {
53+
loadingPosts = false;
54+
}
55+
};
56+
57+
const selectUserId = (id: number, signal: AbortSignal) => {
58+
selectedUserId = id;
59+
fetchPosts(signal);
60+
this.update();
61+
};
62+
63+
this.queueTask(fetchUsers);
64+
65+
return () => (
66+
<>
67+
<h1>Buildless Remix 3 app</h1>
68+
{users !== undefined && (
69+
<label>
70+
Select User:
71+
<select
72+
on={[
73+
dom.change(({ currentTarget }, signal) => {
74+
selectUserId(+currentTarget.value, signal);
75+
}),
76+
]}
77+
>
78+
{users.map((user) => (
79+
<option key={user.id} value={user.id}>
80+
@{user.username}: {user.name}
81+
</option>
82+
))}
83+
</select>
84+
</label>
85+
) ||
86+
loadingUsers && <p>Loading Users...</p>}
87+
{posts !== undefined && (
88+
<ul>
89+
{posts.map((post) => <li key={post.id}>{post.title}</li>)}
90+
</ul>
91+
) ||
92+
loadingPosts && <p>Loading Posts...</p> ||
93+
users !== undefined && <p>Select User to view posts</p>}
94+
</>
95+
);
96+
}
97+
98+
const root = createRoot(document.body);
99+
root.render(<App />);

0 commit comments

Comments
 (0)