create-vitnode-app 0.0.1-canary.0
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/LICENSE.md +21 -0
- package/README.md +78 -0
- package/copy-of-vitnode-app/.vscode/settings.json +10 -0
- package/copy-of-vitnode-app/README.md +40 -0
- package/copy-of-vitnode-app/api/.gitignore_template +32 -0
- package/copy-of-vitnode-app/api/drizzle.config.ts +12 -0
- package/copy-of-vitnode-app/api/src/i18n.ts +38 -0
- package/copy-of-vitnode-app/api/src/index.ts +27 -0
- package/copy-of-vitnode-app/api/src/vitnode.api.config.ts +40 -0
- package/copy-of-vitnode-app/api/tsconfig.json +17 -0
- package/copy-of-vitnode-app/api-bun/src/index.ts +16 -0
- package/copy-of-vitnode-app/api-single-app/drizzle.config.ts +12 -0
- package/copy-of-vitnode-app/api-single-app/src/routes/api/$.ts +32 -0
- package/copy-of-vitnode-app/api-single-app/src/server/api-bridge.ts +22 -0
- package/copy-of-vitnode-app/api-single-app/src/server/vitnode-api.server.ts +29 -0
- package/copy-of-vitnode-app/api-single-app/src/vitnode.api.config.ts +37 -0
- package/copy-of-vitnode-app/docker/docker-compose.yml +30 -0
- package/copy-of-vitnode-app/eslint/.prettierrc.mjs +11 -0
- package/copy-of-vitnode-app/eslint/eslint.config.mjs +19 -0
- package/copy-of-vitnode-app/eslint-react/.prettierrc.mjs +11 -0
- package/copy-of-vitnode-app/eslint-react/eslint.config.mjs +19 -0
- package/copy-of-vitnode-app/monorepo/.gitignore_template +41 -0
- package/copy-of-vitnode-app/monorepo/apps/api/.env.example +12 -0
- package/copy-of-vitnode-app/monorepo/apps/web/.env.example +12 -0
- package/copy-of-vitnode-app/monorepo/turbo.json +53 -0
- package/copy-of-vitnode-app/root/.env.example +22 -0
- package/copy-of-vitnode-app/root/.gitignore_template +41 -0
- package/copy-of-vitnode-app/root/global.d.ts +28 -0
- package/copy-of-vitnode-app/root/src/components/admin-shell.tsx +72 -0
- package/copy-of-vitnode-app/root/src/components/main-header.tsx +33 -0
- package/copy-of-vitnode-app/root/src/i18n.ts +36 -0
- package/copy-of-vitnode-app/root/src/lib/admin-auth.ts +11 -0
- package/copy-of-vitnode-app/root/src/lib/admin-nav.ts +43 -0
- package/copy-of-vitnode-app/root/src/lib/admin-search.ts +37 -0
- package/copy-of-vitnode-app/root/src/lib/auth.ts +66 -0
- package/copy-of-vitnode-app/root/src/lib/content-registry.ts +51 -0
- package/copy-of-vitnode-app/root/src/lib/document-headers.ts +128 -0
- package/copy-of-vitnode-app/root/src/lib/i18n/runtime.ts +75 -0
- package/copy-of-vitnode-app/root/src/lib/i18n/shared.ts +20 -0
- package/copy-of-vitnode-app/root/src/lib/navigation.ts +24 -0
- package/copy-of-vitnode-app/root/src/lib/page-head.ts +19 -0
- package/copy-of-vitnode-app/root/src/locales/app.ts +28 -0
- package/copy-of-vitnode-app/root/src/locales/packages.ts +43 -0
- package/copy-of-vitnode-app/root/src/router.tsx +227 -0
- package/copy-of-vitnode-app/root/src/routes/__root.tsx +212 -0
- package/copy-of-vitnode-app/root/src/routes/_admin/admin.core.index.tsx +70 -0
- package/copy-of-vitnode-app/root/src/routes/_admin.tsx +258 -0
- package/copy-of-vitnode-app/root/src/routes/_main/index.tsx +60 -0
- package/copy-of-vitnode-app/root/src/routes/_main.tsx +64 -0
- package/copy-of-vitnode-app/root/src/server/messages.server.ts +29 -0
- package/copy-of-vitnode-app/root/src/start.ts +88 -0
- package/copy-of-vitnode-app/root/src/styles.css +171 -0
- package/copy-of-vitnode-app/root/src/vitnode.config.ts +58 -0
- package/copy-of-vitnode-app/root/src/vitnode.shell.config.ts +35 -0
- package/copy-of-vitnode-app/root/tsconfig.json +29 -0
- package/copy-of-vitnode-app/root/tsr.config.json +3 -0
- package/copy-of-vitnode-app/root/vite.config.ts +119 -0
- package/copy-of-vitnode-plugin/root/.swcrc +26 -0
- package/copy-of-vitnode-plugin/root/global.d.ts +21 -0
- package/copy-of-vitnode-plugin/root/npmignore.template +17 -0
- package/copy-of-vitnode-plugin/root/tsconfig.build.json +5 -0
- package/copy-of-vitnode-plugin/root/tsconfig.json +25 -0
- package/dist/src/create/create-package-json.js +276 -0
- package/dist/src/create/create-vitnode.js +204 -0
- package/dist/src/create/package-versions.js +49 -0
- package/dist/src/helpers/get-available-package-managers.js +24 -0
- package/dist/src/helpers/get-package-json.js +2 -0
- package/dist/src/helpers/get-package-manager-from-root.js +15 -0
- package/dist/src/helpers/get-vitnode-package-version.js +9 -0
- package/dist/src/helpers/init-vitnode.js +34 -0
- package/dist/src/helpers/install-dependencies.js +71 -0
- package/dist/src/helpers/is-folder-empty.js +48 -0
- package/dist/src/helpers/is-online.js +38 -0
- package/dist/src/helpers/is-writeable.js +11 -0
- package/dist/src/helpers/packages-json.js +1 -0
- package/dist/src/helpers/validate-pkg.js +14 -0
- package/dist/src/helpers/with-If.js +1 -0
- package/dist/src/index.js +68 -0
- package/dist/src/plugin/create/add-plugin-to-workspace.js +74 -0
- package/dist/src/plugin/create/create-package-json.js +54 -0
- package/dist/src/plugin/create/create-plugin-vitnode.js +80 -0
- package/dist/src/plugin/create/route-templates.js +144 -0
- package/dist/src/plugin/index.js +29 -0
- package/dist/src/plugin/questions.js +14 -0
- package/dist/src/plugin/validation.js +76 -0
- package/dist/src/prepare/prepare.js +19 -0
- package/dist/src/questions.js +83 -0
- package/dist/src/validation.js +40 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -0
- package/package.json +55 -0
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
@import 'tailwindcss';
|
|
2
|
+
@import 'shadcn/tailwind.css';
|
|
3
|
+
@import 'tw-animate-css';
|
|
4
|
+
|
|
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
|
+
@source "../node_modules/@vitnode/core/dist/src/components";
|
|
27
|
+
@source "../node_modules/@vitnode/core/dist/src/tanstack";
|
|
28
|
+
@source "../node_modules/@vitnode/core/dist/src/views";
|
|
29
|
+
|
|
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
|
+
:root:not(.dark) {
|
|
36
|
+
--background: oklch(0.97 0 0);
|
|
37
|
+
--foreground: oklch(0.145 0 0);
|
|
38
|
+
--card: oklch(1 0 0);
|
|
39
|
+
--card-foreground: oklch(0.145 0 0);
|
|
40
|
+
--popover: oklch(1 0 0);
|
|
41
|
+
--popover-foreground: oklch(0.145 0 0);
|
|
42
|
+
--primary: oklch(0.51 0.16 262.61);
|
|
43
|
+
--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);
|
|
60
|
+
--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);
|
|
63
|
+
--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);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.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);
|
|
77
|
+
--primary: oklch(0.6 0.18 262.65);
|
|
78
|
+
--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);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
:root {
|
|
106
|
+
--radius: 0.625rem;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
@theme inline {
|
|
110
|
+
--font-heading: var(--font-sans);
|
|
111
|
+
--color-sidebar-ring: var(--sidebar-ring);
|
|
112
|
+
--color-sidebar-border: var(--sidebar-border);
|
|
113
|
+
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
|
114
|
+
--color-sidebar-accent: var(--sidebar-accent);
|
|
115
|
+
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
|
116
|
+
--color-sidebar-primary: var(--sidebar-primary);
|
|
117
|
+
--color-sidebar-foreground: var(--sidebar-foreground);
|
|
118
|
+
--color-sidebar: var(--sidebar);
|
|
119
|
+
--color-chart-5: var(--chart-5);
|
|
120
|
+
--color-chart-4: var(--chart-4);
|
|
121
|
+
--color-chart-3: var(--chart-3);
|
|
122
|
+
--color-chart-2: var(--chart-2);
|
|
123
|
+
--color-chart-1: var(--chart-1);
|
|
124
|
+
--color-ring: var(--ring);
|
|
125
|
+
--color-input: var(--input);
|
|
126
|
+
--color-border: var(--border);
|
|
127
|
+
--color-warn: var(--warn);
|
|
128
|
+
--color-destructive: var(--destructive);
|
|
129
|
+
--color-accent-foreground: var(--accent-foreground);
|
|
130
|
+
--color-accent: var(--accent);
|
|
131
|
+
--color-muted-foreground: var(--muted-foreground);
|
|
132
|
+
--color-muted: var(--muted);
|
|
133
|
+
--color-secondary-foreground: var(--secondary-foreground);
|
|
134
|
+
--color-secondary: var(--secondary);
|
|
135
|
+
--color-primary-foreground: var(--primary-foreground);
|
|
136
|
+
--color-primary: var(--primary);
|
|
137
|
+
--color-popover-foreground: var(--popover-foreground);
|
|
138
|
+
--color-popover: var(--popover);
|
|
139
|
+
--color-card-foreground: var(--card-foreground);
|
|
140
|
+
--color-card: var(--card);
|
|
141
|
+
--color-foreground: var(--foreground);
|
|
142
|
+
--color-background: var(--background);
|
|
143
|
+
--radius-sm: calc(var(--radius) * 0.6);
|
|
144
|
+
--radius-md: calc(var(--radius) * 0.8);
|
|
145
|
+
--radius-lg: var(--radius);
|
|
146
|
+
--radius-xl: calc(var(--radius) * 1.4);
|
|
147
|
+
--radius-2xl: calc(var(--radius) * 1.8);
|
|
148
|
+
--radius-3xl: calc(var(--radius) * 2.2);
|
|
149
|
+
--radius-4xl: calc(var(--radius) * 2.6);
|
|
150
|
+
}
|
|
151
|
+
|
|
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
|
+
@layer base {
|
|
159
|
+
* {
|
|
160
|
+
@apply border-border outline-ring/50;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
html,
|
|
164
|
+
body {
|
|
165
|
+
min-height: 100%;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
body {
|
|
169
|
+
@apply bg-background text-foreground antialiased;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { buildConfig } from "@vitnode/core/vitnode.config";
|
|
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
|
+
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 },
|
|
57
|
+
plugins: [],
|
|
58
|
+
});
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { VitNodeConfig } from "@vitnode/core/vitnode.config";
|
|
2
|
+
|
|
3
|
+
import { i18n } from "./i18n";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The VitNode config the browser is allowed to see.
|
|
7
|
+
*
|
|
8
|
+
* Everything in `VitNodeConfig` except `plugins`, and that omission is the whole
|
|
9
|
+
* point. The plugin registry carries each plugin's translations as `import()`s
|
|
10
|
+
* of JSON inside its `dist`, and eventually its AdminCP components - neither of
|
|
11
|
+
* which a browser bundle should hold. In Next.js the boundary is drawn for you:
|
|
12
|
+
* `vitnode.config.ts` is only ever read by Server Components, so none of it
|
|
13
|
+
* reaches the client. TanStack Start has no such boundary - anything the root
|
|
14
|
+
* route imports is in the browser bundle - so the split is made here instead, by
|
|
15
|
+
* hand.
|
|
16
|
+
*
|
|
17
|
+
* `vitnode.config.ts` spreads this into `buildConfig` with the plugins added, so
|
|
18
|
+
* there is one source for the metadata, the theme and the locales rather than
|
|
19
|
+
* two that agree until they don't.
|
|
20
|
+
*
|
|
21
|
+
* Everything here is plain, serializable data. That is a rule, not a
|
|
22
|
+
* coincidence: this module is imported by the document shell, which renders on
|
|
23
|
+
* both sides of hydration.
|
|
24
|
+
*/
|
|
25
|
+
export const vitNodeShellConfig = {
|
|
26
|
+
debug: false,
|
|
27
|
+
i18n,
|
|
28
|
+
metadata: {
|
|
29
|
+
shortTitle: "VitNode",
|
|
30
|
+
title: "VitNode",
|
|
31
|
+
},
|
|
32
|
+
theme: {
|
|
33
|
+
defaultTheme: "system",
|
|
34
|
+
},
|
|
35
|
+
} satisfies Omit<VitNodeConfig, "plugins">;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"include": ["**/*.ts", "**/*.tsx", "eslint.config.js", "prettier.config.js", "vite.config.js"],
|
|
3
|
+
|
|
4
|
+
"compilerOptions": {
|
|
5
|
+
"target": "ES2022",
|
|
6
|
+
"jsx": "react-jsx",
|
|
7
|
+
"module": "ESNext",
|
|
8
|
+
"paths": {
|
|
9
|
+
"#/*": ["./src/*"],
|
|
10
|
+
"@/*": ["./src/*"]
|
|
11
|
+
},
|
|
12
|
+
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
|
13
|
+
"types": ["vite/client", "node"],
|
|
14
|
+
|
|
15
|
+
/* Bundler mode */
|
|
16
|
+
"moduleResolution": "bundler",
|
|
17
|
+
"allowImportingTsExtensions": true,
|
|
18
|
+
"verbatimModuleSyntax": true,
|
|
19
|
+
"noEmit": true,
|
|
20
|
+
|
|
21
|
+
/* Linting */
|
|
22
|
+
"skipLibCheck": true,
|
|
23
|
+
"strict": true,
|
|
24
|
+
"noUnusedLocals": true,
|
|
25
|
+
"noUnusedParameters": true,
|
|
26
|
+
"noFallthroughCasesInSwitch": true,
|
|
27
|
+
"noUncheckedSideEffectImports": true
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import tailwindcss from "@tailwindcss/vite";
|
|
2
|
+
import { devtools } from "@tanstack/devtools-vite";
|
|
3
|
+
import { tanstackStart } from "@tanstack/react-start/plugin/vite";
|
|
4
|
+
import viteReact from "@vitejs/plugin-react";
|
|
5
|
+
import {
|
|
6
|
+
vitNodeEnv,
|
|
7
|
+
vitNodeOptimizeDeps,
|
|
8
|
+
vitNodePluginRoutes,
|
|
9
|
+
} from "@vitnode/core/framework/vite";
|
|
10
|
+
import { nitro } from "nitro/vite";
|
|
11
|
+
import { defineConfig } from "vite";
|
|
12
|
+
|
|
13
|
+
const config = defineConfig({
|
|
14
|
+
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
|
+
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
|
+
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 }),
|
|
111
|
+
devtools(),
|
|
112
|
+
nitro({ rollupConfig: { external: [/^@sentry\//] } }),
|
|
113
|
+
tailwindcss(),
|
|
114
|
+
tanstackStart(),
|
|
115
|
+
viteReact(),
|
|
116
|
+
],
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
export default config;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://swc.rs/schema.json",
|
|
3
|
+
"exclude": ["\\.test\\.tsx?$"],
|
|
4
|
+
"minify": true,
|
|
5
|
+
"jsc": {
|
|
6
|
+
"baseUrl": "./",
|
|
7
|
+
"target": "esnext",
|
|
8
|
+
"paths": {
|
|
9
|
+
"@/*": ["./src/*"]
|
|
10
|
+
},
|
|
11
|
+
"parser": {
|
|
12
|
+
"syntax": "typescript",
|
|
13
|
+
"tsx": true
|
|
14
|
+
},
|
|
15
|
+
"transform": {
|
|
16
|
+
"react": {
|
|
17
|
+
"runtime": "automatic"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"module": {
|
|
22
|
+
"type": "nodenext",
|
|
23
|
+
"strict": true,
|
|
24
|
+
"resolveFully": true
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/// <reference types="use-intl" />
|
|
2
|
+
|
|
3
|
+
import coreApi from "@vitnode/core/locales/api/en.json" with { type: "json" };
|
|
4
|
+
import core from "@vitnode/core/locales/en.json" with { type: "json" };
|
|
5
|
+
import plugin from "./src/locales/en.json" with { type: "json" };
|
|
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`.
|
|
13
|
+
//
|
|
14
|
+
// A plugin can render on both sides (UI components and, e.g., emails), so it
|
|
15
|
+
// types keys against both of core's trees. Add your own server tree here too
|
|
16
|
+
// (`./src/locales/api/en.json`) once your plugin sends email.
|
|
17
|
+
declare module "use-intl" {
|
|
18
|
+
interface AppConfig {
|
|
19
|
+
Messages: typeof plugin & typeof core & typeof coreApi;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/src/*
|
|
2
|
+
!/src/routes
|
|
3
|
+
!/src/routes/**
|
|
4
|
+
!/src/locales
|
|
5
|
+
!/src/locales/**
|
|
6
|
+
|
|
7
|
+
/node_modules
|
|
8
|
+
/.turbo
|
|
9
|
+
/tsconfig.json
|
|
10
|
+
/.swcrc
|
|
11
|
+
/components.json
|
|
12
|
+
/global.d.ts
|
|
13
|
+
/tsup.config.ts
|
|
14
|
+
/vitest.config.ts
|
|
15
|
+
/tsconfig.json
|
|
16
|
+
/scripts
|
|
17
|
+
/config
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json.schemastore.org/tsconfig",
|
|
3
|
+
"extends": "@vitnode/config/tsconfig",
|
|
4
|
+
"compilerOptions": {
|
|
5
|
+
"target": "ESNext",
|
|
6
|
+
"module": "esnext",
|
|
7
|
+
"moduleResolution": "bundler",
|
|
8
|
+
"rootDir": "./",
|
|
9
|
+
"outDir": "./dist",
|
|
10
|
+
"jsx": "react-jsx",
|
|
11
|
+
"emitDeclarationOnly": true,
|
|
12
|
+
"declaration": true,
|
|
13
|
+
"declarationMap": true,
|
|
14
|
+
"plugins": [
|
|
15
|
+
{
|
|
16
|
+
"name": "next"
|
|
17
|
+
}
|
|
18
|
+
],
|
|
19
|
+
"paths": {
|
|
20
|
+
"@/*": ["./src/*"]
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"exclude": ["node_modules"],
|
|
24
|
+
"include": ["src", "global.d.ts"]
|
|
25
|
+
}
|