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.
Files changed (90) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +78 -0
  3. package/copy-of-vitnode-app/.vscode/settings.json +10 -0
  4. package/copy-of-vitnode-app/README.md +40 -0
  5. package/copy-of-vitnode-app/api/.gitignore_template +32 -0
  6. package/copy-of-vitnode-app/api/drizzle.config.ts +12 -0
  7. package/copy-of-vitnode-app/api/src/i18n.ts +38 -0
  8. package/copy-of-vitnode-app/api/src/index.ts +27 -0
  9. package/copy-of-vitnode-app/api/src/vitnode.api.config.ts +40 -0
  10. package/copy-of-vitnode-app/api/tsconfig.json +17 -0
  11. package/copy-of-vitnode-app/api-bun/src/index.ts +16 -0
  12. package/copy-of-vitnode-app/api-single-app/drizzle.config.ts +12 -0
  13. package/copy-of-vitnode-app/api-single-app/src/routes/api/$.ts +32 -0
  14. package/copy-of-vitnode-app/api-single-app/src/server/api-bridge.ts +22 -0
  15. package/copy-of-vitnode-app/api-single-app/src/server/vitnode-api.server.ts +29 -0
  16. package/copy-of-vitnode-app/api-single-app/src/vitnode.api.config.ts +37 -0
  17. package/copy-of-vitnode-app/docker/docker-compose.yml +30 -0
  18. package/copy-of-vitnode-app/eslint/.prettierrc.mjs +11 -0
  19. package/copy-of-vitnode-app/eslint/eslint.config.mjs +19 -0
  20. package/copy-of-vitnode-app/eslint-react/.prettierrc.mjs +11 -0
  21. package/copy-of-vitnode-app/eslint-react/eslint.config.mjs +19 -0
  22. package/copy-of-vitnode-app/monorepo/.gitignore_template +41 -0
  23. package/copy-of-vitnode-app/monorepo/apps/api/.env.example +12 -0
  24. package/copy-of-vitnode-app/monorepo/apps/web/.env.example +12 -0
  25. package/copy-of-vitnode-app/monorepo/turbo.json +53 -0
  26. package/copy-of-vitnode-app/root/.env.example +22 -0
  27. package/copy-of-vitnode-app/root/.gitignore_template +41 -0
  28. package/copy-of-vitnode-app/root/global.d.ts +28 -0
  29. package/copy-of-vitnode-app/root/src/components/admin-shell.tsx +72 -0
  30. package/copy-of-vitnode-app/root/src/components/main-header.tsx +33 -0
  31. package/copy-of-vitnode-app/root/src/i18n.ts +36 -0
  32. package/copy-of-vitnode-app/root/src/lib/admin-auth.ts +11 -0
  33. package/copy-of-vitnode-app/root/src/lib/admin-nav.ts +43 -0
  34. package/copy-of-vitnode-app/root/src/lib/admin-search.ts +37 -0
  35. package/copy-of-vitnode-app/root/src/lib/auth.ts +66 -0
  36. package/copy-of-vitnode-app/root/src/lib/content-registry.ts +51 -0
  37. package/copy-of-vitnode-app/root/src/lib/document-headers.ts +128 -0
  38. package/copy-of-vitnode-app/root/src/lib/i18n/runtime.ts +75 -0
  39. package/copy-of-vitnode-app/root/src/lib/i18n/shared.ts +20 -0
  40. package/copy-of-vitnode-app/root/src/lib/navigation.ts +24 -0
  41. package/copy-of-vitnode-app/root/src/lib/page-head.ts +19 -0
  42. package/copy-of-vitnode-app/root/src/locales/app.ts +28 -0
  43. package/copy-of-vitnode-app/root/src/locales/packages.ts +43 -0
  44. package/copy-of-vitnode-app/root/src/router.tsx +227 -0
  45. package/copy-of-vitnode-app/root/src/routes/__root.tsx +212 -0
  46. package/copy-of-vitnode-app/root/src/routes/_admin/admin.core.index.tsx +70 -0
  47. package/copy-of-vitnode-app/root/src/routes/_admin.tsx +258 -0
  48. package/copy-of-vitnode-app/root/src/routes/_main/index.tsx +60 -0
  49. package/copy-of-vitnode-app/root/src/routes/_main.tsx +64 -0
  50. package/copy-of-vitnode-app/root/src/server/messages.server.ts +29 -0
  51. package/copy-of-vitnode-app/root/src/start.ts +88 -0
  52. package/copy-of-vitnode-app/root/src/styles.css +171 -0
  53. package/copy-of-vitnode-app/root/src/vitnode.config.ts +58 -0
  54. package/copy-of-vitnode-app/root/src/vitnode.shell.config.ts +35 -0
  55. package/copy-of-vitnode-app/root/tsconfig.json +29 -0
  56. package/copy-of-vitnode-app/root/tsr.config.json +3 -0
  57. package/copy-of-vitnode-app/root/vite.config.ts +119 -0
  58. package/copy-of-vitnode-plugin/root/.swcrc +26 -0
  59. package/copy-of-vitnode-plugin/root/global.d.ts +21 -0
  60. package/copy-of-vitnode-plugin/root/npmignore.template +17 -0
  61. package/copy-of-vitnode-plugin/root/tsconfig.build.json +5 -0
  62. package/copy-of-vitnode-plugin/root/tsconfig.json +25 -0
  63. package/dist/src/create/create-package-json.js +276 -0
  64. package/dist/src/create/create-vitnode.js +204 -0
  65. package/dist/src/create/package-versions.js +49 -0
  66. package/dist/src/helpers/get-available-package-managers.js +24 -0
  67. package/dist/src/helpers/get-package-json.js +2 -0
  68. package/dist/src/helpers/get-package-manager-from-root.js +15 -0
  69. package/dist/src/helpers/get-vitnode-package-version.js +9 -0
  70. package/dist/src/helpers/init-vitnode.js +34 -0
  71. package/dist/src/helpers/install-dependencies.js +71 -0
  72. package/dist/src/helpers/is-folder-empty.js +48 -0
  73. package/dist/src/helpers/is-online.js +38 -0
  74. package/dist/src/helpers/is-writeable.js +11 -0
  75. package/dist/src/helpers/packages-json.js +1 -0
  76. package/dist/src/helpers/validate-pkg.js +14 -0
  77. package/dist/src/helpers/with-If.js +1 -0
  78. package/dist/src/index.js +68 -0
  79. package/dist/src/plugin/create/add-plugin-to-workspace.js +74 -0
  80. package/dist/src/plugin/create/create-package-json.js +54 -0
  81. package/dist/src/plugin/create/create-plugin-vitnode.js +80 -0
  82. package/dist/src/plugin/create/route-templates.js +144 -0
  83. package/dist/src/plugin/index.js +29 -0
  84. package/dist/src/plugin/questions.js +14 -0
  85. package/dist/src/plugin/validation.js +76 -0
  86. package/dist/src/prepare/prepare.js +19 -0
  87. package/dist/src/questions.js +83 -0
  88. package/dist/src/validation.js +40 -0
  89. package/dist/tsconfig.build.tsbuildinfo +1 -0
  90. 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,3 @@
1
+ {
2
+ "target": "react"
3
+ }
@@ -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,5 @@
1
+ {
2
+ "$schema": "https://json.schemastore.org/tsconfig",
3
+ "extends": "./tsconfig.json",
4
+ "exclude": ["node_modules", "**/*.test.ts", "**/*.test.tsx"]
5
+ }
@@ -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
+ }