@evjs/cli 0.0.1-rc.18 → 0.0.1-rc.28
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 +4 -8
- package/dist/create-webpack-config.js +5 -2
- package/dist/index.js +5 -91
- package/package.json +7 -10
- 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
package/README.md
CHANGED
|
@@ -22,14 +22,10 @@ No configuration file is needed. `ev dev` and `ev build` work out of the box wit
|
|
|
22
22
|
|
|
23
23
|
| Command | Description |
|
|
24
24
|
|---------|-------------|
|
|
25
|
-
| `ev init [name]` | Scaffold a new project from a template |
|
|
26
25
|
| `ev dev` | Start dev server (client HMR + API watch) |
|
|
27
26
|
| `ev build` | Production build (client + server) |
|
|
28
27
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
Templates: `basic-csr`, `basic-server-fns`, `configured-server-fns`, `complex-routing`, `with-tailwind`.
|
|
32
|
-
Option: `-t, --template <template>` to skip interactive selection.
|
|
28
|
+
> **Scaffolding:** Use `npx @evjs/create-app` to scaffold a new project.
|
|
33
29
|
|
|
34
30
|
### `ev dev`
|
|
35
31
|
|
|
@@ -59,7 +55,7 @@ export default defineConfig({
|
|
|
59
55
|
},
|
|
60
56
|
server: {
|
|
61
57
|
endpoint: "/api/fn",
|
|
62
|
-
|
|
58
|
+
|
|
63
59
|
dev: { port: 3001 },
|
|
64
60
|
},
|
|
65
61
|
});
|
|
@@ -81,7 +77,7 @@ my-app/
|
|
|
81
77
|
├── api/ # server functions
|
|
82
78
|
│ ├── users.server.ts
|
|
83
79
|
│ └── posts.server.ts
|
|
84
|
-
|
|
80
|
+
|
|
85
81
|
└── auth.ts
|
|
86
82
|
```
|
|
87
83
|
|
|
@@ -90,7 +86,7 @@ my-app/
|
|
|
90
86
|
1. **Don't create `webpack.config.cjs`** — use `ev.config.ts` instead
|
|
91
87
|
2. **Don't install webpack manually** — it's a dependency of `@evjs/cli`
|
|
92
88
|
3. **Config file must be `ev.config.ts`** — not `evjs.config.ts`
|
|
93
|
-
4. **Import `defineConfig` from `@evjs/cli`** — not from `@evjs/
|
|
89
|
+
4. **Import `defineConfig` from `@evjs/cli`** — not from `@evjs/server`
|
|
94
90
|
|
|
95
91
|
## Bundled Dependencies
|
|
96
92
|
|
|
@@ -19,8 +19,8 @@ export function createWebpackConfig(config, cwd) {
|
|
|
19
19
|
const isProduction = process.env.NODE_ENV === "production";
|
|
20
20
|
const HtmlWebpackPlugin = esmRequire("html-webpack-plugin");
|
|
21
21
|
const { EvWebpackPlugin } = esmRequire("@evjs/webpack-plugin");
|
|
22
|
-
const pluginOptions = server
|
|
23
|
-
? { server: {
|
|
22
|
+
const pluginOptions = server
|
|
23
|
+
? { server: { entry: server.entry } }
|
|
24
24
|
: undefined;
|
|
25
25
|
// Resolve loader paths from evjs's dependency tree so they work
|
|
26
26
|
// even when the user's project doesn't list them as direct deps.
|
|
@@ -93,6 +93,9 @@ export function createWebpackConfig(config, cwd) {
|
|
|
93
93
|
plugins: [
|
|
94
94
|
new HtmlWebpackPlugin({ template: html }),
|
|
95
95
|
new EvWebpackPlugin(pluginOptions),
|
|
96
|
+
...(!isProduction
|
|
97
|
+
? [new (esmRequire("webpack").HotModuleReplacementPlugin)()]
|
|
98
|
+
: []),
|
|
96
99
|
],
|
|
97
100
|
optimization: isProduction
|
|
98
101
|
? { splitChunks: { chunks: "all" } }
|
package/dist/index.js
CHANGED
|
@@ -6,7 +6,6 @@ import { configure, getConsoleSink, getLogger } from "@logtape/logtape";
|
|
|
6
6
|
import { Command } from "commander";
|
|
7
7
|
import { execa } from "execa";
|
|
8
8
|
import fs from "fs-extra";
|
|
9
|
-
import prompts from "prompts";
|
|
10
9
|
import { CONFIG_DEFAULTS } from "./config.js";
|
|
11
10
|
const esmRequire = createRequire(import.meta.url);
|
|
12
11
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
@@ -24,92 +23,6 @@ program
|
|
|
24
23
|
.name("ev")
|
|
25
24
|
.description("CLI for the evjs framework")
|
|
26
25
|
.version(pkg.version);
|
|
27
|
-
program
|
|
28
|
-
.command("init")
|
|
29
|
-
.description("Initialize a new evjs project")
|
|
30
|
-
.argument("[name]", "Project name")
|
|
31
|
-
.option("-t, --template <template>", "Template to use")
|
|
32
|
-
.action(async (name, options) => {
|
|
33
|
-
const response = await prompts([
|
|
34
|
-
{
|
|
35
|
-
type: name ? null : "text",
|
|
36
|
-
name: "projectName",
|
|
37
|
-
message: "Project name:",
|
|
38
|
-
initial: name || "my-evjs-app",
|
|
39
|
-
},
|
|
40
|
-
{
|
|
41
|
-
type: options.template ? null : "select",
|
|
42
|
-
name: "template",
|
|
43
|
-
message: "Select a template:",
|
|
44
|
-
choices: [
|
|
45
|
-
{ title: "Basic CSR (Client-Side Rendering)", value: "basic-csr" },
|
|
46
|
-
{ title: "Basic Server Functions", value: "basic-server-fns" },
|
|
47
|
-
{
|
|
48
|
-
title: "Configured Server Functions (ev.config.ts + Query)",
|
|
49
|
-
value: "configured-server-fns",
|
|
50
|
-
},
|
|
51
|
-
{
|
|
52
|
-
title: "Complex Routing (params, search, layouts, loaders)",
|
|
53
|
-
value: "complex-routing",
|
|
54
|
-
},
|
|
55
|
-
{
|
|
56
|
-
title: "With Tailwind CSS (plugin loaders example)",
|
|
57
|
-
value: "with-tailwind",
|
|
58
|
-
},
|
|
59
|
-
],
|
|
60
|
-
},
|
|
61
|
-
], {
|
|
62
|
-
onCancel: () => {
|
|
63
|
-
process.exit(1);
|
|
64
|
-
},
|
|
65
|
-
});
|
|
66
|
-
const projectName = response.projectName || name;
|
|
67
|
-
const template = response.template || options.template;
|
|
68
|
-
const targetDir = path.resolve(process.cwd(), projectName);
|
|
69
|
-
if (fs.existsSync(targetDir)) {
|
|
70
|
-
logger.error `Directory ${projectName} already exists!`;
|
|
71
|
-
process.exit(1);
|
|
72
|
-
}
|
|
73
|
-
const templateDir = path.resolve(__dirname, "../templates", template);
|
|
74
|
-
if (!fs.existsSync(templateDir)) {
|
|
75
|
-
logger.error `Template ${template} not found!`;
|
|
76
|
-
process.exit(1);
|
|
77
|
-
}
|
|
78
|
-
logger.info `Scaffolding project in ${targetDir}...`;
|
|
79
|
-
await fs.copy(templateDir, targetDir, {
|
|
80
|
-
dereference: true,
|
|
81
|
-
filter: (src) => {
|
|
82
|
-
const basename = path.basename(src);
|
|
83
|
-
return !["node_modules", "dist", ".turbo"].includes(basename);
|
|
84
|
-
},
|
|
85
|
-
});
|
|
86
|
-
// Post-process package.json: sync @evjs/* versions and set project name
|
|
87
|
-
const pkgPath = path.join(targetDir, "package.json");
|
|
88
|
-
if (fs.existsSync(pkgPath)) {
|
|
89
|
-
const pkg = await fs.readJson(pkgPath);
|
|
90
|
-
pkg.name = projectName;
|
|
91
|
-
delete pkg.private; // Templates shouldn't be private by default
|
|
92
|
-
const updateDeps = (deps) => {
|
|
93
|
-
if (!deps)
|
|
94
|
-
return;
|
|
95
|
-
for (const [name, val] of Object.entries(deps)) {
|
|
96
|
-
// Sync all @evjs/* packages to current CLI version
|
|
97
|
-
if (name.startsWith("@evjs/") &&
|
|
98
|
-
(val === "*" ||
|
|
99
|
-
(typeof val === "string" && val.includes("workspace")))) {
|
|
100
|
-
deps[name] = `^${pkg.version}`;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
};
|
|
104
|
-
updateDeps(pkg.dependencies);
|
|
105
|
-
updateDeps(pkg.devDependencies);
|
|
106
|
-
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
|
107
|
-
}
|
|
108
|
-
logger.info `Done! Now run:`;
|
|
109
|
-
logger.info ` cd ${projectName}`;
|
|
110
|
-
logger.info ` npm install`;
|
|
111
|
-
logger.info ` npm run dev`;
|
|
112
|
-
});
|
|
113
26
|
/**
|
|
114
27
|
* Load config and create webpack configuration object.
|
|
115
28
|
*
|
|
@@ -149,8 +62,8 @@ program
|
|
|
149
62
|
const bootstrapPath = path.resolve(cwd, "dist/server/_dev_start.cjs");
|
|
150
63
|
if (fs.existsSync(manifestPath)) {
|
|
151
64
|
const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf-8"));
|
|
152
|
-
//
|
|
153
|
-
if (
|
|
65
|
+
// Start API server if there's a server entry
|
|
66
|
+
if (!manifest.server?.entry)
|
|
154
67
|
return;
|
|
155
68
|
apiStarted = true;
|
|
156
69
|
const backendConfig = evjsConfig?.server?.backend ?? "node";
|
|
@@ -158,10 +71,11 @@ program
|
|
|
158
71
|
logger.info `Server bundle detected, starting ${backend} API...`;
|
|
159
72
|
try {
|
|
160
73
|
const serverBundlePath = path.resolve(cwd, "dist/server", manifest.server.entry);
|
|
74
|
+
fs.ensureDirSync(path.dirname(bootstrapPath));
|
|
161
75
|
fs.writeFileSync(bootstrapPath, [
|
|
162
76
|
`const bundle = require(${JSON.stringify(serverBundlePath)});`,
|
|
163
|
-
`const app = bundle.createApp({ endpoint: ${JSON.stringify(evjsConfig?.server?.endpoint ?? CONFIG_DEFAULTS.endpoint)} });`,
|
|
164
|
-
`const { serve } = require("@evjs/
|
|
77
|
+
`const app = bundle.app || bundle.createApp({ endpoint: ${JSON.stringify(evjsConfig?.server?.endpoint ?? CONFIG_DEFAULTS.endpoint)} });`,
|
|
78
|
+
`const { serve } = require("@evjs/server/node");`,
|
|
165
79
|
`serve(app, { port: ${serverPort} });`,
|
|
166
80
|
].join("\n"));
|
|
167
81
|
// node gets --watch flags; other runtimes use their own args as-is
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@evjs/cli",
|
|
3
|
-
"version": "0.0.1-rc.
|
|
3
|
+
"version": "0.0.1-rc.28",
|
|
4
4
|
"description": "CLI and configuration layer for the evjs framework",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/config.js",
|
|
@@ -18,8 +18,7 @@
|
|
|
18
18
|
"ev": "dist/index.js"
|
|
19
19
|
},
|
|
20
20
|
"files": [
|
|
21
|
-
"dist"
|
|
22
|
-
"templates"
|
|
21
|
+
"dist"
|
|
23
22
|
],
|
|
24
23
|
"scripts": {
|
|
25
24
|
"build": "tsc",
|
|
@@ -31,14 +30,13 @@
|
|
|
31
30
|
"dependencies": {
|
|
32
31
|
"@evjs/webpack-plugin": "*",
|
|
33
32
|
"@logtape/logtape": "^2.0.4",
|
|
34
|
-
"@swc/core": "^1.15.
|
|
33
|
+
"@swc/core": "^1.15.21",
|
|
35
34
|
"commander": "^12.1.0",
|
|
36
|
-
"execa": "^9.
|
|
37
|
-
"fs-extra": "^11.3.
|
|
35
|
+
"execa": "^9.6.1",
|
|
36
|
+
"fs-extra": "^11.3.4",
|
|
38
37
|
"glob": "^13.0.6",
|
|
39
38
|
"html-webpack-plugin": "^5.6.6",
|
|
40
39
|
"picocolors": "^1.1.1",
|
|
41
|
-
"prompts": "^2.4.2",
|
|
42
40
|
"swc-loader": "^0.2.7",
|
|
43
41
|
"webpack": "^5.105.4",
|
|
44
42
|
"webpack-cli": "^6.0.1",
|
|
@@ -46,9 +44,8 @@
|
|
|
46
44
|
},
|
|
47
45
|
"devDependencies": {
|
|
48
46
|
"@types/fs-extra": "^11.0.4",
|
|
49
|
-
"@types/node": "^22.
|
|
50
|
-
"
|
|
51
|
-
"typescript": "^5.7.3"
|
|
47
|
+
"@types/node": "^22.19.15",
|
|
48
|
+
"typescript": "^6.0.2"
|
|
52
49
|
},
|
|
53
50
|
"homepage": "https://github.com/evaijs/evjs#readme",
|
|
54
51
|
"bugs": {
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
# basic-csr
|
|
2
|
-
|
|
3
|
-
Minimal client-side rendering example — no server functions, just routing.
|
|
4
|
-
|
|
5
|
-
## Run
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
npm run dev -w example-basic-csr
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
## Key Files
|
|
12
|
-
|
|
13
|
-
| File | Purpose |
|
|
14
|
-
|------|---------|
|
|
15
|
-
| `src/main.tsx` | App bootstrap with `createApp` |
|
|
16
|
-
| `src/pages/` | Route components (Home, Posts) |
|
|
17
|
-
|
|
18
|
-
## What It Demonstrates
|
|
19
|
-
|
|
20
|
-
- `createApp` + `createRoute` from `@evjs/runtime`
|
|
21
|
-
- Client-side routing with TanStack Router
|
|
22
|
-
- Dynamic route params (`$postId`)
|
|
23
|
-
- No server functions — pure CSR
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "example-basic-csr",
|
|
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,22 +0,0 @@
|
|
|
1
|
-
import { createApp } from "@evjs/runtime/client";
|
|
2
|
-
import { rootRoute } from "./pages/__root";
|
|
3
|
-
import { aboutRoute } from "./pages/about";
|
|
4
|
-
import { homeRoute } from "./pages/home";
|
|
5
|
-
import { postDetailRoute, postsIndexRoute, postsRoute } from "./pages/posts";
|
|
6
|
-
|
|
7
|
-
const routeTree = rootRoute.addChildren([
|
|
8
|
-
homeRoute,
|
|
9
|
-
aboutRoute,
|
|
10
|
-
postsRoute.addChildren([postsIndexRoute, postDetailRoute]),
|
|
11
|
-
]);
|
|
12
|
-
|
|
13
|
-
const app = createApp({ routeTree });
|
|
14
|
-
|
|
15
|
-
// Register router type for full IDE type-safety on useParams, useSearch, Link, etc.
|
|
16
|
-
declare module "@tanstack/react-router" {
|
|
17
|
-
interface Register {
|
|
18
|
-
router: typeof app.router;
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
app.render("#app");
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { createRootRoute, Link, Outlet } from "@evjs/runtime/client";
|
|
2
|
-
|
|
3
|
-
function Root() {
|
|
4
|
-
return (
|
|
5
|
-
<div style={{ fontFamily: "system-ui, sans-serif", padding: "1rem" }}>
|
|
6
|
-
<nav
|
|
7
|
-
style={{
|
|
8
|
-
display: "flex",
|
|
9
|
-
gap: "1rem",
|
|
10
|
-
borderBottom: "1px solid #e5e7eb",
|
|
11
|
-
paddingBottom: "0.5rem",
|
|
12
|
-
marginBottom: "1rem",
|
|
13
|
-
}}
|
|
14
|
-
>
|
|
15
|
-
<Link to="/" style={{ fontWeight: "bold" }}>
|
|
16
|
-
Home
|
|
17
|
-
</Link>
|
|
18
|
-
<Link to="/about">About</Link>
|
|
19
|
-
<Link to="/posts">Posts</Link>
|
|
20
|
-
</nav>
|
|
21
|
-
<Outlet />
|
|
22
|
-
</div>
|
|
23
|
-
);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export const rootRoute = createRootRoute({
|
|
27
|
-
component: Root,
|
|
28
|
-
});
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { createRoute } from "@evjs/runtime/client";
|
|
2
|
-
import { rootRoute } from "./__root";
|
|
3
|
-
|
|
4
|
-
function About() {
|
|
5
|
-
return (
|
|
6
|
-
<div>
|
|
7
|
-
<h1>About</h1>
|
|
8
|
-
<p>
|
|
9
|
-
Code-based routing with TanStack Router via <code>createApp</code>.
|
|
10
|
-
</p>
|
|
11
|
-
</div>
|
|
12
|
-
);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export const aboutRoute = createRoute({
|
|
16
|
-
getParentRoute: () => rootRoute,
|
|
17
|
-
path: "/about",
|
|
18
|
-
component: About,
|
|
19
|
-
});
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { createRoute } from "@evjs/runtime/client";
|
|
2
|
-
import { rootRoute } from "./__root";
|
|
3
|
-
|
|
4
|
-
function Home() {
|
|
5
|
-
return (
|
|
6
|
-
<div>
|
|
7
|
-
<h1>Welcome Home!</h1>
|
|
8
|
-
<p>
|
|
9
|
-
A basic client-side rendered app built with <code>@evjs/runtime</code>.
|
|
10
|
-
</p>
|
|
11
|
-
</div>
|
|
12
|
-
);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export const homeRoute = createRoute({
|
|
16
|
-
getParentRoute: () => rootRoute,
|
|
17
|
-
path: "/",
|
|
18
|
-
component: Home,
|
|
19
|
-
});
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import { createRoute, Link, Outlet } from "@evjs/runtime/client";
|
|
2
|
-
import { rootRoute } from "../__root";
|
|
3
|
-
|
|
4
|
-
const posts = [
|
|
5
|
-
{ id: "1", title: "First Post", body: "Hello world!" },
|
|
6
|
-
{ id: "2", title: "Second Post", body: "Another day, another post." },
|
|
7
|
-
{ id: "3", title: "Third Post", body: "Three's a charm." },
|
|
8
|
-
];
|
|
9
|
-
|
|
10
|
-
function Posts() {
|
|
11
|
-
return (
|
|
12
|
-
<div style={{ display: "flex", gap: "1rem" }}>
|
|
13
|
-
<ul style={{ listStyle: "none", padding: 0, minWidth: 160 }}>
|
|
14
|
-
{posts.map((p) => (
|
|
15
|
-
<li key={p.id} style={{ marginBottom: "0.25rem" }}>
|
|
16
|
-
<Link
|
|
17
|
-
to="/posts/$postId"
|
|
18
|
-
params={{ postId: p.id }}
|
|
19
|
-
activeProps={{ style: { fontWeight: "bold" } }}
|
|
20
|
-
>
|
|
21
|
-
{p.title}
|
|
22
|
-
</Link>
|
|
23
|
-
</li>
|
|
24
|
-
))}
|
|
25
|
-
</ul>
|
|
26
|
-
<Outlet />
|
|
27
|
-
</div>
|
|
28
|
-
);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export const postsRoute = createRoute({
|
|
32
|
-
getParentRoute: () => rootRoute,
|
|
33
|
-
path: "/posts",
|
|
34
|
-
component: Posts,
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
function PostsIndex() {
|
|
38
|
-
return <p style={{ color: "#6b7280" }}>Select a post.</p>;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export const postsIndexRoute = createRoute({
|
|
42
|
-
getParentRoute: () => postsRoute,
|
|
43
|
-
path: "/",
|
|
44
|
-
component: PostsIndex,
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
function PostDetail() {
|
|
48
|
-
const { postId } = postDetailRoute.useParams();
|
|
49
|
-
const post = posts.find((p) => p.id === postId);
|
|
50
|
-
if (!post) return <p>Post not found.</p>;
|
|
51
|
-
return (
|
|
52
|
-
<div>
|
|
53
|
-
<h2>{post.title}</h2>
|
|
54
|
-
<p>{post.body}</p>
|
|
55
|
-
</div>
|
|
56
|
-
);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export const postDetailRoute = createRoute({
|
|
60
|
-
getParentRoute: () => postsRoute,
|
|
61
|
-
path: "$postId",
|
|
62
|
-
component: PostDetail,
|
|
63
|
-
});
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ESNext",
|
|
4
|
-
"jsx": "react-jsx",
|
|
5
|
-
"module": "ESNext",
|
|
6
|
-
"lib": ["ESNext", "DOM", "DOM.Iterable"],
|
|
7
|
-
"moduleResolution": "Bundler",
|
|
8
|
-
"verbatimModuleSyntax": true,
|
|
9
|
-
"noEmit": true,
|
|
10
|
-
"skipLibCheck": true,
|
|
11
|
-
"strict": true,
|
|
12
|
-
"noUnusedLocals": true,
|
|
13
|
-
"noUnusedParameters": true,
|
|
14
|
-
"noFallthroughCasesInSwitch": true
|
|
15
|
-
},
|
|
16
|
-
"include": ["src"]
|
|
17
|
-
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
# basic-server-fns
|
|
2
|
-
|
|
3
|
-
Basic server functions with `query()` / `mutation()` wrappers.
|
|
4
|
-
|
|
5
|
-
## Run
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
npm run dev -w example-basic-server-fns
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
## Key Files
|
|
12
|
-
|
|
13
|
-
| File | Purpose |
|
|
14
|
-
|------|---------|
|
|
15
|
-
| `src/main.tsx` | App bootstrap |
|
|
16
|
-
| `src/routes.tsx` | Routes + components |
|
|
17
|
-
| `src/api/users.server.ts` | `"use server"` CRUD functions |
|
|
18
|
-
|
|
19
|
-
## What It Demonstrates
|
|
20
|
-
|
|
21
|
-
- `"use server"` directive for auto-discovered server functions
|
|
22
|
-
- `query(fn).useQuery()` for data fetching
|
|
23
|
-
- `mutation(fn).useMutation()` for mutations
|
|
24
|
-
- `invalidates` for auto cache invalidation on mutation success
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "example-basic-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
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
"use server";
|
|
2
|
-
|
|
3
|
-
/** Simulated user database. */
|
|
4
|
-
const users = [
|
|
5
|
-
{ id: "1", name: "Alice", email: "alice@example.com" },
|
|
6
|
-
{ id: "2", name: "Bob", email: "bob@example.com" },
|
|
7
|
-
{ id: "3", name: "Charlie", email: "charlie@example.com" },
|
|
8
|
-
];
|
|
9
|
-
|
|
10
|
-
/** Get all users. */
|
|
11
|
-
export async function getUsers() {
|
|
12
|
-
// Simulate server latency
|
|
13
|
-
await new Promise((r) => setTimeout(r, 100));
|
|
14
|
-
return users;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/** Get a single user by ID. */
|
|
18
|
-
export async function getUser(id: string) {
|
|
19
|
-
await new Promise((r) => setTimeout(r, 50));
|
|
20
|
-
const user = users.find((u) => u.id === id);
|
|
21
|
-
if (!user) throw new Error(`User ${id} not found`);
|
|
22
|
-
return user;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/** Create a new user. */
|
|
26
|
-
export async function createUser(data: { name: string; email: string }) {
|
|
27
|
-
await new Promise((r) => setTimeout(r, 50));
|
|
28
|
-
const newUser = { id: String(users.length + 1), ...data };
|
|
29
|
-
users.push(newUser);
|
|
30
|
-
return newUser;
|
|
31
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { createApp } from "@evjs/runtime/client";
|
|
2
|
-
import { routeTree } from "./routes";
|
|
3
|
-
|
|
4
|
-
const app = createApp({ routeTree });
|
|
5
|
-
|
|
6
|
-
declare module "@tanstack/react-router" {
|
|
7
|
-
interface Register {
|
|
8
|
-
router: typeof app.router;
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
app.render("#app");
|