create-vitnode-app 2.0.0-canary.1 → 2.0.0-canary.10

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.
Files changed (61) hide show
  1. package/README.md +9 -2
  2. package/copy-of-vitnode-app/README.md +22 -0
  3. package/copy-of-vitnode-app/api/src/vitnode.api.config.ts +10 -11
  4. package/copy-of-vitnode-app/api-single-app/src/routes/api/$.ts +4 -26
  5. package/copy-of-vitnode-app/api-single-app/src/server/api-bridge.ts +1 -12
  6. package/copy-of-vitnode-app/api-single-app/src/server/vitnode-api.server.ts +13 -13
  7. package/copy-of-vitnode-app/api-single-app/src/vitnode.api.config.ts +3 -12
  8. package/copy-of-vitnode-app/docker/docker-compose.yml +6 -4
  9. package/copy-of-vitnode-app/monorepo/apps/api/.env.example +1 -1
  10. package/copy-of-vitnode-app/monorepo/apps/web/.env.example +1 -12
  11. package/copy-of-vitnode-app/monorepo/turbo.json +2 -2
  12. package/copy-of-vitnode-app/root/.env.example +1 -8
  13. package/copy-of-vitnode-app/root/global.d.ts +1 -19
  14. package/copy-of-vitnode-app/root/src/components/admin-shell.tsx +2 -53
  15. package/copy-of-vitnode-app/root/src/components/main-footer.tsx +44 -0
  16. package/copy-of-vitnode-app/root/src/components/main-header.tsx +1 -30
  17. package/copy-of-vitnode-app/root/src/lib/i18n.ts +37 -0
  18. package/copy-of-vitnode-app/root/src/locales/app.ts +1 -25
  19. package/copy-of-vitnode-app/root/src/locales/packages.ts +1 -34
  20. package/copy-of-vitnode-app/root/src/router.tsx +9 -165
  21. package/copy-of-vitnode-app/root/src/routes/__root.tsx +12 -115
  22. package/copy-of-vitnode-app/root/src/routes/_admin/admin.core.index.tsx +4 -54
  23. package/copy-of-vitnode-app/root/src/routes/_admin.tsx +5 -198
  24. package/copy-of-vitnode-app/root/src/routes/_main/index.tsx +182 -46
  25. package/copy-of-vitnode-app/root/src/routes/_main.tsx +12 -47
  26. package/copy-of-vitnode-app/root/src/server/messages.server.ts +2 -23
  27. package/copy-of-vitnode-app/root/src/start.ts +3 -86
  28. package/copy-of-vitnode-app/root/src/styles.css +70 -92
  29. package/copy-of-vitnode-app/root/src/vitnode.config.ts +15 -53
  30. package/copy-of-vitnode-app/root/src/vitnode.server.config.ts +12 -0
  31. package/copy-of-vitnode-app/root/tsconfig.json +8 -3
  32. package/copy-of-vitnode-app/root/vite.config.ts +2 -99
  33. package/copy-of-vitnode-plugin/root/global.d.ts +6 -6
  34. package/dist/src/create/create-package-json.js +3 -3
  35. package/dist/src/create/create-vitnode.js +15 -1
  36. package/dist/src/create/package-versions.js +22 -22
  37. package/dist/src/helpers/init-git.js +38 -0
  38. package/dist/src/helpers/init-vitnode.js +2 -3
  39. package/dist/src/helpers/install-dependencies.js +2 -3
  40. package/dist/src/helpers/spawn-command.js +7 -0
  41. package/dist/src/index.js +1 -0
  42. package/dist/src/plugin/create/add-plugin-to-config.js +231 -0
  43. package/dist/src/plugin/create/create-package-json.js +2 -1
  44. package/dist/src/plugin/create/create-plugin-vitnode.js +23 -2
  45. package/dist/src/plugin/create/route-templates.js +103 -61
  46. package/dist/src/questions.js +7 -0
  47. package/dist/tsconfig.build.tsbuildinfo +1 -1
  48. package/package.json +6 -6
  49. package/copy-of-vitnode-app/api/src/i18n.ts +0 -38
  50. package/copy-of-vitnode-app/root/src/i18n.ts +0 -36
  51. package/copy-of-vitnode-app/root/src/lib/admin-auth.ts +0 -11
  52. package/copy-of-vitnode-app/root/src/lib/admin-nav.ts +0 -43
  53. package/copy-of-vitnode-app/root/src/lib/admin-search.ts +0 -37
  54. package/copy-of-vitnode-app/root/src/lib/auth.ts +0 -66
  55. package/copy-of-vitnode-app/root/src/lib/content-registry.ts +0 -51
  56. package/copy-of-vitnode-app/root/src/lib/document-headers.ts +0 -128
  57. package/copy-of-vitnode-app/root/src/lib/i18n/runtime.ts +0 -75
  58. package/copy-of-vitnode-app/root/src/lib/i18n/shared.ts +0 -20
  59. package/copy-of-vitnode-app/root/src/lib/navigation.ts +0 -24
  60. package/copy-of-vitnode-app/root/src/lib/page-head.ts +0 -19
  61. package/copy-of-vitnode-app/root/src/vitnode.shell.config.ts +0 -35
@@ -1,105 +1,84 @@
1
- @import 'tailwindcss';
2
- @import 'shadcn/tailwind.css';
3
- @import 'tw-animate-css';
1
+ @import "tailwindcss";
2
+ @import "shadcn/tailwind.css";
3
+ @import "tw-animate-css";
4
+ @import "@vitnode/core/styles/tiptap.css";
4
5
 
5
-
6
- /*
7
- * VitNode's components ship compiled, so Tailwind cannot find their classes by
8
- * scanning this app's source. Pointing it at core's build output is what makes
9
- * the toaster, the tooltip and everything else that follows look like VitNode
10
- * instead of unstyled markup.
11
- *
12
- * `dist/src/tanstack` is the line that is easiest to leave off and hardest to
13
- * diagnose. `@vitnode/core/tanstack/*` is markup as much as it is orchestration
14
- * - the header bar, the language switcher, the debug ribbon, the not-found
15
- * screen - and a class written *there* exists nowhere else, because this app
16
- * inherits those components rather than writing their markup. Without it a class
17
- * like `.w-34` is never generated, an `<svg>` with a viewBox and no width
18
- * collapses, and the header renders with no logo at all.
19
- *
20
- * Add a line per plugin that ships compiled components of its own.
21
- *
22
- * The paths are relative to this file. In a monorepo where the package manager
23
- * hoists to the repository root, that is `../../../node_modules/...` - the
24
- * generator rewrites them when it knows.
25
- */
26
6
  @source "../node_modules/@vitnode/core/dist/src/components";
27
7
  @source "../node_modules/@vitnode/core/dist/src/tanstack";
28
8
  @source "../node_modules/@vitnode/core/dist/src/views";
29
9
 
30
- /*
31
- * The design tokens every VitNode component reads. `.dark` is what
32
- * `ThemeScript` and `ThemeProvider` put on `<html>`, so the whole palette
33
- * switches from that one class.
34
- */
35
10
  :root:not(.dark) {
36
- --background: oklch(0.97 0 0);
37
- --foreground: oklch(0.145 0 0);
11
+ color-scheme: light;
12
+ --background: oklch(1 0 0);
13
+ --foreground: oklch(0.23 0.021 264);
38
14
  --card: oklch(1 0 0);
39
- --card-foreground: oklch(0.145 0 0);
15
+ --card-foreground: oklch(0.23 0.021 264);
40
16
  --popover: oklch(1 0 0);
41
- --popover-foreground: oklch(0.145 0 0);
42
- --primary: oklch(0.51 0.16 262.61);
17
+ --popover-foreground: oklch(0.23 0.021 264);
18
+ --primary: oklch(0.52 0.2 264);
43
19
  --primary-foreground: oklch(0.985 0 0);
44
- --secondary: oklch(0.967 0.001 286.375);
45
- --secondary-foreground: oklch(0.21 0.006 285.885);
46
- --muted: oklch(0.967 0.001 286.375);
47
- --muted-foreground: oklch(0.552 0.016 285.938);
48
- --accent: oklch(0.967 0.001 286.375);
49
- --accent-foreground: oklch(0.21 0.006 285.885);
50
- --destructive: oklch(0.577 0.245 27.325);
51
- --warn: oklch(0.54 0.12 82.58);
52
- --border: oklch(0.92 0.004 286.32);
53
- --input: oklch(0.92 0.004 286.32);
54
- --ring: oklch(0.705 0.015 286.067);
55
- --chart-1: oklch(0.871 0.006 286.286);
56
- --chart-2: oklch(0.552 0.016 285.938);
57
- --chart-3: oklch(0.442 0.017 285.786);
58
- --chart-4: oklch(0.37 0.013 285.805);
59
- --chart-5: oklch(0.274 0.006 286.033);
20
+ --secondary: oklch(0.97 0 0);
21
+ --secondary-foreground: oklch(0.394 0.02 266);
22
+ --muted: oklch(0.97 0 0);
23
+ --muted-foreground: oklch(0.46 0.017 264);
24
+ --accent: oklch(0.97 0 0);
25
+ --accent-foreground: oklch(0.23 0.021 264);
26
+ --destructive: oklch(0.576 0.209 29.5);
27
+ --success: oklch(0.586 0.143 155);
28
+ --warn: oklch(0.646 0.17 50);
29
+ --border: oklch(0.937 0.002 264);
30
+ --input: oklch(0.878 0.005 258);
31
+ --ring: oklch(0.52 0.2 264);
32
+ --chart-1: oklch(0.52 0.2 264);
33
+ --chart-2: oklch(0.586 0.143 155);
34
+ --chart-3: oklch(0.576 0.209 29.5);
35
+ --chart-4: oklch(0.646 0.17 50);
36
+ --chart-5: oklch(0.565 0.017 264);
60
37
  --sidebar: oklch(0.985 0 0);
61
- --sidebar-foreground: oklch(0.141 0.005 285.823);
62
- --sidebar-primary: oklch(0.21 0.006 285.885);
38
+ --sidebar-foreground: oklch(0.394 0.02 266);
39
+ --sidebar-primary: oklch(0.52 0.2 264);
63
40
  --sidebar-primary-foreground: oklch(0.985 0 0);
64
- --sidebar-accent: oklch(0.967 0.001 286.375);
65
- --sidebar-accent-foreground: oklch(0.21 0.006 285.885);
66
- --sidebar-border: oklch(0.92 0.004 286.32);
67
- --sidebar-ring: oklch(0.705 0.015 286.067);
41
+ --sidebar-accent: oklch(1 0 0);
42
+ --sidebar-accent-foreground: oklch(0.23 0.021 264);
43
+ --sidebar-border: oklch(0.937 0.002 264);
44
+ --sidebar-ring: oklch(0.52 0.2 264);
68
45
  }
69
46
 
70
47
  .dark {
71
- --background: oklch(0.14 0 0);
72
- --foreground: oklch(0.985 0 0);
73
- --card: oklch(0.21 0.006 285.885);
74
- --card-foreground: oklch(0.985 0 0);
75
- --popover: oklch(0.21 0.006 285.885);
76
- --popover-foreground: oklch(0.985 0 0);
48
+ color-scheme: dark;
49
+ --background: oklch(0.163 0.009 264);
50
+ --foreground: oklch(0.976 0 0);
51
+ --card: oklch(0.199 0.011 261);
52
+ --card-foreground: oklch(0.976 0 0);
53
+ --popover: oklch(0.22 0.012 264);
54
+ --popover-foreground: oklch(0.976 0 0);
77
55
  --primary: oklch(0.6 0.18 262.65);
78
56
  --primary-foreground: oklch(0.98 0 0);
79
- --secondary: oklch(0.274 0.006 286.033);
80
- --secondary-foreground: oklch(0.985 0 0);
81
- --muted: oklch(0.274 0.006 286.033);
82
- --muted-foreground: oklch(0.705 0.015 286.067);
83
- --accent: oklch(0.274 0.006 286.033);
84
- --accent-foreground: oklch(0.985 0 0);
85
- --destructive: oklch(0.704 0.191 22.216);
86
- --warn: oklch(0.76 0.18 81.84);
87
- --border: oklch(1 0 0 / 10%);
88
- --input: oklch(1 0 0 / 15%);
89
- --ring: oklch(0.552 0.016 285.938);
90
- --chart-1: oklch(0.871 0.006 286.286);
91
- --chart-2: oklch(0.552 0.016 285.938);
92
- --chart-3: oklch(0.442 0.017 285.786);
93
- --chart-4: oklch(0.37 0.013 285.805);
94
- --chart-5: oklch(0.274 0.006 286.033);
95
- --sidebar: oklch(0.21 0.006 285.885);
96
- --sidebar-foreground: oklch(0.985 0 0);
97
- --sidebar-primary: oklch(0.488 0.243 264.376);
98
- --sidebar-primary-foreground: oklch(0.985 0 0);
99
- --sidebar-accent: oklch(0.274 0.006 286.033);
100
- --sidebar-accent-foreground: oklch(0.985 0 0);
101
- --sidebar-border: oklch(1 0 0 / 10%);
102
- --sidebar-ring: oklch(0.552 0.016 285.938);
57
+ --secondary: oklch(0.269 0.018 266);
58
+ --secondary-foreground: oklch(0.976 0 0);
59
+ --muted: oklch(0.269 0.018 266);
60
+ --muted-foreground: oklch(0.675 0.008 261);
61
+ --accent: oklch(0.269 0.018 266);
62
+ --accent-foreground: oklch(0.976 0 0);
63
+ --destructive: oklch(0.709 0.17 26.5);
64
+ --success: oklch(0.758 0.153 157);
65
+ --warn: oklch(0.811 0.163 75.6);
66
+ --border: oklch(0.269 0.018 266);
67
+ --input: oklch(0.348 0.013 267);
68
+ --ring: oklch(0.7 0.14 264);
69
+ --chart-1: oklch(0.7 0.14 264);
70
+ --chart-2: oklch(0.758 0.153 157);
71
+ --chart-3: oklch(0.709 0.17 26.5);
72
+ --chart-4: oklch(0.811 0.163 75.6);
73
+ --chart-5: oklch(0.626 0.01 264);
74
+ --sidebar: oklch(0.199 0.011 261);
75
+ --sidebar-foreground: oklch(0.855 0.004 271);
76
+ --sidebar-primary: oklch(0.7 0.14 264);
77
+ --sidebar-primary-foreground: oklch(0.16 0.015 265);
78
+ --sidebar-accent: oklch(0.269 0.018 266);
79
+ --sidebar-accent-foreground: oklch(0.976 0 0);
80
+ --sidebar-border: oklch(0.269 0.018 266);
81
+ --sidebar-ring: oklch(0.7 0.14 264);
103
82
  }
104
83
 
105
84
  :root {
@@ -107,6 +86,10 @@
107
86
  }
108
87
 
109
88
  @theme inline {
89
+ --font-sans:
90
+ -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue",
91
+ "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji",
92
+ "Segoe UI Symbol", "Noto Color Emoji";
110
93
  --font-heading: var(--font-sans);
111
94
  --color-sidebar-ring: var(--sidebar-ring);
112
95
  --color-sidebar-border: var(--sidebar-border);
@@ -125,6 +108,7 @@
125
108
  --color-input: var(--input);
126
109
  --color-border: var(--border);
127
110
  --color-warn: var(--warn);
111
+ --color-success: var(--success);
128
112
  --color-destructive: var(--destructive);
129
113
  --color-accent-foreground: var(--accent-foreground);
130
114
  --color-accent: var(--accent);
@@ -149,12 +133,6 @@
149
133
  --radius-4xl: calc(var(--radius) * 2.6);
150
134
  }
151
135
 
152
- /*
153
- * Last, so that a stylesheet a package brings in cannot outrank it in this
154
- * layer: `@layer base` rules are ordered by where they appear, and a library
155
- * that sets its own `body { background-color: ... }` would otherwise repaint
156
- * whichever pages happen to load it.
157
- */
158
136
  @layer base {
159
137
  * {
160
138
  @apply border-border outline-ring/50;
@@ -1,58 +1,20 @@
1
1
  import { buildConfig } from "@vitnode/core/vitnode.config";
2
2
 
3
- import { appMessages } from "./locales/app";
4
- import { vitNodeShellConfig } from "./vitnode.shell.config";
5
-
6
- /**
7
- * This app's frontend config, in the shape every VitNode app builds it.
8
- *
9
- * `plugins` is empty, and a plugin is added here by id and translations rather
10
- * than through its own `blogPlugin()` entry:
11
- *
12
- * import { buildPlugin } from '@vitnode/core/lib/plugin'
13
- * import { CONFIG_PLUGIN as BLOG } from '@acme/blog/const'
14
- *
15
- * import { packageMessages } from './locales/packages'
16
- *
17
- * plugins: [
18
- * buildPlugin({
19
- * messages: packageMessages[BLOG.pluginId],
20
- * pluginId: BLOG.pluginId,
21
- * }),
22
- * ]
23
- *
24
- * That is a *scope* decision rather than a compatibility one. This object's one
25
- * reader takes `pluginId` and `messages` off each plugin and nothing else, so a
26
- * full registration would add every content type's editing screen to a
27
- * server-only graph where nothing would ever look at them. The AdminCP gets its
28
- * content types from `src/content-registry.gen.ts` instead - one literal import
29
- * per configured plugin - so a browser loads them with the content route and not
30
- * before.
31
- *
32
- * The same split, one layer up, feeds the sidebar: `src/admin-nav.gen.ts` is the
33
- * navigation half - ids, hrefs, permissions, icons - and nothing that renders a
34
- * screen. See `src/lib/admin-nav.ts` and `src/lib/content-registry.ts`; both
35
- * explain why they are generated rather than read from here.
36
- *
37
- * A plugin's *pages* need nothing in this file at all. It declares them in its
38
- * own `src/routes.ts`, and this app's Vite build compiles them into
39
- * `src/plugin-routes.gen.ts`, which `src/router.tsx` mounts under the shell the
40
- * plugin's `area` names. No page is ever copied into `src/routes`.
41
- *
42
- * Server-side only, and deliberately so - see `vitnode.shell.config.ts`.
43
- * `src/server/messages.server.ts` is the only importer, and it carries the
44
- * `server-only` guard that keeps it that way.
45
- *
46
- * `buildConfig` also registers this object process-wide, which is how core's own
47
- * route files find it without being handed it as a prop.
48
- */
49
3
  export const vitNodeConfig = buildConfig({
50
- ...vitNodeShellConfig,
51
- /**
52
- * The shell's locale declaration, plus the message loaders that must not be in
53
- * it: `src/i18n.ts` is spread into the browser-facing shell config, and these
54
- * are functions.
55
- */
56
- i18n: { ...vitNodeShellConfig.i18n, messages: appMessages },
4
+ debug: false,
5
+ i18n: {
6
+ defaultLocale: "en",
7
+ locales: [{ code: "en", name: "English" }],
8
+ timeZone: "UTC",
9
+ },
10
+ metadata: {
11
+ shortTitle: "VitNode",
12
+ title: "VitNode",
13
+ },
57
14
  plugins: [],
15
+ theme: {
16
+ defaultTheme: "system",
17
+ },
58
18
  });
19
+
20
+ export type Locale = (typeof vitNodeConfig.i18n.locales)[number]["code"];
@@ -0,0 +1,12 @@
1
+ import "@tanstack/react-start/server-only";
2
+ import { buildServerConfig } from "@vitnode/core/vitnode.config";
3
+
4
+ import { appMessages } from "@/locales/app";
5
+ import { packageMessages } from "@/locales/packages";
6
+ import { vitNodeConfig } from "@/vitnode.config";
7
+
8
+ export const vitNodeServerConfig = buildServerConfig({
9
+ config: vitNodeConfig,
10
+ messages: appMessages,
11
+ packageMessages,
12
+ });
@@ -1,12 +1,17 @@
1
1
  {
2
- "include": ["**/*.ts", "**/*.tsx", "eslint.config.js", "prettier.config.js", "vite.config.js"],
3
-
2
+ "include": [
3
+ "**/*.ts",
4
+ "**/*.tsx",
5
+ "eslint.config.js",
6
+ "prettier.config.js",
7
+ "vite.config.js"
8
+ ],
9
+
4
10
  "compilerOptions": {
5
11
  "target": "ES2022",
6
12
  "jsx": "react-jsx",
7
13
  "module": "ESNext",
8
14
  "paths": {
9
- "#/*": ["./src/*"],
10
15
  "@/*": ["./src/*"]
11
16
  },
12
17
  "lib": ["ES2022", "DOM", "DOM.Iterable"],
@@ -2,112 +2,15 @@ import tailwindcss from "@tailwindcss/vite";
2
2
  import { devtools } from "@tanstack/devtools-vite";
3
3
  import { tanstackStart } from "@tanstack/react-start/plugin/vite";
4
4
  import viteReact from "@vitejs/plugin-react";
5
- import {
6
- vitNodeEnv,
7
- vitNodeOptimizeDeps,
8
- vitNodePluginRoutes,
9
- } from "@vitnode/core/framework/vite";
5
+ import { vitnode } from "@vitnode/core/framework/vite";
10
6
  import { nitro } from "nitro/vite";
11
7
  import { defineConfig } from "vite";
12
8
 
13
9
  const config = defineConfig({
14
10
  resolve: { tsconfigPaths: true },
15
- /**
16
- * A second dev server has to fail rather than quietly move.
17
- *
18
- * `tanstackStart()` runs the route generator and *writes*
19
- * `src/routeTree.gen.ts`. Two servers means two generators owning one file: if
20
- * their route lists ever differ - which is precisely what happens when one was
21
- * started before a route file existed - they overwrite each other forever, and
22
- * every write is a full page reload. Without `strictPort` the second `pnpm dev`
23
- * says "Port 3000 is in use, trying another one" and succeeds, so the fight
24
- * starts silently and looks like an inexplicable refresh loop on the first
25
- * server.
26
- */
27
11
  server: { strictPort: true },
28
- ssr: {
29
- /**
30
- * The VitNode API packages mounted at `/api/*`, kept out of the SSR pass.
31
- *
32
- * They are Node libraries rather than app source: `@vitnode/core` loads its
33
- * locale files with a runtime `import("./en.json", { with: { type: "json" } })`
34
- * relative to its own `dist`. Bundling them in this pass moves that chunk
35
- * and the JSON stops resolving, which fails the build outright. Left
36
- * external here, Nitro resolves them from the package itself.
37
- *
38
- * Every VitNode package the app installs belongs on this list - add a
39
- * plugin's package name here when you install one.
40
- *
41
- * This is also what decides the shape of `@vitnode/core/tanstack/*`, so it is
42
- * worth naming the consequence rather than leaving it to be rediscovered.
43
- * Externalised here, the package skips this pass entirely and Nitro's own
44
- * Rollup run inlines its `dist` afterwards - and nothing in that path runs
45
- * the TanStack Start compiler. The *client* build has no such gap: it inlines
46
- * the package, so the compiler transforms it there. So package code reaches
47
- * the browser compiled and the server un-compiled, which is exactly why the
48
- * package may declare `createIsomorphicFn` (its stub falls back to the
49
- * `.server()` branch, which is what a server wants) and may never declare
50
- * `createServerFn` (un-compiled, its handler resolves to `undefined` with no
51
- * error at all). `packages/vitnode/src/tanstack/boundary.test.ts` holds the
52
- * package to that.
53
- *
54
- * Removing `@vitnode/core` from this list to close the gap was measured and
55
- * does not work: the SSR pass then reaches the locale barrel above and the
56
- * build fails on `Could not resolve './en.json'`.
57
- *
58
- * ## `tslib` is here for an entirely different reason
59
- *
60
- * It is not a VitNode package and it is not a Node library. It is here
61
- * because bundling it is broken, in a way that only appears in a production
62
- * build and only once a page renders.
63
- *
64
- * The Radix scroll-lock stack that every modal in a VitNode page pulls in -
65
- * `react-remove-scroll`, `use-sidecar`, `aria-hidden` - does
66
- * `import { __extends } from "tslib"`. Under the `node` condition that
67
- * resolves to `tslib/modules/index.js`, a two-line ESM shim around the
68
- * **CommonJS** `tslib.js`:
69
- *
70
- * import tslib from "../tslib.js";
71
- * const { __extends, … } = tslib;
72
- *
73
- * `tslib.js` defines `__esModule` on its exports, so Rolldown's CJS interop
74
- * helper does not synthesise a `default` - while the call site it generated
75
- * still reads `.default`. Every page that renders a dialog then throws
76
- * `Cannot destructure property '__extends' of undefined`.
77
- *
78
- * Externalised, the file is never bundled: Nitro traces the package into the
79
- * output and Node loads it with Node's own interop, which is correct. An
80
- * alias to `tslib/tslib.es6.mjs` was tried first and is worse - it fixes
81
- * Vite's copy and not Nitro's, because Nitro re-resolves externals itself,
82
- * and the tracer then copies only the file the alias named.
83
- */
84
- external: ["@vitnode/core", "tslib"],
85
- },
86
12
  plugins: [
87
- /**
88
- * All three from `@vitnode/core/framework/vite`.
89
- *
90
- * `vitNodeOptimizeDeps` takes nothing at all: it names the browser
91
- * dependencies of the package's own `dist` so `vite dev` pre-bundles them on
92
- * a cold start. Nothing crawls that `dist` before it is requested, so
93
- * without this list a screen that is opened for the first time discovers a
94
- * dependency mid-session, the optimizer re-runs, and a page holding modules
95
- * from the previous run ends up with two copies of React.
96
- *
97
- * `vitNodeEnv` takes no `clientEnv`: this app publishes nothing to the
98
- * browser beyond the two keys the package inlines for every VitNode install
99
- * (`NEXT_PUBLIC_API_URL`, `NEXT_PUBLIC_WEB_URL`). Anything named there is
100
- * compiled into JavaScript anyone can read, so an empty list is the right
101
- * default and a key is added only when something in the browser genuinely
102
- * reads it.
103
- *
104
- * `appRoot` is `import.meta.dirname` because a Vite config is loaded with the
105
- * working directory set to wherever the command ran, which in this monorepo
106
- * is regularly the repository root.
107
- */
108
- vitNodeEnv(),
109
- vitNodeOptimizeDeps(),
110
- vitNodePluginRoutes({ appRoot: import.meta.dirname }),
13
+ vitnode({ appRoot: import.meta.dirname }),
111
14
  devtools(),
112
15
  nitro({ rollupConfig: { external: [/^@sentry\//] } }),
113
16
  tailwindcss(),
@@ -4,12 +4,12 @@ import coreApi from "@vitnode/core/locales/api/en.json" with { type: "json" };
4
4
  import core from "@vitnode/core/locales/en.json" with { type: "json" };
5
5
  import plugin from "./src/locales/en.json" with { type: "json" };
6
6
 
7
- // Augmenting `use-intl`, not `next-intl`. `AppConfig` is declared by `use-intl`,
8
- // which is what VitNode renders every string through on every host, and a plugin
9
- // is compiled into its own `dist` and imported by whichever app installed it -
10
- // so a type-level dependency on one host's framework is one every installing app
11
- // inherits. `use-intl` must be a direct dependency of this package for the
12
- // reference above to resolve under pnpm's strict `node_modules`.
7
+ // `AppConfig` is declared by `use-intl`, which is what VitNode renders every
8
+ // string through on every host, and a plugin is compiled into its own `dist`
9
+ // and imported by whichever app installed it - so a type-level dependency on
10
+ // one host's framework is one every installing app inherits. `use-intl` must be
11
+ // a direct dependency of this package for the reference above to resolve under
12
+ // pnpm's strict `node_modules`.
13
13
  //
14
14
  // A plugin can render on both sides (UI components and, e.g., emails), so it
15
15
  // types keys against both of core's trees. Add your own server tree here too
@@ -116,6 +116,7 @@ const apiDevDeps = (pm, eslint) => ({
116
116
  "@types/node": versionsPackageJson.typesNode,
117
117
  "@types/react": versionsPackageJson.typesReact,
118
118
  "@types/react-dom": versionsPackageJson.typesReactDom,
119
+ cn: versionsPackageJson.cn,
119
120
  "@vitnode/config": "",
120
121
  dotenv: versionsPackageJson.dotenv,
121
122
  ...withIf(eslint, {
@@ -127,6 +128,7 @@ const apiDevDeps = (pm, eslint) => ({
127
128
  });
128
129
  const tanstackWebDeps = {
129
130
  "@tailwindcss/vite": versionsPackageJson.tailwindVite,
131
+ "@tanstack/react-form": versionsPackageJson.tanstackReactForm,
130
132
  "@tanstack/react-query": versionsPackageJson.tanstackReactQuery,
131
133
  "@tanstack/react-router": versionsPackageJson.tanstackReactRouter,
132
134
  "@tanstack/react-router-ssr-query": versionsPackageJson.tanstackRouterSsrQuery,
@@ -136,7 +138,6 @@ const tanstackWebDeps = {
136
138
  nitro: versionsPackageJson.nitro,
137
139
  react: versionsPackageJson.react,
138
140
  "react-dom": versionsPackageJson.reactDom,
139
- "react-hook-form": versionsPackageJson.rhf,
140
141
  sonner: versionsPackageJson.sonner,
141
142
  tailwindcss: versionsPackageJson.tailwind,
142
143
  tslib: versionsPackageJson.tslib,
@@ -147,7 +148,6 @@ const singleAppDeps = {
147
148
  ...tanstackWebDeps,
148
149
  "@hono/zod-openapi": versionsPackageJson.honoZodOpenapi,
149
150
  "@hono/zod-validator": versionsPackageJson.honoZodValidator,
150
- "@hookform/resolvers": versionsPackageJson.rhfResolvers,
151
151
  "drizzle-kit": versionsPackageJson.drizzleKit,
152
152
  "drizzle-orm": versionsPackageJson.drizzleOrm,
153
153
  hono: versionsPackageJson.hono,
@@ -162,6 +162,7 @@ const tanstackWebDevDeps = {
162
162
  "@types/node": versionsPackageJson.typesNode,
163
163
  "@types/react": versionsPackageJson.typesReact,
164
164
  "@types/react-dom": versionsPackageJson.typesReactDom,
165
+ cn: versionsPackageJson.cn,
165
166
  "@vitejs/plugin-react": versionsPackageJson.viteReact,
166
167
  "@vitnode/config": "",
167
168
  "tw-animate-css": versionsPackageJson.twAnimateCss,
@@ -184,7 +185,6 @@ const webDeps = {
184
185
  };
185
186
  const webDevDeps = (eslint) => ({
186
187
  ...tanstackWebDevDeps,
187
- "@hookform/resolvers": versionsPackageJson.rhfResolvers,
188
188
  "class-variance-authority": versionsPackageJson.cva,
189
189
  ...withIf(eslint, { eslint: versionsPackageJson.eslint }),
190
190
  });
@@ -4,11 +4,17 @@ import { dirname, join } from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
5
  import ora from "ora";
6
6
  import color from "picocolors";
7
+ import { initGitRepository } from "../helpers/init-git.js";
7
8
  import { generateMigrationsVitnode } from "../helpers/init-vitnode.js";
8
9
  import { installDependencies } from "../helpers/install-dependencies.js";
9
10
  import { isFolderEmpty } from "../helpers/is-folder-empty.js";
10
11
  import { createPackageJSON } from "./create-package-json.js";
11
- export const createVitNode = async ({ root, appName, packageManager, eslint, install, docker, mode, monorepo, }) => {
12
+ const GIT_WARNINGS = {
13
+ "already-in-repository": "Skipped git setup - the project already lives inside a git repository.",
14
+ failed: 'Could not initialize a git repository. Run "git init" in the project yourself once git is configured.',
15
+ "git-unavailable": 'Git is not installed, so no repository was created. Run "git init" in the project after installing git.',
16
+ };
17
+ export const createVitNode = async ({ root, appName, packageManager, eslint, git, install, docker, mode, monorepo, }) => {
12
18
  const spinner = ora(`Creating a new VitNode app in ${color.green(root)}. Using ${color.green(packageManager)}...`).start();
13
19
  const __filename = fileURLToPath(import.meta.url);
14
20
  const __dirname = dirname(__filename);
@@ -200,5 +206,13 @@ export const createVitNode = async ({ root, appName, packageManager, eslint, ins
200
206
  process.exit(1);
201
207
  }
202
208
  }
209
+ let gitResult;
210
+ if (git) {
211
+ spinner.text = "Initializing git repository...";
212
+ gitResult = await initGitRepository({ root });
213
+ }
203
214
  spinner.succeed(`${color.green("Success!")} Created ${color.cyan(appName)} at ${color.cyan(root)}`);
215
+ if (gitResult && gitResult !== "created") {
216
+ console.log(color.yellow(GIT_WARNINGS[gitResult]));
217
+ }
204
218
  };
@@ -1,49 +1,49 @@
1
1
  export const versionsPackageJson = {
2
- typesNode: "^26",
3
- typesReact: "^19.2",
4
- typesReactDom: "^19.2",
2
+ typesNode: "^26.5",
3
+ typesReact: "^19.3",
4
+ typesReactDom: "^19.3",
5
5
  typesBun: "latest",
6
6
  turbo: "^2.10",
7
7
  typescript: "^6.0",
8
- tsx: "^4",
8
+ tsx: "^4.23",
9
9
  tscAlias: "^1.9",
10
- eslint: "^10",
10
+ eslint: "^10.10",
11
11
  prettier: "^3.9",
12
12
  prettierTailwind: "^0.8",
13
13
  tailwind: "^4.2",
14
14
  twAnimateCss: "^1.4.0",
15
- react: "^19.2",
16
- reactDom: "^19.2",
17
- useIntl: "^4.13.7",
18
- rhf: "^7",
19
- rhfResolvers: "^5.1.1",
20
- lucide: "^1.21",
21
- sonner: "^2.0.7",
15
+ cn: "^0.3.0",
16
+ react: "^19.3",
17
+ reactDom: "^19.3",
18
+ useIntl: "^4.14.4",
19
+ lucide: "^1.45",
20
+ sonner: "^2.0.8",
22
21
  dotenv: "^17.4",
23
22
  drizzleKit: "1.0.0-rc.4",
24
23
  drizzleOrm: "1.0.0-rc.4",
25
- hono: "^4.12",
26
- honoZodOpenapi: "^1.5",
27
- honoZodValidator: "^0.9",
24
+ hono: "^4.13",
25
+ honoZodOpenapi: "^1.6",
26
+ honoZodValidator: "^0.9.1",
28
27
  reactEmail: "^6.9",
29
28
  reactEmailUi: "^6.9",
30
- zod: "^4.4",
29
+ zod: "^4.6",
31
30
  ws: "^8",
32
31
  cva: "^0.7.1",
32
+ tanstackReactForm: "^1.33",
33
33
  tanstackReactRouter: "^1.170",
34
34
  tanstackReactStart: "^1.168",
35
- tanstackReactQuery: "^5.101",
35
+ tanstackReactQuery: "^5.102",
36
36
  tanstackRouterSsrQuery: "^1.167",
37
37
  tanstackReactDevtools: "^0.10",
38
38
  tanstackDevtoolsVite: "^0.8",
39
39
  tanstackQueryDevtools: "^5.102",
40
40
  tanstackRouterDevtools: "^1.167",
41
- vite: "^8.0",
42
- viteReact: "^6.0",
41
+ vite: "^8.3",
42
+ viteReact: "^6.1",
43
43
  tailwindVite: "^4.2",
44
- nitro: "3.0.260610-beta",
44
+ nitro: "3.0.260903-beta",
45
45
  tslib: "^2.8.1",
46
46
  swcCli: "^0.8.1",
47
- swcCore: "^1.15",
48
- shadcn: "^4",
47
+ swcCore: "^1.16",
48
+ shadcn: "^4.21",
49
49
  };
@@ -0,0 +1,38 @@
1
+ import { rm } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { spawnCommand } from "./spawn-command.js";
4
+ export const DEFAULT_GIT_BRANCH = "main";
5
+ const runGit = async (args, cwd) => new Promise(resolve => {
6
+ const child = spawnCommand("git", args, { cwd, stdio: "ignore" });
7
+ child.on("error", () => {
8
+ resolve(false);
9
+ });
10
+ child.on("close", code => {
11
+ resolve(code === 0);
12
+ });
13
+ });
14
+ export const initGitRepository = async ({ root, branch = DEFAULT_GIT_BRANCH, commitMessage = "Initial commit from Create VitNode App", }) => {
15
+ if (!(await runGit(["--version"], root))) {
16
+ return "git-unavailable";
17
+ }
18
+ if (await runGit(["rev-parse", "--is-inside-work-tree"], root)) {
19
+ return "already-in-repository";
20
+ }
21
+ const removeGitDirectory = async () => {
22
+ await rm(join(root, ".git"), { force: true, recursive: true });
23
+ };
24
+ const initialized = (await runGit(["init", "--initial-branch", branch], root)) ||
25
+ ((await runGit(["init"], root)) &&
26
+ (await runGit(["symbolic-ref", "HEAD", `refs/heads/${branch}`], root)));
27
+ if (!initialized) {
28
+ await removeGitDirectory();
29
+ return "failed";
30
+ }
31
+ const committed = (await runGit(["add", "-A"], root)) &&
32
+ (await runGit(["commit", "-m", commitMessage], root));
33
+ if (!committed) {
34
+ await removeGitDirectory();
35
+ return "failed";
36
+ }
37
+ return "created";
38
+ };
@@ -1,14 +1,13 @@
1
- import { spawn } from "node:child_process";
2
1
  import color from "picocolors";
2
+ import { spawnCommand } from "./spawn-command.js";
3
3
  export const generateMigrationsVitnode = async ({ packageManager: pm, cwd, }) => {
4
4
  const packageManager = pm.split("@")[0];
5
5
  const args = ["vitnode", "migrate", "--generate"];
6
6
  await new Promise((resolve, reject) => {
7
7
  let output = "";
8
- const child = spawn(packageManager, args, {
8
+ const child = spawnCommand(packageManager, args, {
9
9
  cwd,
10
10
  env: process.env,
11
- shell: true,
12
11
  stdio: "pipe",
13
12
  });
14
13
  child.stdout?.on("data", (data) => {