@evjs/cli 0.0.1-rc.18 → 0.0.1-rc.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -6
- package/dist/index.js +1 -88
- package/package.json +2 -5
- package/templates/basic-csr/README.md +0 -23
- package/templates/basic-csr/index.html +0 -11
- package/templates/basic-csr/package.json +0 -21
- package/templates/basic-csr/src/main.tsx +0 -22
- package/templates/basic-csr/src/pages/__root.tsx +0 -28
- package/templates/basic-csr/src/pages/about.tsx +0 -19
- package/templates/basic-csr/src/pages/home.tsx +0 -19
- package/templates/basic-csr/src/pages/posts/index.tsx +0 -63
- package/templates/basic-csr/tsconfig.json +0 -17
- package/templates/basic-server-fns/README.md +0 -24
- package/templates/basic-server-fns/index.html +0 -11
- package/templates/basic-server-fns/package.json +0 -21
- package/templates/basic-server-fns/src/api/users.server.ts +0 -31
- package/templates/basic-server-fns/src/main.tsx +0 -12
- package/templates/basic-server-fns/src/routes.tsx +0 -108
- package/templates/basic-server-fns/tsconfig.json +0 -16
- package/templates/complex-routing/README.md +0 -27
- package/templates/complex-routing/index.html +0 -11
- package/templates/complex-routing/package.json +0 -21
- package/templates/complex-routing/src/api/data.server.ts +0 -86
- package/templates/complex-routing/src/main.tsx +0 -29
- package/templates/complex-routing/src/pages/__root.tsx +0 -60
- package/templates/complex-routing/src/pages/catch.tsx +0 -26
- package/templates/complex-routing/src/pages/dashboard.tsx +0 -81
- package/templates/complex-routing/src/pages/home.tsx +0 -35
- package/templates/complex-routing/src/pages/posts/index.tsx +0 -104
- package/templates/complex-routing/src/pages/search.tsx +0 -71
- package/templates/complex-routing/src/pages/user.tsx +0 -32
- package/templates/complex-routing/tsconfig.json +0 -13
- package/templates/configured-server-fns/README.md +0 -24
- package/templates/configured-server-fns/ev.config.ts +0 -56
- package/templates/configured-server-fns/index.html +0 -11
- package/templates/configured-server-fns/package.json +0 -21
- package/templates/configured-server-fns/src/api/users.server.ts +0 -22
- package/templates/configured-server-fns/src/main.tsx +0 -12
- package/templates/configured-server-fns/src/routes.tsx +0 -111
- package/templates/configured-server-fns/tsconfig.json +0 -16
- package/templates/with-tailwind/ev.config.ts +0 -20
- package/templates/with-tailwind/index.html +0 -11
- package/templates/with-tailwind/package.json +0 -28
- package/templates/with-tailwind/postcss.config.mjs +0 -5
- package/templates/with-tailwind/src/main.tsx +0 -15
- package/templates/with-tailwind/src/pages/__root.tsx +0 -30
- package/templates/with-tailwind/src/pages/home.tsx +0 -85
- package/templates/with-tailwind/src/styles.css +0 -2
- package/templates/with-tailwind/tsconfig.json +0 -17
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "example-complex-routing",
|
|
3
|
-
"version": "0.0.1-rc.18",
|
|
4
|
-
"private": true,
|
|
5
|
-
"scripts": {
|
|
6
|
-
"dev": "ev dev",
|
|
7
|
-
"build": "ev build",
|
|
8
|
-
"check-types": "tsc --noEmit"
|
|
9
|
-
},
|
|
10
|
-
"dependencies": {
|
|
11
|
-
"@evjs/runtime": "*",
|
|
12
|
-
"react": "^19.2.4",
|
|
13
|
-
"react-dom": "^19.2.4"
|
|
14
|
-
},
|
|
15
|
-
"devDependencies": {
|
|
16
|
-
"@evjs/cli": "*",
|
|
17
|
-
"@types/react": "^19.0.8",
|
|
18
|
-
"@types/react-dom": "^19.0.3",
|
|
19
|
-
"typescript": "^5.7.3"
|
|
20
|
-
}
|
|
21
|
-
}
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
"use server";
|
|
2
|
-
|
|
3
|
-
// ── Mock data ──
|
|
4
|
-
|
|
5
|
-
const posts = [
|
|
6
|
-
{
|
|
7
|
-
id: "1",
|
|
8
|
-
title: "Getting Started with evjs",
|
|
9
|
-
body: "evjs is a zero-config React meta-framework...",
|
|
10
|
-
author: "alice",
|
|
11
|
-
tags: ["intro", "tutorial"],
|
|
12
|
-
},
|
|
13
|
-
{
|
|
14
|
-
id: "2",
|
|
15
|
-
title: "Server Functions Deep Dive",
|
|
16
|
-
body: 'Server functions use the "use server" directive...',
|
|
17
|
-
author: "bob",
|
|
18
|
-
tags: ["server", "advanced"],
|
|
19
|
-
},
|
|
20
|
-
{
|
|
21
|
-
id: "3",
|
|
22
|
-
title: "Routing Patterns",
|
|
23
|
-
body: "evjs uses TanStack Router for type-safe routing...",
|
|
24
|
-
author: "alice",
|
|
25
|
-
tags: ["routing", "tutorial"],
|
|
26
|
-
},
|
|
27
|
-
{
|
|
28
|
-
id: "4",
|
|
29
|
-
title: "WebSocket Transport",
|
|
30
|
-
body: "You can swap HTTP for WebSocket transport...",
|
|
31
|
-
author: "charlie",
|
|
32
|
-
tags: ["transport", "advanced"],
|
|
33
|
-
},
|
|
34
|
-
{
|
|
35
|
-
id: "5",
|
|
36
|
-
title: "Deploying to Edge",
|
|
37
|
-
body: "Run your evjs app on Deno, Bun, or Workers...",
|
|
38
|
-
author: "bob",
|
|
39
|
-
tags: ["deploy", "edge"],
|
|
40
|
-
},
|
|
41
|
-
];
|
|
42
|
-
|
|
43
|
-
const users: Record<string, { name: string; bio: string }> = {
|
|
44
|
-
alice: { name: "Alice", bio: "Core contributor" },
|
|
45
|
-
bob: { name: "Bob", bio: "Technical writer" },
|
|
46
|
-
charlie: { name: "Charlie", bio: "DevOps engineer" },
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
// ── Server functions ──
|
|
50
|
-
|
|
51
|
-
export async function getPosts(query?: string) {
|
|
52
|
-
await delay(50);
|
|
53
|
-
if (!query) return posts;
|
|
54
|
-
const q = query.toLowerCase();
|
|
55
|
-
return posts.filter(
|
|
56
|
-
(p) =>
|
|
57
|
-
p.title.toLowerCase().includes(q) || p.tags.some((t) => t.includes(q)),
|
|
58
|
-
);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
export async function getPost(id: string) {
|
|
62
|
-
await delay(50);
|
|
63
|
-
const post = posts.find((p) => p.id === id);
|
|
64
|
-
if (!post) throw new Error(`Post ${id} not found`);
|
|
65
|
-
return post;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export async function getUser(username: string) {
|
|
69
|
-
await delay(50);
|
|
70
|
-
const user = users[username];
|
|
71
|
-
if (!user) throw new Error(`User ${username} not found`);
|
|
72
|
-
return { username, ...user };
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
export async function getStats() {
|
|
76
|
-
await delay(50);
|
|
77
|
-
return {
|
|
78
|
-
totalPosts: posts.length,
|
|
79
|
-
totalUsers: Object.keys(users).length,
|
|
80
|
-
tags: [...new Set(posts.flatMap((p) => p.tags))],
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
function delay(ms: number) {
|
|
85
|
-
return new Promise((r) => setTimeout(r, ms));
|
|
86
|
-
}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { createApp } from "@evjs/runtime/client";
|
|
2
|
-
import { rootRoute } from "./pages/__root";
|
|
3
|
-
import { notFoundRoute, redirectRoute } from "./pages/catch";
|
|
4
|
-
import { dashboardLayout, dashboardRoute } from "./pages/dashboard";
|
|
5
|
-
import { homeRoute } from "./pages/home";
|
|
6
|
-
import { postDetailRoute, postsIndexRoute, postsRoute } from "./pages/posts";
|
|
7
|
-
import { searchRoute } from "./pages/search";
|
|
8
|
-
import { userRoute } from "./pages/user";
|
|
9
|
-
|
|
10
|
-
const routeTree = rootRoute.addChildren([
|
|
11
|
-
homeRoute,
|
|
12
|
-
postsRoute.addChildren([postsIndexRoute, postDetailRoute]),
|
|
13
|
-
userRoute,
|
|
14
|
-
dashboardLayout.addChildren([dashboardRoute]),
|
|
15
|
-
searchRoute,
|
|
16
|
-
redirectRoute,
|
|
17
|
-
notFoundRoute,
|
|
18
|
-
]);
|
|
19
|
-
|
|
20
|
-
const app = createApp({ routeTree });
|
|
21
|
-
|
|
22
|
-
// Register router type for full IDE type-safety on useParams, useSearch, Link, etc.
|
|
23
|
-
declare module "@tanstack/react-router" {
|
|
24
|
-
interface Register {
|
|
25
|
-
router: typeof app.router;
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
app.render("#app");
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import { createAppRootRoute, Link, Outlet } from "@evjs/runtime/client";
|
|
2
|
-
|
|
3
|
-
const styles = {
|
|
4
|
-
app: {
|
|
5
|
-
fontFamily: "system-ui, sans-serif",
|
|
6
|
-
maxWidth: 900,
|
|
7
|
-
margin: "0 auto",
|
|
8
|
-
padding: "1rem",
|
|
9
|
-
},
|
|
10
|
-
nav: {
|
|
11
|
-
display: "flex",
|
|
12
|
-
gap: "1rem",
|
|
13
|
-
padding: "0.75rem 0",
|
|
14
|
-
borderBottom: "1px solid #e5e7eb",
|
|
15
|
-
marginBottom: "1rem",
|
|
16
|
-
},
|
|
17
|
-
link: { textDecoration: "none", color: "#6b7280" },
|
|
18
|
-
activeLink: { color: "#111", fontWeight: 600 as const },
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
function RootLayout() {
|
|
22
|
-
return (
|
|
23
|
-
<div style={styles.app}>
|
|
24
|
-
<nav style={styles.nav}>
|
|
25
|
-
<Link
|
|
26
|
-
to="/"
|
|
27
|
-
style={styles.link}
|
|
28
|
-
activeProps={{ style: styles.activeLink }}
|
|
29
|
-
>
|
|
30
|
-
Home
|
|
31
|
-
</Link>
|
|
32
|
-
<Link
|
|
33
|
-
to="/posts"
|
|
34
|
-
style={styles.link}
|
|
35
|
-
activeProps={{ style: styles.activeLink }}
|
|
36
|
-
>
|
|
37
|
-
Posts
|
|
38
|
-
</Link>
|
|
39
|
-
<Link
|
|
40
|
-
to="/dashboard"
|
|
41
|
-
style={styles.link}
|
|
42
|
-
activeProps={{ style: styles.activeLink }}
|
|
43
|
-
>
|
|
44
|
-
Dashboard
|
|
45
|
-
</Link>
|
|
46
|
-
<Link
|
|
47
|
-
to="/search"
|
|
48
|
-
search={{ q: "" }}
|
|
49
|
-
style={styles.link}
|
|
50
|
-
activeProps={{ style: styles.activeLink }}
|
|
51
|
-
>
|
|
52
|
-
Search
|
|
53
|
-
</Link>
|
|
54
|
-
</nav>
|
|
55
|
-
<Outlet />
|
|
56
|
-
</div>
|
|
57
|
-
);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
export const rootRoute = createAppRootRoute({ component: RootLayout });
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { createRoute, Link, redirect } from "@evjs/runtime/client";
|
|
2
|
-
import { rootRoute } from "./__root";
|
|
3
|
-
|
|
4
|
-
// ── Redirect: /old-blog → /posts ──
|
|
5
|
-
|
|
6
|
-
export const redirectRoute = createRoute({
|
|
7
|
-
getParentRoute: () => rootRoute,
|
|
8
|
-
path: "/old-blog",
|
|
9
|
-
beforeLoad: () => {
|
|
10
|
-
throw redirect({ to: "/posts" });
|
|
11
|
-
},
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
// ── 404 Catch-all ──
|
|
15
|
-
|
|
16
|
-
export const notFoundRoute = createRoute({
|
|
17
|
-
getParentRoute: () => rootRoute,
|
|
18
|
-
path: "*",
|
|
19
|
-
component: () => (
|
|
20
|
-
<div style={{ textAlign: "center", padding: "3rem" }}>
|
|
21
|
-
<h1 style={{ fontSize: 48 }}>404</h1>
|
|
22
|
-
<p style={{ color: "#6b7280" }}>Page not found</p>
|
|
23
|
-
<Link to="/">← Go home</Link>
|
|
24
|
-
</div>
|
|
25
|
-
),
|
|
26
|
-
});
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
import { createRoute, Outlet, query } from "@evjs/runtime/client";
|
|
2
|
-
import { getStats } from "../api/data.server";
|
|
3
|
-
import { rootRoute } from "./__root";
|
|
4
|
-
|
|
5
|
-
const styles = {
|
|
6
|
-
card: {
|
|
7
|
-
border: "1px solid #e5e7eb",
|
|
8
|
-
borderRadius: 8,
|
|
9
|
-
padding: "1rem",
|
|
10
|
-
marginBottom: "0.75rem",
|
|
11
|
-
},
|
|
12
|
-
stat: { textAlign: "center" as const, padding: "1rem" },
|
|
13
|
-
tag: {
|
|
14
|
-
display: "inline-block",
|
|
15
|
-
background: "#f3f4f6",
|
|
16
|
-
borderRadius: 4,
|
|
17
|
-
padding: "2px 8px",
|
|
18
|
-
fontSize: 12,
|
|
19
|
-
marginRight: 4,
|
|
20
|
-
},
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
// ── Pathless layout (no URL segment, just shared UI) ──
|
|
24
|
-
|
|
25
|
-
export const dashboardLayout = createRoute({
|
|
26
|
-
getParentRoute: () => rootRoute,
|
|
27
|
-
id: "dashboard-layout",
|
|
28
|
-
component: () => (
|
|
29
|
-
<div>
|
|
30
|
-
<Outlet />
|
|
31
|
-
</div>
|
|
32
|
-
),
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
// ── Dashboard page (/dashboard) ──
|
|
36
|
-
|
|
37
|
-
function Dashboard() {
|
|
38
|
-
const { data: stats } = query(getStats).useQuery();
|
|
39
|
-
if (!stats) return <p>Loading...</p>;
|
|
40
|
-
return (
|
|
41
|
-
<div>
|
|
42
|
-
<h2>Dashboard</h2>
|
|
43
|
-
<div style={{ display: "flex", gap: "1rem" }}>
|
|
44
|
-
<div style={{ ...styles.card, ...styles.stat }}>
|
|
45
|
-
<div style={{ fontSize: 32, fontWeight: 700 }}>
|
|
46
|
-
{stats.totalPosts}
|
|
47
|
-
</div>
|
|
48
|
-
<div style={{ color: "#6b7280" }}>Posts</div>
|
|
49
|
-
</div>
|
|
50
|
-
<div style={{ ...styles.card, ...styles.stat }}>
|
|
51
|
-
<div style={{ fontSize: 32, fontWeight: 700 }}>
|
|
52
|
-
{stats.totalUsers}
|
|
53
|
-
</div>
|
|
54
|
-
<div style={{ color: "#6b7280" }}>Users</div>
|
|
55
|
-
</div>
|
|
56
|
-
<div style={{ ...styles.card, ...styles.stat }}>
|
|
57
|
-
<div style={{ fontSize: 32, fontWeight: 700 }}>
|
|
58
|
-
{stats.tags.length}
|
|
59
|
-
</div>
|
|
60
|
-
<div style={{ color: "#6b7280" }}>Tags</div>
|
|
61
|
-
</div>
|
|
62
|
-
</div>
|
|
63
|
-
<h3>All Tags</h3>
|
|
64
|
-
<div>
|
|
65
|
-
{stats.tags.map((t) => (
|
|
66
|
-
<span key={t} style={styles.tag}>
|
|
67
|
-
{t}
|
|
68
|
-
</span>
|
|
69
|
-
))}
|
|
70
|
-
</div>
|
|
71
|
-
</div>
|
|
72
|
-
);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
export const dashboardRoute = createRoute({
|
|
76
|
-
getParentRoute: () => dashboardLayout,
|
|
77
|
-
path: "/dashboard",
|
|
78
|
-
loader: ({ context }) =>
|
|
79
|
-
context.queryClient.ensureQueryData(query(getStats).queryOptions()),
|
|
80
|
-
component: Dashboard,
|
|
81
|
-
});
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { createRoute, Link } from "@evjs/runtime/client";
|
|
2
|
-
import { rootRoute } from "./__root";
|
|
3
|
-
|
|
4
|
-
export const homeRoute = createRoute({
|
|
5
|
-
getParentRoute: () => rootRoute,
|
|
6
|
-
path: "/",
|
|
7
|
-
component: () => (
|
|
8
|
-
<div>
|
|
9
|
-
<h1>evjs Complex Routing Example</h1>
|
|
10
|
-
<p>
|
|
11
|
-
Demonstrates nested layouts, dynamic params, search params, redirects,
|
|
12
|
-
and server function loaders.
|
|
13
|
-
</p>
|
|
14
|
-
<ul>
|
|
15
|
-
<li>
|
|
16
|
-
<Link to="/posts">Posts</Link> — nested group with dynamic{" "}
|
|
17
|
-
<code>$postId</code>
|
|
18
|
-
</li>
|
|
19
|
-
<li>
|
|
20
|
-
<Link to="/dashboard">Dashboard</Link> — pathless layout with server
|
|
21
|
-
function loader
|
|
22
|
-
</li>
|
|
23
|
-
<li>
|
|
24
|
-
<Link to="/search" search={{ q: "tutorial" }}>
|
|
25
|
-
Search
|
|
26
|
-
</Link>{" "}
|
|
27
|
-
— search params
|
|
28
|
-
</li>
|
|
29
|
-
<li>
|
|
30
|
-
<Link to="/old-blog">Old Blog</Link> — redirect to /posts
|
|
31
|
-
</li>
|
|
32
|
-
</ul>
|
|
33
|
-
</div>
|
|
34
|
-
),
|
|
35
|
-
});
|
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
import { createRoute, Link, Outlet, query } from "@evjs/runtime/client";
|
|
2
|
-
import { getPost, getPosts } from "../../api/data.server";
|
|
3
|
-
import { rootRoute } from "../__root";
|
|
4
|
-
|
|
5
|
-
const styles = {
|
|
6
|
-
sidebar: { display: "flex", gap: "1.5rem" },
|
|
7
|
-
nav: {
|
|
8
|
-
minWidth: 180,
|
|
9
|
-
borderRight: "1px solid #e5e7eb",
|
|
10
|
-
paddingRight: "1rem",
|
|
11
|
-
},
|
|
12
|
-
tag: {
|
|
13
|
-
display: "inline-block",
|
|
14
|
-
background: "#f3f4f6",
|
|
15
|
-
borderRadius: 4,
|
|
16
|
-
padding: "2px 8px",
|
|
17
|
-
fontSize: 12,
|
|
18
|
-
marginRight: 4,
|
|
19
|
-
},
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
// ── Posts layout (/posts) ──
|
|
23
|
-
|
|
24
|
-
function PostsLayout() {
|
|
25
|
-
const { data: posts } = query(getPosts).useQuery();
|
|
26
|
-
return (
|
|
27
|
-
<div style={styles.sidebar}>
|
|
28
|
-
<div style={styles.nav}>
|
|
29
|
-
<h3 style={{ marginTop: 0 }}>Posts</h3>
|
|
30
|
-
<ul style={{ listStyle: "none", padding: 0 }}>
|
|
31
|
-
{posts?.map((p) => (
|
|
32
|
-
<li key={p.id} style={{ marginBottom: "0.25rem" }}>
|
|
33
|
-
<Link
|
|
34
|
-
to="/posts/$postId"
|
|
35
|
-
params={{ postId: p.id }}
|
|
36
|
-
style={{ textDecoration: "none", color: "#374151" }}
|
|
37
|
-
activeProps={{ style: { fontWeight: "bold", color: "#111" } }}
|
|
38
|
-
>
|
|
39
|
-
{p.title}
|
|
40
|
-
</Link>
|
|
41
|
-
</li>
|
|
42
|
-
))}
|
|
43
|
-
</ul>
|
|
44
|
-
</div>
|
|
45
|
-
<div style={{ flex: 1 }}>
|
|
46
|
-
<Outlet />
|
|
47
|
-
</div>
|
|
48
|
-
</div>
|
|
49
|
-
);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export const postsRoute = createRoute({
|
|
53
|
-
getParentRoute: () => rootRoute,
|
|
54
|
-
path: "/posts",
|
|
55
|
-
component: PostsLayout,
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
// ── Posts index (/posts/) ──
|
|
59
|
-
|
|
60
|
-
export const postsIndexRoute = createRoute({
|
|
61
|
-
getParentRoute: () => postsRoute,
|
|
62
|
-
path: "/",
|
|
63
|
-
component: () => (
|
|
64
|
-
<p style={{ color: "#6b7280" }}>← Select a post from the sidebar</p>
|
|
65
|
-
),
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
// ── Post detail (/posts/$postId) ──
|
|
69
|
-
|
|
70
|
-
function PostDetail() {
|
|
71
|
-
const { postId } = postDetailRoute.useParams();
|
|
72
|
-
const { data: post } = query(getPost).useQuery(postId);
|
|
73
|
-
|
|
74
|
-
if (!post) return <p>Loading...</p>;
|
|
75
|
-
return (
|
|
76
|
-
<div>
|
|
77
|
-
<h2>{post.title}</h2>
|
|
78
|
-
<p style={{ color: "#6b7280" }}>
|
|
79
|
-
by{" "}
|
|
80
|
-
<Link to="/users/$username" params={{ username: post.author }}>
|
|
81
|
-
{post.author}
|
|
82
|
-
</Link>
|
|
83
|
-
</p>
|
|
84
|
-
<p>{post.body}</p>
|
|
85
|
-
<div>
|
|
86
|
-
{post.tags.map((tag) => (
|
|
87
|
-
<span key={tag} style={styles.tag}>
|
|
88
|
-
{tag}
|
|
89
|
-
</span>
|
|
90
|
-
))}
|
|
91
|
-
</div>
|
|
92
|
-
</div>
|
|
93
|
-
);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
export const postDetailRoute = createRoute({
|
|
97
|
-
getParentRoute: () => postsRoute,
|
|
98
|
-
path: "$postId",
|
|
99
|
-
loader: ({ params, context }) =>
|
|
100
|
-
context.queryClient.ensureQueryData(
|
|
101
|
-
query(getPost).queryOptions(params.postId),
|
|
102
|
-
),
|
|
103
|
-
component: PostDetail,
|
|
104
|
-
});
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import { createRoute, Link, query } from "@evjs/runtime/client";
|
|
2
|
-
import { getPosts } from "../api/data.server";
|
|
3
|
-
import { rootRoute } from "./__root";
|
|
4
|
-
|
|
5
|
-
const styles = {
|
|
6
|
-
card: {
|
|
7
|
-
border: "1px solid #e5e7eb",
|
|
8
|
-
borderRadius: 8,
|
|
9
|
-
padding: "1rem",
|
|
10
|
-
marginBottom: "0.75rem",
|
|
11
|
-
},
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
function SearchPage() {
|
|
15
|
-
const { q } = searchRoute.useSearch();
|
|
16
|
-
const { data: results } = query(getPosts).useQuery(q || undefined);
|
|
17
|
-
|
|
18
|
-
return (
|
|
19
|
-
<div>
|
|
20
|
-
<h2>Search</h2>
|
|
21
|
-
<form
|
|
22
|
-
onSubmit={(e) => {
|
|
23
|
-
e.preventDefault();
|
|
24
|
-
const form = new FormData(e.currentTarget);
|
|
25
|
-
const q = form.get("q") as string;
|
|
26
|
-
window.location.search = `?q=${encodeURIComponent(q)}`;
|
|
27
|
-
}}
|
|
28
|
-
>
|
|
29
|
-
<input
|
|
30
|
-
name="q"
|
|
31
|
-
defaultValue={q}
|
|
32
|
-
placeholder="Search posts..."
|
|
33
|
-
style={{
|
|
34
|
-
padding: "0.5rem",
|
|
35
|
-
width: 300,
|
|
36
|
-
borderRadius: 4,
|
|
37
|
-
border: "1px solid #d1d5db",
|
|
38
|
-
}}
|
|
39
|
-
/>
|
|
40
|
-
</form>
|
|
41
|
-
<div style={{ marginTop: "1rem" }}>
|
|
42
|
-
{q && <p style={{ color: "#6b7280" }}>Results for "{q}":</p>}
|
|
43
|
-
{results?.map((post) => (
|
|
44
|
-
<div key={post.id} style={styles.card}>
|
|
45
|
-
<Link
|
|
46
|
-
to="/posts/$postId"
|
|
47
|
-
params={{ postId: post.id }}
|
|
48
|
-
style={{ textDecoration: "none", color: "#111" }}
|
|
49
|
-
>
|
|
50
|
-
<strong>{post.title}</strong>
|
|
51
|
-
</Link>
|
|
52
|
-
<p
|
|
53
|
-
style={{ margin: "0.25rem 0 0", color: "#6b7280", fontSize: 14 }}
|
|
54
|
-
>
|
|
55
|
-
{post.body}
|
|
56
|
-
</p>
|
|
57
|
-
</div>
|
|
58
|
-
))}
|
|
59
|
-
</div>
|
|
60
|
-
</div>
|
|
61
|
-
);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export const searchRoute = createRoute({
|
|
65
|
-
getParentRoute: () => rootRoute,
|
|
66
|
-
path: "/search",
|
|
67
|
-
validateSearch: (search: Record<string, unknown>) => ({
|
|
68
|
-
q: (search.q as string) || "",
|
|
69
|
-
}),
|
|
70
|
-
component: SearchPage,
|
|
71
|
-
});
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { createRoute, Link, query } from "@evjs/runtime/client";
|
|
2
|
-
import { getUser } from "../api/data.server";
|
|
3
|
-
import { rootRoute } from "./__root";
|
|
4
|
-
|
|
5
|
-
const styles = {
|
|
6
|
-
card: { border: "1px solid #e5e7eb", borderRadius: 8, padding: "1rem" },
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
function UserProfile() {
|
|
10
|
-
const { username } = userRoute.useParams();
|
|
11
|
-
const { data: user } = query(getUser).useQuery(username);
|
|
12
|
-
|
|
13
|
-
if (!user) return <p>Loading...</p>;
|
|
14
|
-
return (
|
|
15
|
-
<div style={styles.card}>
|
|
16
|
-
<h2>{user.name}</h2>
|
|
17
|
-
<p style={{ color: "#6b7280" }}>@{user.username}</p>
|
|
18
|
-
<p>{user.bio}</p>
|
|
19
|
-
<Link to="/posts">← Back to posts</Link>
|
|
20
|
-
</div>
|
|
21
|
-
);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export const userRoute = createRoute({
|
|
25
|
-
getParentRoute: () => rootRoute,
|
|
26
|
-
path: "/users/$username",
|
|
27
|
-
loader: ({ params, context }) =>
|
|
28
|
-
context.queryClient.ensureQueryData(
|
|
29
|
-
query(getUser).queryOptions(params.username),
|
|
30
|
-
),
|
|
31
|
-
component: UserProfile,
|
|
32
|
-
});
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
# configured-server-fns
|
|
2
|
-
|
|
3
|
-
Server functions with `ev.config.ts` and module-level query/mutation proxies.
|
|
4
|
-
|
|
5
|
-
## Run
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
npm run dev -w example-configured-server-fns
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
## Key Files
|
|
12
|
-
|
|
13
|
-
| File | Purpose |
|
|
14
|
-
|------|---------|
|
|
15
|
-
| `ev.config.ts` | Custom ports and settings |
|
|
16
|
-
| `src/routes.tsx` | Routes with `createQueryProxy` / `createMutationProxy` |
|
|
17
|
-
| `src/api/users.server.ts` | User CRUD functions |
|
|
18
|
-
|
|
19
|
-
## What It Demonstrates
|
|
20
|
-
|
|
21
|
-
- `ev.config.ts` with `defineConfig` for custom ports
|
|
22
|
-
- `createQueryProxy(module)` for grouped queries
|
|
23
|
-
- `createMutationProxy(module)` for grouped mutations
|
|
24
|
-
- Direct mutation args: `mutate({ name, email })` (not array-wrapped)
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import { defineConfig } from "@evjs/cli";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Advanced ev.config.ts example.
|
|
5
|
-
*
|
|
6
|
-
* This file demonstrates all available configuration options.
|
|
7
|
-
* All fields are optional — evjs works out of the box.
|
|
8
|
-
*/
|
|
9
|
-
export default defineConfig({
|
|
10
|
-
client: {
|
|
11
|
-
// Client entry point (default: "./src/main.tsx")
|
|
12
|
-
entry: "./src/main.tsx",
|
|
13
|
-
|
|
14
|
-
// HTML template (default: "./index.html")
|
|
15
|
-
html: "./index.html",
|
|
16
|
-
|
|
17
|
-
// Dev server options (merged with built-in defaults)
|
|
18
|
-
dev: {
|
|
19
|
-
// Dev server port (default: 3000)
|
|
20
|
-
port: 4000,
|
|
21
|
-
|
|
22
|
-
// Any dev server options can be added here:
|
|
23
|
-
// https: true,
|
|
24
|
-
// open: true,
|
|
25
|
-
// historyApiFallback: true,
|
|
26
|
-
},
|
|
27
|
-
|
|
28
|
-
// Transport configuration for server function calls
|
|
29
|
-
transport: {
|
|
30
|
-
// Base URL for server function endpoint (default: same origin)
|
|
31
|
-
// baseUrl: "https://api.example.com",
|
|
32
|
-
|
|
33
|
-
// Server function endpoint path (default: "/api/fn")
|
|
34
|
-
endpoint: "/api/fn",
|
|
35
|
-
},
|
|
36
|
-
},
|
|
37
|
-
|
|
38
|
-
server: {
|
|
39
|
-
// Server function endpoint path (default: "/api/fn")
|
|
40
|
-
endpoint: "/api/fn",
|
|
41
|
-
|
|
42
|
-
// Server backend command (default: "node")
|
|
43
|
-
// Supports: "node", "bun", "deno run --allow-net", etc.
|
|
44
|
-
backend: "node",
|
|
45
|
-
|
|
46
|
-
// Middleware module paths to auto-register in server entry
|
|
47
|
-
// These are imported and applied in order
|
|
48
|
-
// middleware: ["./src/middleware/auth.ts", "./src/middleware/cors.ts"],
|
|
49
|
-
|
|
50
|
-
// Dev server options
|
|
51
|
-
dev: {
|
|
52
|
-
// API server port in dev mode (default: 3001)
|
|
53
|
-
port: 4001,
|
|
54
|
-
},
|
|
55
|
-
},
|
|
56
|
-
});
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8" />
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
-
<title>Configured Server Functions Example</title>
|
|
7
|
-
</head>
|
|
8
|
-
<body>
|
|
9
|
-
<div id="app"></div>
|
|
10
|
-
</body>
|
|
11
|
-
</html>
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "example-configured-server-fns",
|
|
3
|
-
"version": "0.0.1-rc.18",
|
|
4
|
-
"private": true,
|
|
5
|
-
"scripts": {
|
|
6
|
-
"dev": "ev dev",
|
|
7
|
-
"build": "ev build",
|
|
8
|
-
"check-types": "tsc --noEmit"
|
|
9
|
-
},
|
|
10
|
-
"dependencies": {
|
|
11
|
-
"@evjs/runtime": "*",
|
|
12
|
-
"react": "^19.2.4",
|
|
13
|
-
"react-dom": "^19.2.4"
|
|
14
|
-
},
|
|
15
|
-
"devDependencies": {
|
|
16
|
-
"@evjs/cli": "*",
|
|
17
|
-
"@types/react": "^19.1.8",
|
|
18
|
-
"@types/react-dom": "^19.1.8",
|
|
19
|
-
"typescript": "^5.7.3"
|
|
20
|
-
}
|
|
21
|
-
}
|