@evjs/cli 0.0.1-rc.16 → 0.0.1-rc.18

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 CHANGED
@@ -28,7 +28,7 @@ No configuration file is needed. `ev dev` and `ev build` work out of the box wit
28
28
 
29
29
  ### `ev init [name]`
30
30
 
31
- Templates: `basic-csr`, `basic-server-fns`, `trpc-server-fns`.
31
+ Templates: `basic-csr`, `basic-server-fns`, `configured-server-fns`, `complex-routing`, `with-tailwind`.
32
32
  Option: `-t, --template <template>` to skip interactive selection.
33
33
 
34
34
  ### `ev dev`
@@ -54,6 +54,7 @@ export default defineConfig({
54
54
  client: {
55
55
  entry: "./src/main.tsx",
56
56
  html: "./index.html",
57
+ plugins: [{ name: "tailwind", loaders: [{ test: /\.css$/, use: ["style-loader", "css-loader", "postcss-loader"] }] }],
57
58
  dev: { port: 3000 },
58
59
  },
59
60
  server: {
@@ -74,6 +74,20 @@ export function createWebpackConfig(config, cwd) {
74
74
  },
75
75
  ],
76
76
  },
77
+ // Plugin-declared loaders
78
+ ...(client?.plugins ?? []).flatMap((plugin) => (plugin.loaders ?? []).map((rule) => {
79
+ const entries = Array.isArray(rule.use) ? rule.use : [rule.use];
80
+ return {
81
+ test: rule.test,
82
+ ...(rule.exclude ? { exclude: rule.exclude } : {}),
83
+ use: entries.map((entry) => typeof entry === "string"
84
+ ? { loader: resolveLoader(entry) }
85
+ : {
86
+ loader: resolveLoader(entry.loader),
87
+ ...(entry.options ? { options: entry.options } : {}),
88
+ }),
89
+ };
90
+ })),
77
91
  ],
78
92
  },
79
93
  plugins: [
package/dist/index.js CHANGED
@@ -52,6 +52,10 @@ program
52
52
  title: "Complex Routing (params, search, layouts, loaders)",
53
53
  value: "complex-routing",
54
54
  },
55
+ {
56
+ title: "With Tailwind CSS (plugin loaders example)",
57
+ value: "with-tailwind",
58
+ },
55
59
  ],
56
60
  },
57
61
  ], {
@@ -144,12 +148,15 @@ program
144
148
  const manifestPath = path.resolve(cwd, "dist/manifest.json");
145
149
  const bootstrapPath = path.resolve(cwd, "dist/server/_dev_start.cjs");
146
150
  if (fs.existsSync(manifestPath)) {
151
+ const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf-8"));
152
+ // Only start API server if there are actual server functions
153
+ if (Object.keys(manifest.server?.fns ?? {}).length === 0)
154
+ return;
147
155
  apiStarted = true;
148
156
  const backendConfig = evjsConfig?.server?.backend ?? "node";
149
157
  const [backend, ...backendExtraArgs] = backendConfig.split(/\s+/);
150
158
  logger.info `Server bundle detected, starting ${backend} API...`;
151
159
  try {
152
- const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf-8"));
153
160
  const serverBundlePath = path.resolve(cwd, "dist/server", manifest.server.entry);
154
161
  fs.writeFileSync(bootstrapPath, [
155
162
  `const bundle = require(${JSON.stringify(serverBundlePath)});`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@evjs/cli",
3
- "version": "0.0.1-rc.16",
3
+ "version": "0.0.1-rc.18",
4
4
  "description": "CLI and configuration layer for the evjs framework",
5
5
  "type": "module",
6
6
  "main": "./dist/config.js",
@@ -0,0 +1,23 @@
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,6 +1,6 @@
1
1
  {
2
2
  "name": "example-basic-csr",
3
- "version": "0.0.0",
3
+ "version": "0.0.1-rc.18",
4
4
  "private": true,
5
5
  "scripts": {
6
6
  "dev": "ev dev",
@@ -0,0 +1,24 @@
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,6 +1,6 @@
1
1
  {
2
2
  "name": "example-basic-server-fns",
3
- "version": "0.0.0",
3
+ "version": "0.0.1-rc.18",
4
4
  "private": true,
5
5
  "scripts": {
6
6
  "dev": "ev dev",
@@ -0,0 +1,27 @@
1
+ # complex-routing
2
+
3
+ Advanced routing patterns with TanStack Router.
4
+
5
+ ## Run
6
+
7
+ ```bash
8
+ npm run dev -w example-complex-routing
9
+ ```
10
+
11
+ ## Key Files
12
+
13
+ | File | Purpose |
14
+ |------|---------|
15
+ | `src/main.tsx` | Route tree assembly |
16
+ | `src/pages/__root.tsx` | Root layout with navigation |
17
+ | `src/pages/home.tsx` | Index route |
18
+ | `src/pages/posts/` | Nested routes with loader |
19
+
20
+ ## What It Demonstrates
21
+
22
+ - Dynamic route params (`$postId`)
23
+ - Pathless layout routes
24
+ - Route loaders with `queryClient.ensureQueryData`
25
+ - Search params with `validateSearch`
26
+ - Catch-all 404 route
27
+ - Type-safe `route.useParams()`
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "example-complex-routing",
3
- "version": "0.0.0",
3
+ "version": "0.0.1-rc.18",
4
4
  "private": true,
5
5
  "scripts": {
6
6
  "dev": "ev dev",
@@ -0,0 +1,24 @@
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)
@@ -39,9 +39,9 @@ export default defineConfig({
39
39
  // Server function endpoint path (default: "/api/fn")
40
40
  endpoint: "/api/fn",
41
41
 
42
- // Server backend module (default: "@evjs/runtime/server/node")
43
- // For Deno/Bun/Workers, use: "@evjs/runtime/server/ecma"
44
- backend: "@evjs/runtime/server/node",
42
+ // Server backend command (default: "node")
43
+ // Supports: "node", "bun", "deno run --allow-net", etc.
44
+ backend: "node",
45
45
 
46
46
  // Middleware module paths to auto-register in server entry
47
47
  // These are imported and applied in order
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "example-configured-server-fns",
3
- "version": "0.0.0",
3
+ "version": "0.0.1-rc.18",
4
4
  "private": true,
5
5
  "scripts": {
6
6
  "dev": "ev dev",
@@ -60,7 +60,7 @@ function UsersPage() {
60
60
  async function handleCreate(e: { preventDefault: () => void }) {
61
61
  e.preventDefault();
62
62
  if (!name || !email) return;
63
- await doCreateUser([{ name, email }]);
63
+ await doCreateUser({ name, email });
64
64
  setName("");
65
65
  setEmail("");
66
66
  }
@@ -0,0 +1,20 @@
1
+ import { defineConfig } from "@evjs/cli";
2
+
3
+ /**
4
+ * Example: Using client plugins to add Tailwind CSS support.
5
+ */
6
+ export default defineConfig({
7
+ client: {
8
+ plugins: [
9
+ {
10
+ name: "tailwind",
11
+ loaders: [
12
+ {
13
+ test: /\.css$/,
14
+ use: ["style-loader", "css-loader", "postcss-loader"],
15
+ },
16
+ ],
17
+ },
18
+ ],
19
+ },
20
+ });
@@ -0,0 +1,11 @@
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>ev — CSS Plugin Example</title>
7
+ </head>
8
+ <body>
9
+ <div id="app"></div>
10
+ </body>
11
+ </html>
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "example-with-tailwind",
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
+ "@tailwindcss/typography": "^0.5.19",
13
+ "react": "^19.2.4",
14
+ "react-dom": "^19.2.4"
15
+ },
16
+ "devDependencies": {
17
+ "@evjs/cli": "*",
18
+ "@tailwindcss/postcss": "^4.1.10",
19
+ "@types/react": "^19.0.8",
20
+ "@types/react-dom": "^19.0.3",
21
+ "css-loader": "^7.1.2",
22
+ "postcss": "^8.5.6",
23
+ "postcss-loader": "^8.1.1",
24
+ "style-loader": "^4.0.0",
25
+ "tailwindcss": "^4.1.10",
26
+ "typescript": "^5.7.3"
27
+ }
28
+ }
@@ -0,0 +1,5 @@
1
+ export default {
2
+ plugins: {
3
+ "@tailwindcss/postcss": {},
4
+ },
5
+ };
@@ -0,0 +1,15 @@
1
+ import { createApp } from "@evjs/runtime/client";
2
+ import { rootRoute } from "./pages/__root";
3
+ import { homeRoute } from "./pages/home";
4
+
5
+ const routeTree = rootRoute.addChildren([homeRoute]);
6
+
7
+ const app = createApp({ routeTree });
8
+
9
+ declare module "@tanstack/react-router" {
10
+ interface Register {
11
+ router: typeof app.router;
12
+ }
13
+ }
14
+
15
+ app.render("#app");
@@ -0,0 +1,30 @@
1
+ import { createRootRoute, Link, Outlet } from "@evjs/runtime/client";
2
+ import "../styles.css";
3
+
4
+ function Root() {
5
+ return (
6
+ <div className="min-h-screen bg-gradient-to-br from-slate-900 via-slate-800 to-slate-900 text-white">
7
+ <nav className="border-b border-white/10 backdrop-blur-sm bg-white/5">
8
+ <div className="max-w-4xl mx-auto px-6 py-4 flex items-center gap-6">
9
+ <Link
10
+ to="/"
11
+ className="text-lg font-bold bg-gradient-to-r from-blue-400 to-violet-400 bg-clip-text text-transparent"
12
+ >
13
+ evjs
14
+ </Link>
15
+ <Link
16
+ to="/"
17
+ className="text-sm text-slate-300 hover:text-white transition-colors"
18
+ >
19
+ Home
20
+ </Link>
21
+ </div>
22
+ </nav>
23
+ <Outlet />
24
+ </div>
25
+ );
26
+ }
27
+
28
+ export const rootRoute = createRootRoute({
29
+ component: Root,
30
+ });
@@ -0,0 +1,85 @@
1
+ import { createRoute } from "@evjs/runtime/client";
2
+ import { rootRoute } from "./__root";
3
+
4
+ export const homeRoute = createRoute({
5
+ getParentRoute: () => rootRoute,
6
+ path: "/",
7
+ component: () => (
8
+ <main className="max-w-4xl mx-auto px-6 py-16">
9
+ {/* Hero */}
10
+ <div className="text-center mb-16">
11
+ <h1
12
+ className="text-5xl font-extrabold tracking-tight bg-gradient-to-r from-blue-400 via-violet-400 to-fuchsia-400 bg-clip-text text-transparent"
13
+ data-testid="title"
14
+ >
15
+ Tailwind Plugin Example
16
+ </h1>
17
+ <p
18
+ className="mt-4 text-lg text-slate-400 max-w-xl mx-auto"
19
+ data-testid="subtitle"
20
+ >
21
+ Styled with Tailwind CSS v4 via the evjs plugin system — no webpack
22
+ config needed.
23
+ </p>
24
+ </div>
25
+
26
+ {/* Feature cards */}
27
+ <div className="grid grid-cols-1 md:grid-cols-3 gap-6 mb-16">
28
+ <div className="rounded-xl border border-white/10 bg-white/5 backdrop-blur-sm p-6 hover:bg-white/10 transition-colors">
29
+ <div className="text-3xl mb-3">🔌</div>
30
+ <h3 className="font-semibold text-white mb-1">Plugin Loaders</h3>
31
+ <p className="text-sm text-slate-400">
32
+ Declare loaders in ev.config.ts. The framework handles the rest.
33
+ </p>
34
+ </div>
35
+
36
+ <div className="rounded-xl border border-white/10 bg-white/5 backdrop-blur-sm p-6 hover:bg-white/10 transition-colors">
37
+ <div className="text-3xl mb-3">🎨</div>
38
+ <h3 className="font-semibold text-white mb-1">Tailwind CSS v4</h3>
39
+ <p className="text-sm text-slate-400">
40
+ Full utility-first styling with zero configuration overhead.
41
+ </p>
42
+ </div>
43
+
44
+ <div className="rounded-xl border border-white/10 bg-white/5 backdrop-blur-sm p-6 hover:bg-white/10 transition-colors">
45
+ <div className="text-3xl mb-3">⚡</div>
46
+ <h3 className="font-semibold text-white mb-1">Zero Config</h3>
47
+ <p className="text-sm text-slate-400">
48
+ evjs works out of the box. Plugins extend it cleanly.
49
+ </p>
50
+ </div>
51
+ </div>
52
+
53
+ {/* Typography plugin demo */}
54
+ <div className="rounded-xl border border-white/10 bg-white/5 backdrop-blur-sm p-8 mb-16">
55
+ <div className="prose prose-invert max-w-none" data-testid="prose">
56
+ <h2>Typography Plugin</h2>
57
+ <p>
58
+ This section uses <code>@tailwindcss/typography</code> via the{" "}
59
+ <code>prose</code> class. It automatically styles headings,
60
+ paragraphs, code blocks, lists, and more with beautiful defaults.
61
+ </p>
62
+ <ul>
63
+ <li>Automatic heading styles</li>
64
+ <li>Beautiful paragraph spacing</li>
65
+ <li>
66
+ Styled <code>code</code> elements
67
+ </li>
68
+ </ul>
69
+ </div>
70
+ </div>
71
+
72
+ {/* Config preview */}
73
+ <div className="rounded-xl border border-white/10 bg-white/5 backdrop-blur-sm p-6">
74
+ <h2 className="text-lg font-semibold text-white mb-4">ev.config.ts</h2>
75
+ <pre className="text-sm text-slate-300 bg-black/30 rounded-lg p-4 overflow-x-auto">
76
+ <code>{`export default defineConfig({
77
+ client: {
78
+ plugins: [tailwind()],
79
+ },
80
+ });`}</code>
81
+ </pre>
82
+ </div>
83
+ </main>
84
+ ),
85
+ });
@@ -0,0 +1,2 @@
1
+ @import "tailwindcss";
2
+ @plugin "@tailwindcss/typography";
@@ -0,0 +1,17 @@
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
+ }