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.
- package/README.md +9 -2
- package/copy-of-vitnode-app/README.md +22 -0
- package/copy-of-vitnode-app/api/src/vitnode.api.config.ts +10 -11
- package/copy-of-vitnode-app/api-single-app/src/routes/api/$.ts +4 -26
- package/copy-of-vitnode-app/api-single-app/src/server/api-bridge.ts +1 -12
- package/copy-of-vitnode-app/api-single-app/src/server/vitnode-api.server.ts +13 -13
- package/copy-of-vitnode-app/api-single-app/src/vitnode.api.config.ts +3 -12
- package/copy-of-vitnode-app/docker/docker-compose.yml +6 -4
- package/copy-of-vitnode-app/monorepo/apps/api/.env.example +1 -1
- package/copy-of-vitnode-app/monorepo/apps/web/.env.example +1 -12
- package/copy-of-vitnode-app/monorepo/turbo.json +2 -2
- package/copy-of-vitnode-app/root/.env.example +1 -8
- package/copy-of-vitnode-app/root/global.d.ts +1 -19
- package/copy-of-vitnode-app/root/src/components/admin-shell.tsx +2 -53
- package/copy-of-vitnode-app/root/src/components/main-footer.tsx +44 -0
- package/copy-of-vitnode-app/root/src/components/main-header.tsx +1 -30
- package/copy-of-vitnode-app/root/src/lib/i18n.ts +37 -0
- package/copy-of-vitnode-app/root/src/locales/app.ts +1 -25
- package/copy-of-vitnode-app/root/src/locales/packages.ts +1 -34
- package/copy-of-vitnode-app/root/src/router.tsx +9 -165
- package/copy-of-vitnode-app/root/src/routes/__root.tsx +12 -115
- package/copy-of-vitnode-app/root/src/routes/_admin/admin.core.index.tsx +4 -54
- package/copy-of-vitnode-app/root/src/routes/_admin.tsx +5 -198
- package/copy-of-vitnode-app/root/src/routes/_main/index.tsx +182 -46
- package/copy-of-vitnode-app/root/src/routes/_main.tsx +12 -47
- package/copy-of-vitnode-app/root/src/server/messages.server.ts +2 -23
- package/copy-of-vitnode-app/root/src/start.ts +3 -86
- package/copy-of-vitnode-app/root/src/styles.css +70 -92
- package/copy-of-vitnode-app/root/src/vitnode.config.ts +15 -53
- package/copy-of-vitnode-app/root/src/vitnode.server.config.ts +12 -0
- package/copy-of-vitnode-app/root/tsconfig.json +8 -3
- package/copy-of-vitnode-app/root/vite.config.ts +2 -99
- package/copy-of-vitnode-plugin/root/global.d.ts +6 -6
- package/dist/src/create/create-package-json.js +3 -3
- package/dist/src/create/create-vitnode.js +15 -1
- package/dist/src/create/package-versions.js +22 -22
- package/dist/src/helpers/init-git.js +38 -0
- package/dist/src/helpers/init-vitnode.js +2 -3
- package/dist/src/helpers/install-dependencies.js +2 -3
- package/dist/src/helpers/spawn-command.js +7 -0
- package/dist/src/index.js +1 -0
- package/dist/src/plugin/create/add-plugin-to-config.js +231 -0
- package/dist/src/plugin/create/create-package-json.js +2 -1
- package/dist/src/plugin/create/create-plugin-vitnode.js +23 -2
- package/dist/src/plugin/create/route-templates.js +103 -61
- package/dist/src/questions.js +7 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +6 -6
- package/copy-of-vitnode-app/api/src/i18n.ts +0 -38
- package/copy-of-vitnode-app/root/src/i18n.ts +0 -36
- package/copy-of-vitnode-app/root/src/lib/admin-auth.ts +0 -11
- package/copy-of-vitnode-app/root/src/lib/admin-nav.ts +0 -43
- package/copy-of-vitnode-app/root/src/lib/admin-search.ts +0 -37
- package/copy-of-vitnode-app/root/src/lib/auth.ts +0 -66
- package/copy-of-vitnode-app/root/src/lib/content-registry.ts +0 -51
- package/copy-of-vitnode-app/root/src/lib/document-headers.ts +0 -128
- package/copy-of-vitnode-app/root/src/lib/i18n/runtime.ts +0 -75
- package/copy-of-vitnode-app/root/src/lib/i18n/shared.ts +0 -20
- package/copy-of-vitnode-app/root/src/lib/navigation.ts +0 -24
- package/copy-of-vitnode-app/root/src/lib/page-head.ts +0 -19
- package/copy-of-vitnode-app/root/src/vitnode.shell.config.ts +0 -35
|
@@ -1,105 +1,84 @@
|
|
|
1
|
-
@import
|
|
2
|
-
@import
|
|
3
|
-
@import
|
|
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
|
-
|
|
37
|
-
--
|
|
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.
|
|
15
|
+
--card-foreground: oklch(0.23 0.021 264);
|
|
40
16
|
--popover: oklch(1 0 0);
|
|
41
|
-
--popover-foreground: oklch(0.
|
|
42
|
-
--primary: oklch(0.
|
|
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.
|
|
45
|
-
--secondary-foreground: oklch(0.
|
|
46
|
-
--muted: oklch(0.
|
|
47
|
-
--muted-foreground: oklch(0.
|
|
48
|
-
--accent: oklch(0.
|
|
49
|
-
--accent-foreground: oklch(0.
|
|
50
|
-
--destructive: oklch(0.
|
|
51
|
-
--
|
|
52
|
-
--
|
|
53
|
-
--
|
|
54
|
-
--
|
|
55
|
-
--
|
|
56
|
-
--chart-
|
|
57
|
-
--chart-
|
|
58
|
-
--chart-
|
|
59
|
-
--chart-
|
|
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.
|
|
62
|
-
--sidebar-primary: oklch(0.
|
|
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
|
|
65
|
-
--sidebar-accent-foreground: oklch(0.
|
|
66
|
-
--sidebar-border: oklch(0.
|
|
67
|
-
--sidebar-ring: oklch(0.
|
|
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
|
-
|
|
72
|
-
--
|
|
73
|
-
--
|
|
74
|
-
--card
|
|
75
|
-
--
|
|
76
|
-
--popover
|
|
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.
|
|
80
|
-
--secondary-foreground: oklch(0.
|
|
81
|
-
--muted: oklch(0.
|
|
82
|
-
--muted-foreground: oklch(0.
|
|
83
|
-
--accent: oklch(0.
|
|
84
|
-
--accent-foreground: oklch(0.
|
|
85
|
-
--destructive: oklch(0.
|
|
86
|
-
--
|
|
87
|
-
--
|
|
88
|
-
--
|
|
89
|
-
--
|
|
90
|
-
--
|
|
91
|
-
--chart-
|
|
92
|
-
--chart-
|
|
93
|
-
--chart-
|
|
94
|
-
--chart-
|
|
95
|
-
--
|
|
96
|
-
--sidebar
|
|
97
|
-
--sidebar-
|
|
98
|
-
--sidebar-primary
|
|
99
|
-
--sidebar-
|
|
100
|
-
--sidebar-accent
|
|
101
|
-
--sidebar-
|
|
102
|
-
--sidebar-
|
|
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
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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": [
|
|
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
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
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
|
-
|
|
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.
|
|
4
|
-
typesReactDom: "^19.
|
|
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
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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.
|
|
26
|
-
honoZodOpenapi: "^1.
|
|
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.
|
|
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.
|
|
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.
|
|
42
|
-
viteReact: "^6.
|
|
41
|
+
vite: "^8.3",
|
|
42
|
+
viteReact: "^6.1",
|
|
43
43
|
tailwindVite: "^4.2",
|
|
44
|
-
nitro: "3.0.
|
|
44
|
+
nitro: "3.0.260903-beta",
|
|
45
45
|
tslib: "^2.8.1",
|
|
46
46
|
swcCli: "^0.8.1",
|
|
47
|
-
swcCore: "^1.
|
|
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 =
|
|
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) => {
|