create-blitzpack 0.1.5 → 0.1.7
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/dist/index.js +279 -54
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -7,18 +7,122 @@ import { dirname, join } from "path";
|
|
|
7
7
|
import { fileURLToPath } from "url";
|
|
8
8
|
|
|
9
9
|
// src/commands/create.ts
|
|
10
|
-
import
|
|
10
|
+
import chalk4 from "chalk";
|
|
11
11
|
import { spawn } from "child_process";
|
|
12
12
|
import fs3 from "fs-extra";
|
|
13
13
|
import ora from "ora";
|
|
14
14
|
import path4 from "path";
|
|
15
15
|
import prompts2 from "prompts";
|
|
16
16
|
|
|
17
|
-
// src/
|
|
17
|
+
// src/checks.ts
|
|
18
|
+
import chalk from "chalk";
|
|
18
19
|
import { execSync } from "child_process";
|
|
20
|
+
function checkNodeVersion() {
|
|
21
|
+
try {
|
|
22
|
+
const nodeVersion = process.version;
|
|
23
|
+
const majorVersion = parseInt(nodeVersion.slice(1).split(".")[0], 10);
|
|
24
|
+
if (majorVersion >= 20) {
|
|
25
|
+
return {
|
|
26
|
+
passed: true,
|
|
27
|
+
name: "Node.js"
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
return {
|
|
31
|
+
passed: false,
|
|
32
|
+
name: "Node.js",
|
|
33
|
+
message: `Node.js >= 20.0.0 required (found ${nodeVersion})`
|
|
34
|
+
};
|
|
35
|
+
} catch {
|
|
36
|
+
return {
|
|
37
|
+
passed: false,
|
|
38
|
+
name: "Node.js",
|
|
39
|
+
message: "Failed to check Node.js version"
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function checkPnpmInstalled() {
|
|
44
|
+
try {
|
|
45
|
+
execSync("pnpm --version", { stdio: "ignore" });
|
|
46
|
+
return {
|
|
47
|
+
passed: true,
|
|
48
|
+
name: "pnpm"
|
|
49
|
+
};
|
|
50
|
+
} catch {
|
|
51
|
+
return {
|
|
52
|
+
passed: false,
|
|
53
|
+
name: "pnpm",
|
|
54
|
+
message: "pnpm not found. Install: npm install -g pnpm"
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
async function runPreflightChecks() {
|
|
59
|
+
console.log();
|
|
60
|
+
console.log(chalk.bold(" Checking requirements..."));
|
|
61
|
+
console.log();
|
|
62
|
+
const checks = [checkNodeVersion(), checkPnpmInstalled()];
|
|
63
|
+
let hasErrors = false;
|
|
64
|
+
for (const check of checks) {
|
|
65
|
+
if (check.passed) {
|
|
66
|
+
console.log(chalk.green(" \u2714"), check.name);
|
|
67
|
+
} else {
|
|
68
|
+
hasErrors = true;
|
|
69
|
+
console.log(chalk.red(" \u2716"), check.name);
|
|
70
|
+
if (check.message) {
|
|
71
|
+
console.log(chalk.dim(` ${check.message}`));
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
console.log();
|
|
76
|
+
if (hasErrors) {
|
|
77
|
+
console.log(
|
|
78
|
+
chalk.red(" \u2716"),
|
|
79
|
+
"Requirements not met. Please fix the errors above."
|
|
80
|
+
);
|
|
81
|
+
console.log();
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// src/docker.ts
|
|
88
|
+
import { execSync as execSync2 } from "child_process";
|
|
89
|
+
function isDockerRunning() {
|
|
90
|
+
try {
|
|
91
|
+
execSync2("docker info", { stdio: "ignore", timeout: 3e3 });
|
|
92
|
+
return true;
|
|
93
|
+
} catch {
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
function runDockerCompose(targetDir) {
|
|
98
|
+
try {
|
|
99
|
+
execSync2("docker compose up -d", {
|
|
100
|
+
cwd: targetDir,
|
|
101
|
+
stdio: "inherit"
|
|
102
|
+
});
|
|
103
|
+
return true;
|
|
104
|
+
} catch {
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
function runDatabaseMigrations(targetDir) {
|
|
109
|
+
try {
|
|
110
|
+
const isWindows = process.platform === "win32";
|
|
111
|
+
execSync2(isWindows ? "pnpm.cmd db:migrate" : "pnpm db:migrate", {
|
|
112
|
+
cwd: targetDir,
|
|
113
|
+
stdio: "inherit"
|
|
114
|
+
});
|
|
115
|
+
return true;
|
|
116
|
+
} catch {
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// src/git.ts
|
|
122
|
+
import { execSync as execSync3 } from "child_process";
|
|
19
123
|
function isGitInstalled() {
|
|
20
124
|
try {
|
|
21
|
-
|
|
125
|
+
execSync3("git --version", { stdio: "ignore" });
|
|
22
126
|
return true;
|
|
23
127
|
} catch {
|
|
24
128
|
return false;
|
|
@@ -26,9 +130,9 @@ function isGitInstalled() {
|
|
|
26
130
|
}
|
|
27
131
|
function initGit(targetDir) {
|
|
28
132
|
try {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
133
|
+
execSync3("git init", { cwd: targetDir, stdio: "ignore" });
|
|
134
|
+
execSync3("git add -A", { cwd: targetDir, stdio: "ignore" });
|
|
135
|
+
execSync3('git commit -m "Initial commit from create-blitzpack"', {
|
|
32
136
|
cwd: targetDir,
|
|
33
137
|
stdio: "ignore"
|
|
34
138
|
});
|
|
@@ -39,6 +143,7 @@ function initGit(targetDir) {
|
|
|
39
143
|
}
|
|
40
144
|
|
|
41
145
|
// src/prompts.ts
|
|
146
|
+
import chalk3 from "chalk";
|
|
42
147
|
import prompts from "prompts";
|
|
43
148
|
|
|
44
149
|
// src/constants.ts
|
|
@@ -52,7 +157,7 @@ var REPLACEABLE_FILES = [
|
|
|
52
157
|
var DEFAULT_DESCRIPTION = "A full-stack TypeScript monorepo built with Blitzpack";
|
|
53
158
|
|
|
54
159
|
// src/utils.ts
|
|
55
|
-
import
|
|
160
|
+
import chalk2 from "chalk";
|
|
56
161
|
import path from "path";
|
|
57
162
|
import validatePackageName from "validate-npm-package-name";
|
|
58
163
|
function getCurrentDirName() {
|
|
@@ -74,51 +179,95 @@ function validateProjectName(name) {
|
|
|
74
179
|
}
|
|
75
180
|
function printHeader() {
|
|
76
181
|
console.log();
|
|
77
|
-
console.log(
|
|
78
|
-
console.log(
|
|
182
|
+
console.log(chalk2.bold.cyan(" Create Blitzpack"));
|
|
183
|
+
console.log(chalk2.dim(" Full-stack TypeScript monorepo"));
|
|
79
184
|
console.log();
|
|
80
185
|
}
|
|
81
|
-
function printSuccess(projectName, targetDir) {
|
|
82
|
-
console.log();
|
|
83
|
-
console.log(chalk.green("\u2714"), chalk.bold(`Created ${projectName}`));
|
|
186
|
+
function printSuccess(projectName, targetDir, ranAutomaticSetup = false) {
|
|
84
187
|
console.log();
|
|
85
|
-
console.log(
|
|
188
|
+
console.log(chalk2.green("\u2714"), chalk2.bold(`Created ${projectName}`));
|
|
86
189
|
console.log();
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
190
|
+
if (ranAutomaticSetup) {
|
|
191
|
+
console.log(
|
|
192
|
+
chalk2.green("\u2714"),
|
|
193
|
+
chalk2.dim("Database setup complete! Ready to start developing.")
|
|
194
|
+
);
|
|
195
|
+
console.log();
|
|
196
|
+
console.log(chalk2.bold(" Next steps:"));
|
|
197
|
+
console.log();
|
|
198
|
+
let stepNumber = 1;
|
|
199
|
+
if (targetDir !== ".") {
|
|
200
|
+
console.log(
|
|
201
|
+
chalk2.cyan(` ${stepNumber}.`),
|
|
202
|
+
chalk2.bold(`cd ${targetDir}`)
|
|
203
|
+
);
|
|
204
|
+
stepNumber++;
|
|
205
|
+
}
|
|
206
|
+
console.log(chalk2.cyan(` ${stepNumber}.`), chalk2.bold("pnpm dev"));
|
|
207
|
+
console.log(chalk2.dim(" Start development servers (web + api)"));
|
|
208
|
+
console.log();
|
|
209
|
+
console.log(chalk2.dim(" Optional commands:"));
|
|
210
|
+
console.log(
|
|
211
|
+
chalk2.dim(
|
|
212
|
+
" \u2022 pnpm db:seed Add test data (admin accounts, users)"
|
|
213
|
+
)
|
|
214
|
+
);
|
|
215
|
+
console.log(
|
|
216
|
+
chalk2.dim(" \u2022 pnpm db:studio Open Prisma Studio to view data")
|
|
217
|
+
);
|
|
218
|
+
} else {
|
|
219
|
+
console.log(
|
|
220
|
+
chalk2.dim(" Setup complete! Follow these steps to start developing:")
|
|
221
|
+
);
|
|
222
|
+
console.log();
|
|
223
|
+
let stepNumber = 1;
|
|
224
|
+
if (targetDir !== ".") {
|
|
225
|
+
console.log(
|
|
226
|
+
chalk2.cyan(` ${stepNumber}.`),
|
|
227
|
+
chalk2.bold(`cd ${targetDir}`)
|
|
228
|
+
);
|
|
229
|
+
stepNumber++;
|
|
230
|
+
}
|
|
231
|
+
console.log(
|
|
232
|
+
chalk2.cyan(` ${stepNumber}.`),
|
|
233
|
+
chalk2.bold("docker compose up -d")
|
|
234
|
+
);
|
|
235
|
+
console.log(chalk2.dim(" Start PostgreSQL database (requires Docker)"));
|
|
236
|
+
console.log();
|
|
237
|
+
stepNumber++;
|
|
238
|
+
console.log(chalk2.cyan(` ${stepNumber}.`), chalk2.bold("pnpm db:migrate"));
|
|
239
|
+
console.log(chalk2.dim(" Run database migrations and setup schema"));
|
|
240
|
+
console.log();
|
|
90
241
|
stepNumber++;
|
|
242
|
+
console.log(chalk2.cyan(` ${stepNumber}.`), chalk2.bold("pnpm dev"));
|
|
243
|
+
console.log(chalk2.dim(" Start development servers (web + api)"));
|
|
244
|
+
console.log();
|
|
245
|
+
console.log(chalk2.dim(" Optional commands:"));
|
|
246
|
+
console.log(
|
|
247
|
+
chalk2.dim(
|
|
248
|
+
" \u2022 pnpm db:seed Add test data (admin accounts, users)"
|
|
249
|
+
)
|
|
250
|
+
);
|
|
251
|
+
console.log(
|
|
252
|
+
chalk2.dim(" \u2022 pnpm db:studio Open Prisma Studio to view data")
|
|
253
|
+
);
|
|
91
254
|
}
|
|
255
|
+
console.log();
|
|
256
|
+
console.log(chalk2.bold(" Your app will be running at:"));
|
|
92
257
|
console.log(
|
|
93
|
-
|
|
94
|
-
"docker compose up -d",
|
|
95
|
-
chalk.dim(" # Start PostgreSQL")
|
|
96
|
-
);
|
|
97
|
-
stepNumber++;
|
|
98
|
-
console.log(
|
|
99
|
-
chalk.cyan(` ${stepNumber}.`),
|
|
100
|
-
"pnpm db:migrate",
|
|
101
|
-
chalk.dim(" # Run database migrations")
|
|
258
|
+
chalk2.dim(" \u2022 Web: ") + chalk2.cyan("http://localhost:3000")
|
|
102
259
|
);
|
|
103
|
-
stepNumber++;
|
|
104
260
|
console.log(
|
|
105
|
-
|
|
106
|
-
"pnpm dev",
|
|
107
|
-
chalk.dim(" # Start dev servers")
|
|
261
|
+
chalk2.dim(" \u2022 API: ") + chalk2.cyan("http://localhost:8080/api")
|
|
108
262
|
);
|
|
109
|
-
console.log();
|
|
110
|
-
console.log(
|
|
111
|
-
chalk.dim(" Optional: pnpm db:seed to add test data like admin accounts")
|
|
112
|
-
);
|
|
113
|
-
console.log();
|
|
114
263
|
console.log(
|
|
115
|
-
|
|
264
|
+
chalk2.dim(" \u2022 API Docs: ") + chalk2.cyan("http://localhost:8080/docs")
|
|
116
265
|
);
|
|
117
266
|
console.log();
|
|
118
267
|
}
|
|
119
268
|
function printError(message) {
|
|
120
269
|
console.log();
|
|
121
|
-
console.log(
|
|
270
|
+
console.log(chalk2.red("\u2716"), message);
|
|
122
271
|
console.log();
|
|
123
272
|
}
|
|
124
273
|
|
|
@@ -172,6 +321,29 @@ async function getProjectOptions(providedName, flags = {}) {
|
|
|
172
321
|
useCurrentDir
|
|
173
322
|
};
|
|
174
323
|
}
|
|
324
|
+
async function promptAutomaticSetup() {
|
|
325
|
+
const dockerRunning = isDockerRunning();
|
|
326
|
+
if (!dockerRunning) {
|
|
327
|
+
console.log();
|
|
328
|
+
console.log(
|
|
329
|
+
chalk3.yellow(" \u26A0"),
|
|
330
|
+
"Docker is not running. Skipping automatic setup."
|
|
331
|
+
);
|
|
332
|
+
console.log(
|
|
333
|
+
chalk3.dim(" Start Docker and run setup steps manually (see below).")
|
|
334
|
+
);
|
|
335
|
+
console.log();
|
|
336
|
+
return false;
|
|
337
|
+
}
|
|
338
|
+
console.log();
|
|
339
|
+
const { runSetup } = await prompts({
|
|
340
|
+
type: "confirm",
|
|
341
|
+
name: "runSetup",
|
|
342
|
+
message: "Run initial setup now? (docker compose + database migrations)",
|
|
343
|
+
initial: true
|
|
344
|
+
});
|
|
345
|
+
return runSetup || false;
|
|
346
|
+
}
|
|
175
347
|
|
|
176
348
|
// src/template.ts
|
|
177
349
|
import fs from "fs-extra";
|
|
@@ -180,9 +352,10 @@ import path2 from "path";
|
|
|
180
352
|
var GITHUB_REPO = "github:CarboxyDev/blitzpack";
|
|
181
353
|
var POST_DOWNLOAD_EXCLUDES = [
|
|
182
354
|
"create-blitzpack",
|
|
183
|
-
"scripts/setup.js",
|
|
184
355
|
".github",
|
|
185
|
-
"apps/marketing"
|
|
356
|
+
"apps/marketing",
|
|
357
|
+
"Dockerfile",
|
|
358
|
+
"docker-compose.prod.yml"
|
|
186
359
|
];
|
|
187
360
|
async function cleanupExcludes(targetDir) {
|
|
188
361
|
for (const exclude of POST_DOWNLOAD_EXCLUDES) {
|
|
@@ -192,12 +365,36 @@ async function cleanupExcludes(targetDir) {
|
|
|
192
365
|
}
|
|
193
366
|
}
|
|
194
367
|
}
|
|
195
|
-
async function downloadAndPrepareTemplate(targetDir) {
|
|
368
|
+
async function downloadAndPrepareTemplate(targetDir, spinner) {
|
|
369
|
+
spinner.text = "Fetching template from GitHub...";
|
|
196
370
|
await downloadTemplate(GITHUB_REPO, {
|
|
197
371
|
dir: targetDir,
|
|
198
372
|
force: true
|
|
199
373
|
});
|
|
374
|
+
spinner.text = "Extracting files...";
|
|
375
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
376
|
+
spinner.text = "Cleaning up template files...";
|
|
200
377
|
await cleanupExcludes(targetDir);
|
|
378
|
+
const files = await countFiles(targetDir);
|
|
379
|
+
spinner.succeed(`Downloaded template (${files} files)`);
|
|
380
|
+
}
|
|
381
|
+
async function countFiles(dir) {
|
|
382
|
+
try {
|
|
383
|
+
let count = 0;
|
|
384
|
+
const items = await fs.readdir(dir);
|
|
385
|
+
for (const item of items) {
|
|
386
|
+
const fullPath = path2.join(dir, item);
|
|
387
|
+
const stat = await fs.stat(fullPath);
|
|
388
|
+
if (stat.isDirectory()) {
|
|
389
|
+
count += await countFiles(fullPath);
|
|
390
|
+
} else {
|
|
391
|
+
count++;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
return count;
|
|
395
|
+
} catch {
|
|
396
|
+
return 0;
|
|
397
|
+
}
|
|
201
398
|
}
|
|
202
399
|
|
|
203
400
|
// src/transform.ts
|
|
@@ -329,32 +526,36 @@ function runInstall(cwd) {
|
|
|
329
526
|
});
|
|
330
527
|
}
|
|
331
528
|
function printDryRun(options) {
|
|
332
|
-
console.log(
|
|
529
|
+
console.log(chalk4.yellow(" Dry run mode - no changes will be made"));
|
|
333
530
|
console.log();
|
|
334
|
-
console.log(
|
|
531
|
+
console.log(chalk4.bold(" Would create:"));
|
|
335
532
|
console.log();
|
|
336
|
-
console.log(` ${
|
|
337
|
-
console.log(` ${
|
|
338
|
-
console.log(` ${
|
|
533
|
+
console.log(` ${chalk4.cyan("Directory:")} ${options.targetDir}`);
|
|
534
|
+
console.log(` ${chalk4.cyan("Name:")} ${options.projectName}`);
|
|
535
|
+
console.log(` ${chalk4.cyan("Slug:")} ${options.projectSlug}`);
|
|
339
536
|
console.log(
|
|
340
|
-
` ${
|
|
537
|
+
` ${chalk4.cyan("Description:")} ${options.projectDescription}`
|
|
341
538
|
);
|
|
342
539
|
console.log();
|
|
343
|
-
console.log(
|
|
540
|
+
console.log(chalk4.bold(" Would run:"));
|
|
344
541
|
console.log();
|
|
345
|
-
console.log(` ${
|
|
346
|
-
console.log(` ${
|
|
347
|
-
console.log(` ${
|
|
542
|
+
console.log(` ${chalk4.dim("\u2022")} Download template from GitHub`);
|
|
543
|
+
console.log(` ${chalk4.dim("\u2022")} Transform package.json files`);
|
|
544
|
+
console.log(` ${chalk4.dim("\u2022")} Create .env.local files`);
|
|
348
545
|
if (!options.skipGit) {
|
|
349
|
-
console.log(` ${
|
|
546
|
+
console.log(` ${chalk4.dim("\u2022")} Initialize git repository`);
|
|
350
547
|
}
|
|
351
548
|
if (!options.skipInstall) {
|
|
352
|
-
console.log(` ${
|
|
549
|
+
console.log(` ${chalk4.dim("\u2022")} Install dependencies (pnpm install)`);
|
|
353
550
|
}
|
|
354
551
|
console.log();
|
|
355
552
|
}
|
|
356
553
|
async function create(projectName, flags) {
|
|
357
554
|
printHeader();
|
|
555
|
+
const checksPass = await runPreflightChecks();
|
|
556
|
+
if (!checksPass) {
|
|
557
|
+
process.exit(1);
|
|
558
|
+
}
|
|
358
559
|
const options = await getProjectOptions(projectName, flags);
|
|
359
560
|
if (!options) {
|
|
360
561
|
return;
|
|
@@ -393,8 +594,7 @@ async function create(projectName, flags) {
|
|
|
393
594
|
const spinner = ora();
|
|
394
595
|
try {
|
|
395
596
|
spinner.start("Downloading template from GitHub...");
|
|
396
|
-
await downloadAndPrepareTemplate(targetDir);
|
|
397
|
-
spinner.succeed("Downloaded template");
|
|
597
|
+
await downloadAndPrepareTemplate(targetDir, spinner);
|
|
398
598
|
spinner.start("Configuring project...");
|
|
399
599
|
await transformFiles(targetDir, {
|
|
400
600
|
projectName: options.projectName,
|
|
@@ -423,9 +623,34 @@ async function create(projectName, flags) {
|
|
|
423
623
|
);
|
|
424
624
|
}
|
|
425
625
|
}
|
|
626
|
+
let ranAutomaticSetup = false;
|
|
627
|
+
const shouldRunSetup = await promptAutomaticSetup();
|
|
628
|
+
if (shouldRunSetup) {
|
|
629
|
+
console.log();
|
|
630
|
+
spinner.start("Starting PostgreSQL database...");
|
|
631
|
+
const dockerSuccess = runDockerCompose(targetDir);
|
|
632
|
+
if (dockerSuccess) {
|
|
633
|
+
spinner.succeed("Started PostgreSQL database");
|
|
634
|
+
spinner.start("Running database migrations...");
|
|
635
|
+
const migrationsSuccess = runDatabaseMigrations(targetDir);
|
|
636
|
+
if (migrationsSuccess) {
|
|
637
|
+
spinner.succeed("Database migrations complete");
|
|
638
|
+
ranAutomaticSetup = true;
|
|
639
|
+
} else {
|
|
640
|
+
spinner.warn(
|
|
641
|
+
'Failed to run migrations. Run "pnpm db:migrate" manually.'
|
|
642
|
+
);
|
|
643
|
+
}
|
|
644
|
+
} else {
|
|
645
|
+
spinner.warn(
|
|
646
|
+
'Failed to start Docker. Run "docker compose up -d" manually.'
|
|
647
|
+
);
|
|
648
|
+
}
|
|
649
|
+
}
|
|
426
650
|
printSuccess(
|
|
427
651
|
options.projectName,
|
|
428
|
-
options.useCurrentDir ? "." : options.projectName
|
|
652
|
+
options.useCurrentDir ? "." : options.projectName,
|
|
653
|
+
ranAutomaticSetup
|
|
429
654
|
);
|
|
430
655
|
} catch (error) {
|
|
431
656
|
spinner.fail();
|