create-vitnode-app 1.2.0-canary.5 → 1.2.0-canary.51
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 +1 -1
- package/README.md +14 -5
- package/copy-of-vitnode-app/.vscode/settings.json +6 -0
- package/copy-of-vitnode-app/api/.gitignore_template +29 -0
- package/copy-of-vitnode-app/api/drizzle.config.ts +12 -0
- package/copy-of-vitnode-app/api/package.json +43 -0
- package/copy-of-vitnode-app/api/src/index.ts +27 -0
- package/copy-of-vitnode-app/api/src/locales/@vitnode/blog/en.json +70 -0
- package/copy-of-vitnode-app/api/src/locales/@vitnode/core/en.json +217 -0
- package/copy-of-vitnode-app/api/src/vitnode.api.config.ts +33 -0
- package/copy-of-vitnode-app/api/tsconfig.json +16 -0
- package/copy-of-vitnode-app/api-bun/src/index.ts +16 -0
- package/copy-of-vitnode-app/api-single-app/.env.example +8 -0
- package/copy-of-vitnode-app/api-single-app/.gitignore_template +37 -0
- package/copy-of-vitnode-app/{root → api-single-app}/src/app/api/[...route]/route.ts +0 -2
- package/copy-of-vitnode-app/api-single-app/src/vitnode.api.config.ts +19 -0
- package/copy-of-vitnode-app/docker/docker-compose.yml +20 -0
- package/copy-of-vitnode-app/eslint/.prettierrc.mjs +1 -1
- package/copy-of-vitnode-app/eslint/eslint.config.mjs +16 -2
- package/copy-of-vitnode-app/monorepo/.gitignore_template +41 -0
- package/copy-of-vitnode-app/monorepo/apps/api/.env.example +8 -0
- package/copy-of-vitnode-app/monorepo/apps/web/.env.example +1 -0
- package/copy-of-vitnode-app/monorepo/turbo.json +47 -0
- package/copy-of-vitnode-app/root/.env.example +9 -0
- package/copy-of-vitnode-app/root/.gitignore_template +37 -0
- package/copy-of-vitnode-app/root/README.md +48 -0
- package/copy-of-vitnode-app/root/global.d.ts +9 -0
- package/copy-of-vitnode-app/root/src/app/[locale]/(main)/layout.tsx +6 -1
- package/copy-of-vitnode-app/root/src/app/[locale]/(main)/page.tsx +9 -17
- package/copy-of-vitnode-app/root/src/app/[locale]/layout.tsx +11 -7
- package/copy-of-vitnode-app/root/src/app/global.css +61 -62
- package/copy-of-vitnode-app/root/src/middleware.ts +24 -0
- package/copy-of-vitnode-app/root/src/vitnode.config.ts +32 -0
- package/copy-of-vitnode-app/root/tsconfig.json +1 -1
- package/dist/src/create/create-package-json.js +231 -40
- package/dist/src/create/create-vitnode.js +142 -9
- package/dist/src/helpers/init-vitnode.js +21 -0
- package/dist/src/helpers/install-dependencies.js +42 -4
- package/dist/src/helpers/is-online.js +1 -1
- package/dist/src/helpers/is-writeable.js +1 -1
- package/dist/src/index.js +4 -1
- package/dist/src/prepare/prepare.js +1 -1
- package/dist/src/questions.js +44 -6
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +7 -7
- package/copy-of-vitnode-app/root/.prettierrc.mjs +0 -11
- package/copy-of-vitnode-app/root/src/app/[locale]/admin/not-found.tsx +0 -5
- package/copy-of-vitnode-app/root/src/app/not-found.tsx +0 -13
- package/copy-of-vitnode-app/root/src/vitnode.api.config.ts +0 -5
- /package/copy-of-vitnode-app/{root → api-single-app}/drizzle.config.ts +0 -0
|
@@ -1,63 +1,254 @@
|
|
|
1
1
|
import { readFile, writeFile } from 'fs/promises';
|
|
2
|
-
import { join } from 'path';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
import { dirname, join } from 'path';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
import { getAvailablePackageManagers } from '../helpers/get-available-package-managers.js';
|
|
5
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
6
|
+
const __dirname = dirname(__filename);
|
|
7
|
+
export const createPackageJSON = async ({ appName, packageManager, root, eslint, docker, mode, monorepo, }) => {
|
|
8
|
+
const availablePackageManagers = await getAvailablePackageManagers();
|
|
9
|
+
const pkg = JSON.parse(await readFile(join(__dirname, '..', '..', '..', 'package.json'), 'utf-8'));
|
|
10
|
+
const pkgVitNodeVersion = `^${pkg.version}`;
|
|
11
|
+
const monorepoStructure = {
|
|
12
|
+
api: join(root, 'apps', 'api'),
|
|
13
|
+
web: join(root, 'apps', 'web'),
|
|
14
|
+
};
|
|
15
|
+
if (mode === 'apiMonorepo' || monorepo) {
|
|
16
|
+
const rootPackageJson = {
|
|
17
|
+
name: appName,
|
|
18
|
+
private: true,
|
|
19
|
+
scripts: {
|
|
20
|
+
'db:migrate': 'turbo db:migrate',
|
|
21
|
+
'db:push': 'turbo db:push',
|
|
22
|
+
init: 'turbo init',
|
|
23
|
+
dev: 'turbo dev',
|
|
24
|
+
build: 'turbo build',
|
|
25
|
+
start: 'turbo start',
|
|
26
|
+
...(eslint
|
|
27
|
+
? {
|
|
28
|
+
lint: 'eslint .',
|
|
29
|
+
'lint:fix': 'eslint . --fix',
|
|
30
|
+
}
|
|
31
|
+
: {}),
|
|
32
|
+
...(docker
|
|
33
|
+
? {
|
|
34
|
+
'docker:dev': `docker compose -f ./docker-compose.yml -p ${appName}-vitnode-dev up -d`,
|
|
35
|
+
}
|
|
36
|
+
: {}),
|
|
37
|
+
},
|
|
38
|
+
devDependencies: {
|
|
39
|
+
'@types/node': '^24',
|
|
40
|
+
'@vitnode/eslint-config': pkgVitNodeVersion,
|
|
41
|
+
...(eslint
|
|
42
|
+
? {
|
|
43
|
+
'prettier-plugin-tailwindcss': '^0.6.14',
|
|
44
|
+
prettier: '^3.6.2',
|
|
45
|
+
}
|
|
46
|
+
: {}),
|
|
47
|
+
turbo: '^2.5.5',
|
|
48
|
+
typescript: '^5.8.3',
|
|
49
|
+
zod: '^4.0.5',
|
|
50
|
+
},
|
|
51
|
+
packageManager: `${packageManager}@${availablePackageManagers[packageManager]}`,
|
|
52
|
+
workspaces: ['apps/*', 'plugins/*'],
|
|
53
|
+
};
|
|
54
|
+
await writeFile(join(root, 'package.json'), JSON.stringify(rootPackageJson, null, 2));
|
|
55
|
+
}
|
|
56
|
+
const apiPackageJson = {
|
|
57
|
+
name: mode === 'apiMonorepo' || monorepo ? 'api' : appName,
|
|
7
58
|
version: '0.1.0',
|
|
8
59
|
private: true,
|
|
9
60
|
type: 'module',
|
|
10
61
|
scripts: {
|
|
11
|
-
'
|
|
12
|
-
'db:
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
62
|
+
'db:push': 'vitnode push',
|
|
63
|
+
'db:migrate': 'vitnode migrate',
|
|
64
|
+
init: 'vitnode init --api',
|
|
65
|
+
...(packageManager === 'bun'
|
|
66
|
+
? {
|
|
67
|
+
dev: 'vitnode init --api && bun run --hot src/index.ts',
|
|
68
|
+
start: 'NODE_ENV=production bun run src/index.ts',
|
|
69
|
+
}
|
|
70
|
+
: {
|
|
71
|
+
dev: 'vitnode init --api && tsx watch src/index.ts',
|
|
72
|
+
build: 'tsc && tsc-alias -p tsconfig.json',
|
|
73
|
+
start: 'node dist/index.js',
|
|
74
|
+
}),
|
|
17
75
|
...(eslint
|
|
18
76
|
? {
|
|
19
77
|
lint: 'eslint .',
|
|
20
78
|
'lint:fix': 'eslint . --fix',
|
|
21
79
|
}
|
|
22
80
|
: {}),
|
|
81
|
+
...(docker && mode === 'onlyApi'
|
|
82
|
+
? {
|
|
83
|
+
'docker:dev': `docker compose -f ./docker-compose.yml -p ${appName}-vitnode-dev up -d`,
|
|
84
|
+
}
|
|
85
|
+
: {}),
|
|
86
|
+
'drizzle-kit': 'drizzle-kit',
|
|
23
87
|
},
|
|
24
88
|
dependencies: {
|
|
25
|
-
'@hono/zod-openapi': '^0.
|
|
26
|
-
'@hono/zod-validator': '^0.7.
|
|
27
|
-
'@
|
|
28
|
-
'@
|
|
29
|
-
'
|
|
30
|
-
'
|
|
31
|
-
|
|
32
|
-
'
|
|
33
|
-
|
|
34
|
-
'
|
|
35
|
-
|
|
36
|
-
'next-intl': '^4.1.0',
|
|
37
|
-
react: '^19.1.0',
|
|
38
|
-
'react-dom': '^19.1.0',
|
|
39
|
-
'react-hook-form': '^7.56.4',
|
|
40
|
-
sonner: '^2.0.3',
|
|
41
|
-
zod: '^3.25.42',
|
|
89
|
+
'@hono/zod-openapi': '^1.0.2',
|
|
90
|
+
'@hono/zod-validator': '^0.7.2',
|
|
91
|
+
'@react-email/components': '^0.3.2',
|
|
92
|
+
'@vitnode/core': pkgVitNodeVersion,
|
|
93
|
+
'drizzle-kit': '^0.31.3',
|
|
94
|
+
'drizzle-orm': '^0.44.3',
|
|
95
|
+
hono: '^4.8.5',
|
|
96
|
+
'next-intl': '^4.3.1',
|
|
97
|
+
react: '^19.1',
|
|
98
|
+
'react-dom': '^19.1',
|
|
99
|
+
zod: '^4.0.5',
|
|
42
100
|
},
|
|
43
101
|
devDependencies: {
|
|
44
|
-
'@
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
102
|
+
'@hono/node-server': '^1.17.1',
|
|
103
|
+
...(packageManager === 'bun'
|
|
104
|
+
? {
|
|
105
|
+
'@types/bun': 'latest',
|
|
106
|
+
}
|
|
107
|
+
: {}),
|
|
108
|
+
'@types/node': '^24',
|
|
109
|
+
'@types/react': '^19.1',
|
|
110
|
+
'@types/react-dom': '^19.1',
|
|
111
|
+
'@vitnode/eslint-config': pkgVitNodeVersion,
|
|
112
|
+
dotenv: '^17.2.0',
|
|
48
113
|
...(eslint
|
|
49
114
|
? {
|
|
50
|
-
eslint: '^9.
|
|
51
|
-
'
|
|
52
|
-
|
|
115
|
+
eslint: '^9.31.0',
|
|
116
|
+
...(mode === 'onlyApi'
|
|
117
|
+
? {
|
|
118
|
+
'prettier-plugin-tailwindcss': '^0.6.14',
|
|
119
|
+
prettier: '^3.6.2',
|
|
120
|
+
}
|
|
121
|
+
: {}),
|
|
53
122
|
}
|
|
54
123
|
: {}),
|
|
55
|
-
'react-email': '^4.
|
|
56
|
-
|
|
57
|
-
|
|
124
|
+
'react-email': '^4.2.3',
|
|
125
|
+
'tsc-alias': '^1.8.16',
|
|
126
|
+
tsx: '^4.20.3',
|
|
58
127
|
typescript: '^5.8.3',
|
|
59
128
|
},
|
|
60
|
-
packageManager,
|
|
61
129
|
};
|
|
62
|
-
|
|
130
|
+
if (mode === 'singleApp') {
|
|
131
|
+
const packageJson = {
|
|
132
|
+
name: monorepo ? 'web' : appName,
|
|
133
|
+
version: '0.1.0',
|
|
134
|
+
private: true,
|
|
135
|
+
type: 'module',
|
|
136
|
+
scripts: {
|
|
137
|
+
'db:push': 'vitnode push',
|
|
138
|
+
'db:migrate': 'vitnode migrate',
|
|
139
|
+
init: 'vitnode init',
|
|
140
|
+
dev: 'vitnode init && next dev --turbopack',
|
|
141
|
+
build: 'next build',
|
|
142
|
+
start: 'next start',
|
|
143
|
+
...(eslint
|
|
144
|
+
? {
|
|
145
|
+
lint: 'eslint .',
|
|
146
|
+
'lint:fix': 'eslint . --fix',
|
|
147
|
+
}
|
|
148
|
+
: {}),
|
|
149
|
+
...(docker
|
|
150
|
+
? {
|
|
151
|
+
'docker:dev': `docker compose -f ./docker-compose.yml -p ${appName}-vitnode-dev up -d`,
|
|
152
|
+
}
|
|
153
|
+
: {}),
|
|
154
|
+
'drizzle-kit': 'drizzle-kit',
|
|
155
|
+
},
|
|
156
|
+
dependencies: {
|
|
157
|
+
'@hono/zod-openapi': '^1.0.2',
|
|
158
|
+
'@hono/zod-validator': '^0.7.2',
|
|
159
|
+
'@hookform/resolvers': '^5.1.1',
|
|
160
|
+
'@react-email/components': '^0.3.2',
|
|
161
|
+
'@vitnode/core': pkgVitNodeVersion,
|
|
162
|
+
'babel-plugin-react-compiler': '19.1.0-rc.2',
|
|
163
|
+
'drizzle-kit': '^0.31.4',
|
|
164
|
+
'drizzle-orm': '^0.44.3',
|
|
165
|
+
hono: '^4.8.5',
|
|
166
|
+
'lucide-react': '^0.525.0',
|
|
167
|
+
next: '^15.4.2',
|
|
168
|
+
'next-intl': '^4.3.4',
|
|
169
|
+
react: '^19.1',
|
|
170
|
+
'react-dom': '^19.1',
|
|
171
|
+
'react-hook-form': '^7.60.0',
|
|
172
|
+
sonner: '^2.0.6',
|
|
173
|
+
zod: '^4.0.5',
|
|
174
|
+
},
|
|
175
|
+
devDependencies: {
|
|
176
|
+
'@tailwindcss/postcss': '^4.1.11',
|
|
177
|
+
'@types/node': '^24',
|
|
178
|
+
'@types/react': '^19.1',
|
|
179
|
+
'@types/react-dom': '^19.1',
|
|
180
|
+
'@vitnode/eslint-config': pkgVitNodeVersion,
|
|
181
|
+
...(eslint
|
|
182
|
+
? {
|
|
183
|
+
eslint: '^9.31.0',
|
|
184
|
+
'prettier-plugin-tailwindcss': '^0.6.14',
|
|
185
|
+
prettier: '^3.6.2',
|
|
186
|
+
}
|
|
187
|
+
: {}),
|
|
188
|
+
'react-email': '^4.2.3',
|
|
189
|
+
turbo: '^2.5.5',
|
|
190
|
+
tailwindcss: '^4.1.11',
|
|
191
|
+
'tw-animate-css': '^1.3.5',
|
|
192
|
+
typescript: '^5.8.3',
|
|
193
|
+
},
|
|
194
|
+
packageManager: `${packageManager}@${availablePackageManagers[packageManager]}`,
|
|
195
|
+
};
|
|
196
|
+
await writeFile(join(monorepo ? monorepoStructure.web : root, 'package.json'), JSON.stringify(packageJson, null, 2));
|
|
197
|
+
}
|
|
198
|
+
else if (mode === 'apiMonorepo') {
|
|
199
|
+
await writeFile(join(root, 'apps', 'api', 'package.json'), JSON.stringify(apiPackageJson, null, 2));
|
|
200
|
+
const webPackageJson = {
|
|
201
|
+
name: 'web',
|
|
202
|
+
version: '0.1.0',
|
|
203
|
+
private: true,
|
|
204
|
+
type: 'module',
|
|
205
|
+
scripts: {
|
|
206
|
+
init: 'vitnode init --web',
|
|
207
|
+
dev: 'vitnode init --web && next dev --turbopack',
|
|
208
|
+
build: 'next build',
|
|
209
|
+
start: 'next start',
|
|
210
|
+
...(eslint
|
|
211
|
+
? {
|
|
212
|
+
lint: 'eslint .',
|
|
213
|
+
'lint:fix': 'eslint . --fix',
|
|
214
|
+
}
|
|
215
|
+
: {}),
|
|
216
|
+
},
|
|
217
|
+
dependencies: {
|
|
218
|
+
'@vitnode/core': pkgVitNodeVersion,
|
|
219
|
+
'babel-plugin-react-compiler': '19.1.0-rc.2',
|
|
220
|
+
'lucide-react': '^0.525.0',
|
|
221
|
+
next: '^15.4.2',
|
|
222
|
+
'next-intl': '^4.3.4',
|
|
223
|
+
react: '^19.1',
|
|
224
|
+
'react-dom': '^19.1',
|
|
225
|
+
'react-hook-form': '^7.60.0',
|
|
226
|
+
sonner: '^2.0.6',
|
|
227
|
+
},
|
|
228
|
+
devDependencies: {
|
|
229
|
+
'@hookform/resolvers': '^5.1.1',
|
|
230
|
+
'@tailwindcss/postcss': '^4.1.11',
|
|
231
|
+
'@types/mdx': '^2.0.13',
|
|
232
|
+
'@types/node': '^24',
|
|
233
|
+
'@types/react': '^19.1',
|
|
234
|
+
'@types/react-dom': '^19.1',
|
|
235
|
+
'@vitnode/eslint-config': pkgVitNodeVersion,
|
|
236
|
+
'class-variance-authority': '^0.7.1',
|
|
237
|
+
...(eslint
|
|
238
|
+
? {
|
|
239
|
+
eslint: '^9.31.0',
|
|
240
|
+
}
|
|
241
|
+
: {}),
|
|
242
|
+
postcss: '^8.5.6',
|
|
243
|
+
tailwindcss: '^4.1.11',
|
|
244
|
+
'tw-animate-css': '^1.3.5',
|
|
245
|
+
typescript: '^5.8.3',
|
|
246
|
+
zod: '^4.0.5',
|
|
247
|
+
},
|
|
248
|
+
};
|
|
249
|
+
await writeFile(join(root, 'apps', 'web', 'package.json'), JSON.stringify(webPackageJson, null, 2));
|
|
250
|
+
}
|
|
251
|
+
else if (mode === 'onlyApi') {
|
|
252
|
+
await writeFile(join(monorepo ? monorepoStructure.api : root, 'package.json'), JSON.stringify(apiPackageJson, null, 2));
|
|
253
|
+
}
|
|
63
254
|
};
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { randomBytes } from 'crypto';
|
|
2
1
|
import { existsSync } from 'fs';
|
|
3
|
-
import { copyFile, cp, mkdir, readFile, writeFile } from 'fs/promises';
|
|
2
|
+
import { copyFile, cp, mkdir, readFile, rename, writeFile } from 'fs/promises';
|
|
4
3
|
import ora from 'ora';
|
|
5
4
|
import { dirname, join } from 'path';
|
|
6
5
|
import color from 'picocolors';
|
|
7
6
|
import { fileURLToPath } from 'url';
|
|
7
|
+
import { generateMigrationsVitnode, initFilesVitnode, } from '../helpers/init-vitnode.js';
|
|
8
8
|
import { installDependencies } from '../helpers/install-dependencies.js';
|
|
9
9
|
import { isFolderEmpty } from '../helpers/is-folder-empty.js';
|
|
10
10
|
import { createPackageJSON } from './create-package-json.js';
|
|
11
|
-
export const createVitNode = async ({ root, appName, packageManager, eslint, install, }) => {
|
|
11
|
+
export const createVitNode = async ({ root, appName, packageManager, eslint, install, docker, mode, monorepo, }) => {
|
|
12
12
|
const spinner = ora(`Creating a new VitNode app in ${color.green(root)}. Using ${color.green(packageManager)}...`).start();
|
|
13
13
|
const __filename = fileURLToPath(import.meta.url);
|
|
14
14
|
const __dirname = dirname(__filename);
|
|
@@ -21,32 +21,165 @@ export const createVitNode = async ({ root, appName, packageManager, eslint, ins
|
|
|
21
21
|
if (!isFolderEmpty(root, appName)) {
|
|
22
22
|
process.exit(1);
|
|
23
23
|
}
|
|
24
|
+
const monorepoStructure = {
|
|
25
|
+
api: join(root, 'apps', 'api'),
|
|
26
|
+
web: join(root, 'apps', 'web'),
|
|
27
|
+
};
|
|
28
|
+
spinner.text = 'Preparing the project structure...';
|
|
29
|
+
if (monorepo || mode === 'apiMonorepo') {
|
|
30
|
+
const dirsToCreate = [];
|
|
31
|
+
if (mode === 'apiMonorepo' || (monorepo && mode === 'onlyApi')) {
|
|
32
|
+
dirsToCreate.push(monorepoStructure.api);
|
|
33
|
+
}
|
|
34
|
+
if (mode === 'apiMonorepo' || (monorepo && mode === 'singleApp')) {
|
|
35
|
+
dirsToCreate.push(monorepoStructure.web);
|
|
36
|
+
}
|
|
37
|
+
await Promise.all(dirsToCreate.map(async (dir) => mkdir(dir, { recursive: true })));
|
|
38
|
+
}
|
|
24
39
|
spinner.text = 'Copying files...';
|
|
25
|
-
await cp(join(templatePath, '
|
|
40
|
+
await cp(join(templatePath, '.vscode'), join(root, '.vscode'), {
|
|
26
41
|
recursive: true,
|
|
27
42
|
});
|
|
43
|
+
if (mode === 'singleApp') {
|
|
44
|
+
await Promise.all([
|
|
45
|
+
cp(join(templatePath, 'root'), monorepo ? monorepoStructure.web : root, {
|
|
46
|
+
recursive: true,
|
|
47
|
+
}),
|
|
48
|
+
cp(join(templatePath, 'api-single-app'), monorepo ? monorepoStructure.web : root, {
|
|
49
|
+
recursive: true,
|
|
50
|
+
}),
|
|
51
|
+
]);
|
|
52
|
+
}
|
|
53
|
+
else if (mode === 'apiMonorepo') {
|
|
54
|
+
await Promise.all([
|
|
55
|
+
cp(join(templatePath, 'root'), monorepoStructure.web, {
|
|
56
|
+
recursive: true,
|
|
57
|
+
}),
|
|
58
|
+
cp(join(templatePath, 'api'), monorepoStructure.api, {
|
|
59
|
+
recursive: true,
|
|
60
|
+
}),
|
|
61
|
+
]);
|
|
62
|
+
if (packageManager === 'bun') {
|
|
63
|
+
await cp(join(templatePath, 'api-bun'), monorepoStructure.api, {
|
|
64
|
+
recursive: true,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
else if (mode === 'onlyApi') {
|
|
69
|
+
await cp(join(templatePath, 'api'), monorepo ? monorepoStructure.api : root, {
|
|
70
|
+
recursive: true,
|
|
71
|
+
});
|
|
72
|
+
if (packageManager === 'bun') {
|
|
73
|
+
await cp(join(templatePath, 'api-bun'), monorepo ? monorepoStructure.api : root, {
|
|
74
|
+
recursive: true,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (mode === 'apiMonorepo' || monorepo) {
|
|
79
|
+
await cp(join(templatePath, 'monorepo'), root, {
|
|
80
|
+
recursive: true,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
28
83
|
if (eslint) {
|
|
29
84
|
spinner.text = 'Copying eslint files...';
|
|
30
85
|
await cp(join(templatePath, 'eslint'), root, {
|
|
31
86
|
recursive: true,
|
|
32
87
|
});
|
|
33
88
|
}
|
|
89
|
+
spinner.text = 'Renaming special files...';
|
|
90
|
+
await rename(join(root, '.gitignore_template'), join(root, '.gitignore'));
|
|
91
|
+
if (mode === 'apiMonorepo' || monorepo) {
|
|
92
|
+
if (existsSync(join(monorepoStructure.api, '.gitignore_template'))) {
|
|
93
|
+
await rename(join(monorepoStructure.api, '.gitignore_template'), join(monorepoStructure.api, '.gitignore'));
|
|
94
|
+
}
|
|
95
|
+
if (existsSync(join(monorepoStructure.web, '.gitignore_template'))) {
|
|
96
|
+
await rename(join(monorepoStructure.web, '.gitignore_template'), join(monorepoStructure.web, '.gitignore'));
|
|
97
|
+
}
|
|
98
|
+
}
|
|
34
99
|
spinner.text = 'Creating package.json...';
|
|
35
100
|
await createPackageJSON({
|
|
36
101
|
root,
|
|
37
102
|
appName,
|
|
38
103
|
packageManager,
|
|
39
104
|
eslint,
|
|
105
|
+
docker,
|
|
106
|
+
mode,
|
|
107
|
+
monorepo,
|
|
40
108
|
});
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
109
|
+
if ((mode === 'apiMonorepo' || monorepo) && packageManager === 'pnpm') {
|
|
110
|
+
spinner.text = 'Creating pnpm-workspace.yaml...';
|
|
111
|
+
const pnpmWorkspaceContent = `packages:\n - 'apps/*'\n - 'plugins/*'\n`;
|
|
112
|
+
await writeFile(join(root, 'pnpm-workspace.yaml'), pnpmWorkspaceContent);
|
|
113
|
+
}
|
|
114
|
+
if (docker) {
|
|
115
|
+
spinner.text = 'Copying docker files...';
|
|
116
|
+
await copyFile(join(templatePath, 'docker', 'docker-compose.yml'), join(root, 'docker-compose.yml'));
|
|
117
|
+
const dockerComposePath = join(root, 'docker-compose.yml');
|
|
118
|
+
const dockerComposeContent = await readFile(dockerComposePath, 'utf-8');
|
|
119
|
+
const updatedContent = dockerComposeContent.replace(/vitnode_postgres_dev/g, `${appName}_vitnode_postgres_dev`);
|
|
120
|
+
await writeFile(dockerComposePath, updatedContent);
|
|
121
|
+
}
|
|
122
|
+
spinner.text = 'Updating VitNode paths...';
|
|
123
|
+
if ((mode === 'apiMonorepo' || monorepo) &&
|
|
124
|
+
packageManager !== 'pnpm' &&
|
|
125
|
+
mode !== 'onlyApi') {
|
|
126
|
+
const globalCssPath = join(monorepoStructure.web, 'src', 'app', 'global.css');
|
|
127
|
+
const globalCssContent = await readFile(globalCssPath, 'utf-8');
|
|
128
|
+
const updatedGlobalCssContent = globalCssContent.replaceAll('@source "../../node_modules/@vitnode/', '@source "../../../../node_modules/@vitnode/');
|
|
129
|
+
await writeFile(globalCssPath, updatedGlobalCssContent);
|
|
130
|
+
}
|
|
131
|
+
if (mode === 'apiMonorepo') {
|
|
132
|
+
spinner.text = 'Setting up environment variables...';
|
|
133
|
+
const envExamplePath = join(monorepoStructure.web, '.env.example');
|
|
134
|
+
if (existsSync(envExamplePath)) {
|
|
135
|
+
await rename(envExamplePath, join(monorepoStructure.web, '.env'));
|
|
136
|
+
}
|
|
137
|
+
}
|
|
46
138
|
if (install) {
|
|
47
139
|
spinner.text = 'Installing dependencies...';
|
|
48
140
|
await installDependencies({
|
|
49
141
|
packageManager,
|
|
142
|
+
cwd: root,
|
|
143
|
+
});
|
|
144
|
+
spinner.text = 'Initializing VitNode files...';
|
|
145
|
+
if (mode === 'apiMonorepo') {
|
|
146
|
+
await Promise.all([
|
|
147
|
+
initFilesVitnode({
|
|
148
|
+
packageManager,
|
|
149
|
+
cwd: monorepoStructure.web,
|
|
150
|
+
flag: 'web',
|
|
151
|
+
}),
|
|
152
|
+
initFilesVitnode({
|
|
153
|
+
packageManager,
|
|
154
|
+
cwd: monorepoStructure.api,
|
|
155
|
+
flag: 'api',
|
|
156
|
+
}),
|
|
157
|
+
initFilesVitnode({
|
|
158
|
+
packageManager,
|
|
159
|
+
cwd: root,
|
|
160
|
+
}),
|
|
161
|
+
]);
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
initFilesVitnode({
|
|
165
|
+
packageManager,
|
|
166
|
+
cwd: root,
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
spinner.text = 'Generating migrations...';
|
|
170
|
+
let migrationsCwd;
|
|
171
|
+
if (mode === 'apiMonorepo' || (monorepo && mode !== 'singleApp')) {
|
|
172
|
+
migrationsCwd = monorepoStructure.api;
|
|
173
|
+
}
|
|
174
|
+
else if (mode === 'singleApp' && monorepo) {
|
|
175
|
+
migrationsCwd = monorepoStructure.web;
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
migrationsCwd = root;
|
|
179
|
+
}
|
|
180
|
+
generateMigrationsVitnode({
|
|
181
|
+
packageManager,
|
|
182
|
+
cwd: migrationsCwd,
|
|
50
183
|
});
|
|
51
184
|
}
|
|
52
185
|
spinner.succeed(`${color.green('Success!')} Created ${color.cyan(appName)} at ${color.cyan(root)}`);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { spawn } from 'child_process';
|
|
2
|
+
export const initFilesVitnode = ({ packageManager: pm, cwd, flag, }) => {
|
|
3
|
+
const packageManager = pm.split('@')[0];
|
|
4
|
+
const args = [
|
|
5
|
+
'vitnode',
|
|
6
|
+
'prepare-plugins',
|
|
7
|
+
flag ? `--${flag}` : '',
|
|
8
|
+
];
|
|
9
|
+
spawn(packageManager, args, {
|
|
10
|
+
cwd,
|
|
11
|
+
shell: true,
|
|
12
|
+
});
|
|
13
|
+
};
|
|
14
|
+
export const generateMigrationsVitnode = ({ packageManager: pm, cwd, }) => {
|
|
15
|
+
const packageManager = pm.split('@')[0];
|
|
16
|
+
const args = ['vitnode', 'migrate', '--generate'];
|
|
17
|
+
spawn(packageManager, args, {
|
|
18
|
+
cwd,
|
|
19
|
+
shell: true,
|
|
20
|
+
});
|
|
21
|
+
};
|
|
@@ -1,17 +1,21 @@
|
|
|
1
1
|
import { spawn } from 'child_process';
|
|
2
2
|
import color from 'picocolors';
|
|
3
3
|
import { getOnline } from './is-online.js';
|
|
4
|
-
export const installDependencies = async ({ packageManager: pm, }) => {
|
|
4
|
+
export const installDependencies = async ({ packageManager: pm, cwd, }) => {
|
|
5
5
|
const packageManager = pm.split('@')[0];
|
|
6
6
|
const isOnline = await getOnline();
|
|
7
|
-
const args =
|
|
7
|
+
const args = ['install'];
|
|
8
8
|
if (!isOnline) {
|
|
9
9
|
console.log(color.yellow('You appear to be offline.\nFalling back to the local cache.'));
|
|
10
10
|
args.push('--offline');
|
|
11
11
|
}
|
|
12
12
|
return new Promise((resolve, reject) => {
|
|
13
|
+
let stdout = '';
|
|
14
|
+
let stderr = '';
|
|
13
15
|
const child = spawn(packageManager, args, {
|
|
14
|
-
stdio: '
|
|
16
|
+
stdio: 'pipe',
|
|
17
|
+
cwd,
|
|
18
|
+
shell: true,
|
|
15
19
|
env: {
|
|
16
20
|
...process.env,
|
|
17
21
|
ADBLOCK: '1',
|
|
@@ -19,12 +23,46 @@ export const installDependencies = async ({ packageManager: pm, }) => {
|
|
|
19
23
|
DISABLE_OPENCOLLECTIVE: '1',
|
|
20
24
|
},
|
|
21
25
|
});
|
|
26
|
+
child.stdout?.on('data', (data) => {
|
|
27
|
+
const output = data.toString();
|
|
28
|
+
stdout += output;
|
|
29
|
+
});
|
|
30
|
+
child.stderr?.on('data', (data) => {
|
|
31
|
+
const output = data.toString();
|
|
32
|
+
stderr += output;
|
|
33
|
+
});
|
|
22
34
|
child.on('close', code => {
|
|
23
35
|
if (code !== 0) {
|
|
24
|
-
|
|
36
|
+
console.error(color.red(`\n❌ Installation failed with exit code: ${code}`));
|
|
37
|
+
if (stderr) {
|
|
38
|
+
console.error(color.red('Error output:'));
|
|
39
|
+
console.error(stderr);
|
|
40
|
+
}
|
|
41
|
+
if (stdout) {
|
|
42
|
+
console.log(color.yellow('Standard output:'));
|
|
43
|
+
console.log(stdout);
|
|
44
|
+
}
|
|
45
|
+
if (stderr.includes('ENOTFOUND') || stderr.includes('network')) {
|
|
46
|
+
console.error(color.yellow('💡 Network error detected. Please check your internet connection.'));
|
|
47
|
+
}
|
|
48
|
+
else if (stderr.includes('EACCES') ||
|
|
49
|
+
stderr.includes('permission denied')) {
|
|
50
|
+
console.error(color.yellow('💡 Permission error detected. Try running with elevated privileges or check file permissions.'));
|
|
51
|
+
}
|
|
52
|
+
else if (stderr.includes('ENOSPC')) {
|
|
53
|
+
console.error(color.yellow('💡 Disk space error detected. Please free up some disk space.'));
|
|
54
|
+
}
|
|
55
|
+
else if (stderr.includes('ERR_PNPM_PEER_DEP_ISSUES')) {
|
|
56
|
+
console.error(color.yellow('💡 Peer dependency issues detected. Consider using --force flag or resolve conflicts manually.'));
|
|
57
|
+
}
|
|
58
|
+
reject(new Error(`Failed to install dependencies using ${packageManager}. Exit code: ${code}\n${stderr || stdout}`));
|
|
25
59
|
return;
|
|
26
60
|
}
|
|
27
61
|
resolve();
|
|
28
62
|
});
|
|
63
|
+
child.on('error', error => {
|
|
64
|
+
console.error(color.red(`❌ Failed to start ${packageManager}:`), error.message);
|
|
65
|
+
reject(new Error(`Failed to start ${packageManager}: ${error.message}`));
|
|
66
|
+
});
|
|
29
67
|
});
|
|
30
68
|
};
|
package/dist/src/index.js
CHANGED
|
@@ -26,7 +26,7 @@ process.on('uncaughtException', (error) => {
|
|
|
26
26
|
const init = async () => {
|
|
27
27
|
let projectPath = '';
|
|
28
28
|
const program = new Command()
|
|
29
|
-
.version(packageJson.version)
|
|
29
|
+
.version(packageJson.version ?? '0.1.0')
|
|
30
30
|
.argument('[project-directory]')
|
|
31
31
|
.usage(`${color.green('[project-directory]')} [options]`)
|
|
32
32
|
.action(name => {
|
|
@@ -36,6 +36,9 @@ const init = async () => {
|
|
|
36
36
|
program.option('--eslint', 'Initialize with eslint config.');
|
|
37
37
|
program.option('--skip-install', 'Skip installing packages after initializing the project.');
|
|
38
38
|
program.option('--plugin', 'Enable plugin mode.');
|
|
39
|
+
program.addOption(new Option('--mode <mode>', 'What type of app do you want to create?').choices(['singleApp', 'apiMonorepo', 'onlyApi']));
|
|
40
|
+
program.option('--monorepo', 'Create project with monorepo structure.');
|
|
41
|
+
program.option('--docker', 'Initialize with Docker support.');
|
|
39
42
|
program.parse(process.argv);
|
|
40
43
|
const opts = program.opts();
|
|
41
44
|
if (opts.plugin) {
|
|
@@ -6,7 +6,7 @@ const prepare = async () => {
|
|
|
6
6
|
if (!existsSync(toRootPath)) {
|
|
7
7
|
await mkdir(toRootPath);
|
|
8
8
|
}
|
|
9
|
-
const fromRootPath = join(process.cwd(), '..', '..', 'apps', '
|
|
9
|
+
const fromRootPath = join(process.cwd(), '..', '..', 'apps', 'docs');
|
|
10
10
|
if (!existsSync(fromRootPath)) {
|
|
11
11
|
console.error(`\x1b[31mThe path ${fromRootPath} does not exist. Please check the directory structure.\x1b[0m`);
|
|
12
12
|
process.exit(1);
|