Skip to content

Commit bdf2721

Browse files
committed
feat: add ability to select between pnpm and npm, when we create apdminforth app
https://web.tracklify.com/project/2b7ZVgE5/AdminForth/1316/EzZFZwip/cli-switch-to-use-pnpmnpm-pnpm
1 parent a62f31d commit bdf2721

File tree

6 files changed

+155
-25
lines changed

6 files changed

+155
-25
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,19 @@
1+
2+
{{#unless useNpm}}
13
FROM devforth/node20-pnpm:latest
24
WORKDIR /code/
35
ADD package.json pnpm-lock.yaml pnpm-workspace.yaml /code/
46
RUN pnpm i
57
ADD . /code/
68
RUN pnpm exec adminforth bundle
79
CMD ["sh", "-c", "pnpm migrate:prod && pnpm prod"]
10+
{{/unless}}
11+
{{#if useNpm}}
12+
FROM node:{{nodeMajor}}-slim
13+
WORKDIR /code/
14+
ADD package.json package-lock.json /code/
15+
RUN npm ci
16+
ADD . /code/
17+
RUN npx adminforth bundle
18+
CMD ["sh", "-c", "npm run migrate:prod && npm run prod"]
19+
{{/if}}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"name": "custom",
3+
"version": "1.0.0",
4+
"main": "index.ts",
5+
"scripts": {
6+
"test": "echo \"Error: no test specified\" && exit 1"
7+
},
8+
"keywords": [],
9+
"author": "",
10+
"license": "ISC",
11+
"description": ""
12+
}

adminforth/commands/createApp/templates/package.json.hbs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
"license": "ISC",
99
"description": "",
1010
"scripts": {
11+
{{#unless useNpm}}
1112
"dev": "pnpm _env:dev tsx watch index.ts",
1213
"prod": "pnpm _env:prod tsx index.ts",
1314
"start": "pnpm dev",
@@ -16,6 +17,17 @@
1617
"migrate:prod": "pnpm _env:prod npx --yes prisma migrate deploy",
1718
"_env:dev": "dotenvx run -f .env -f .env.local --",
1819
"_env:prod": "dotenvx run -f .env.prod --"
20+
{{/unless}}
21+
{{#if useNpm}}
22+
"dev": "npm run _env:dev -- tsx watch index.ts",
23+
"prod": "npm run _env:prod -- tsx index.ts",
24+
"start": "npm run dev",
25+
"makemigration": "npm run _env:dev -- npx --yes prisma migrate dev --create-only",
26+
"migrate:local": "npm run _env:dev -- npx --yes prisma migrate deploy",
27+
"migrate:prod": "npm run _env:prod -- npx --yes prisma migrate deploy",
28+
"_env:dev": "dotenvx run -f .env -f .env.local --",
29+
"_env:prod": "dotenvx run -f .env.prod --"
30+
{{/if}}
1931
},
2032
"engines": {
2133
"node": ">=20"

adminforth/commands/createApp/templates/pnpm-workspace.yaml.hbs renamed to adminforth/commands/createApp/templates/pnpm_templates/pnpm-workspace.yaml.hbs

File renamed without changes.

adminforth/commands/createApp/templates/readme.md.hbs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,25 @@
11
## Starting the application
22

33
Install dependencies:
4+
{{#if useNpm}}
5+
```bash
6+
npm i
7+
```
8+
9+
Migrate the database:
10+
11+
```bash
12+
npm run migrate:local
13+
```
14+
15+
Start the server:
16+
17+
```bash
18+
npm run dev
19+
```
20+
{{/if}}
421

22+
{{#unless useNpm}}
523
```bash
624
pnpm i
725
```
@@ -17,6 +35,7 @@ Start the server:
1735
```bash
1836
pnpm dev
1937
```
38+
{{/unless}}
2039

2140
{{#if prismaDbUrl}}
2241
## Changing schema

adminforth/commands/createApp/utils.js

Lines changed: 100 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ export function parseArgumentsIntoOptions(rawArgs) {
4444
{
4545
'--app-name': String,
4646
'--db': String,
47+
'--use-npm': Boolean,
4748
// you can add more flags here if needed
4849
},
4950
{
@@ -54,6 +55,7 @@ export function parseArgumentsIntoOptions(rawArgs) {
5455
return {
5556
appName: args['--app-name'],
5657
db: args['--db'],
58+
useNpm: args['--use-npm'],
5759
};
5860
}
5961

@@ -78,11 +80,21 @@ export async function promptForMissingOptions(options) {
7880
});
7981
};
8082

83+
if (!options.useNpm) {
84+
questions.push({
85+
type: 'confirm',
86+
name: 'useNpm',
87+
message: 'Do you want to use npm instead of pnpm?',
88+
default: false,
89+
});
90+
}
91+
8192
const answers = await inquirer.prompt(questions);
8293
return {
8394
...options,
8495
appName: options.appName || answers.appName,
8596
db: options.db || answers.db,
97+
useNpm: options.useNpm || answers.useNpm,
8698
};
8799
}
88100

@@ -230,7 +242,7 @@ async function scaffoldProject(ctx, options, cwd) {
230242
await fse.copy(sourceAssetsDir, targetAssetsDir);
231243

232244
// Write templated files
233-
await writeTemplateFiles(dirname, projectDir, {
245+
await writeTemplateFiles(dirname, projectDir, options.useNpm, {
234246
dbUrl: connectionString.toString(),
235247
dbUrlProd: connectionStringProd,
236248
prismaDbUrl,
@@ -244,7 +256,7 @@ async function scaffoldProject(ctx, options, cwd) {
244256
return projectDir; // Return the new directory path
245257
}
246258

247-
async function writeTemplateFiles(dirname, cwd, options) {
259+
async function writeTemplateFiles(dirname, cwd, useNpm, options) {
248260
const {
249261
dbUrl, prismaDbUrl, appName, provider, nodeMajor,
250262
dbUrlProd, prismaDbUrlProd, sqliteFile
@@ -268,14 +280,6 @@ async function writeTemplateFiles(dirname, cwd, options) {
268280
dest: 'prisma.config.ts',
269281
data: {},
270282
},
271-
{
272-
src: 'package.json.hbs',
273-
dest: 'package.json',
274-
data: {
275-
appName,
276-
adminforthVersion: adminforthVersion,
277-
},
278-
},
279283
{
280284
src: 'index.ts.hbs',
281285
dest: 'index.ts',
@@ -304,7 +308,7 @@ async function writeTemplateFiles(dirname, cwd, options) {
304308
{
305309
src: 'readme.md.hbs',
306310
dest: 'README.md',
307-
data: { dbUrl, prismaDbUrl, appName, sqliteFile },
311+
data: { dbUrl, prismaDbUrl, appName, sqliteFile, useNpm },
308312
},
309313
{
310314
// We'll write .env using the same content as .env.sample
@@ -322,11 +326,6 @@ async function writeTemplateFiles(dirname, cwd, options) {
322326
dest: 'custom/tsconfig.json',
323327
data: {},
324328
},
325-
{
326-
src: 'Dockerfile.hbs',
327-
dest: 'Dockerfile',
328-
data: { nodeMajor },
329-
},
330329
{
331330
src: '.dockerignore.hbs',
332331
dest: '.dockerignore',
@@ -335,12 +334,39 @@ async function writeTemplateFiles(dirname, cwd, options) {
335334
},
336335
},
337336
{
338-
src: 'pnpm-workspace.yaml.hbs',
339-
dest: 'pnpm-workspace.yaml',
340-
data: {},
341-
}
337+
src: 'Dockerfile.hbs',
338+
dest: 'Dockerfile',
339+
data: { nodeMajor, useNpm },
340+
},
341+
{
342+
src: 'package.json.hbs',
343+
dest: 'package.json',
344+
data: {
345+
appName,
346+
adminforthVersion: adminforthVersion,
347+
useNpm
348+
},
349+
},
342350
];
343351

352+
if (!useNpm) {
353+
templateTasks.push(
354+
{
355+
src: 'pnpm_templates/pnpm-workspace.yaml.hbs',
356+
dest: 'pnpm-workspace.yaml',
357+
data: {},
358+
},
359+
)
360+
} else {
361+
templateTasks.push(
362+
{
363+
src: 'custom/package.json.hbs',
364+
dest: 'custom/package.json',
365+
data: {}
366+
}
367+
)
368+
}
369+
344370
for (const task of templateTasks) {
345371
// If a condition is specified and false, skip this file
346372
if (task.condition === false) continue;
@@ -358,7 +384,7 @@ async function writeTemplateFiles(dirname, cwd, options) {
358384
}
359385
}
360386

361-
async function installDependencies(ctx, cwd) {
387+
async function installDependenciesPnpm(ctx, cwd) {
362388
const isWindows = process.platform === 'win32';
363389

364390
const nodeBinary = process.execPath;
@@ -375,10 +401,28 @@ async function installDependencies(ctx, cwd) {
375401
await execAsync(`${nodeBinary} ${npmPath} install`, { cwd: customDir, env: { PATH: process.env.PATH } }),
376402
]);
377403
}
378-
// console.log(chalk.dim(`Dependencies installed in ${cwd} and ${customDir}: \n${res[0].stdout}${res[1].stdout}`));
379404
}
380405

381-
function generateFinalInstructions(skipPrismaSetup, options) {
406+
async function installDependenciesNpm(ctx, cwd) {
407+
const isWindows = process.platform === 'win32';
408+
409+
const nodeBinary = process.execPath;
410+
const npmPath = path.join(path.dirname(nodeBinary), isWindows ? 'npm.cmd' : 'npm');
411+
const customDir = ctx.customDir;
412+
if (isWindows) {
413+
const res = await Promise.all([
414+
await execAsync(`npm install`, { cwd, env: { PATH: process.env.PATH } }),
415+
await execAsync(`npm install`, { cwd: customDir, env: { PATH: process.env.PATH } }),
416+
]);
417+
} else {
418+
const res = await Promise.all([
419+
await execAsync(`${nodeBinary} ${npmPath} install`, { cwd, env: { PATH: process.env.PATH } }),
420+
await execAsync(`${nodeBinary} ${npmPath} install`, { cwd: customDir, env: { PATH: process.env.PATH } }),
421+
]);
422+
}
423+
}
424+
425+
function generateFinalInstructionsPnpm(skipPrismaSetup, options) {
382426
let instruction = '⏭️ Run the following commands to get started:\n';
383427
if (!skipPrismaSetup)
384428
instruction += `
@@ -399,6 +443,27 @@ function generateFinalInstructions(skipPrismaSetup, options) {
399443
return instruction;
400444
}
401445

446+
function generateFinalInstructionsNpm(skipPrismaSetup, options) {
447+
let instruction = '⏭️ Run the following commands to get started:\n';
448+
if (!skipPrismaSetup)
449+
instruction += `
450+
${chalk.dim('// Go to the project directory')}
451+
${chalk.dim('$')}${chalk.cyan(` cd ${options.appName}`)}\n`;
452+
453+
instruction += `
454+
${chalk.dim('// Generate and apply initial migration')}
455+
${chalk.dim('$')}${chalk.cyan(' npm run makemigration -- --name init && npm run migrate:local')}\n`;
456+
457+
instruction += `
458+
${chalk.dim('// Start dev server with tsx watch for hot-reloading')}
459+
${chalk.dim('$')}${chalk.cyan(' npm run dev')}\n
460+
`;
461+
462+
instruction += '😉 Happy coding!';
463+
464+
return instruction;
465+
}
466+
402467
function renderHBSTemplate(templatePath, data) {
403468
// Example: renderHBRTemplate('path/to/template.hbs', {name: 'John Doe'})
404469
const template = fs.readFileSync(templatePath, 'utf-8');
@@ -425,13 +490,23 @@ export function prepareWorkflow(options) {
425490
},
426491
{
427492
title: '📦 Installing dependencies...',
428-
task: async (ctx) => installDependencies(ctx, ctx.projectDir)
493+
task: async (ctx) => {
494+
if (options.useNpm) {
495+
await installDependenciesNpm(ctx, ctx.projectDir);
496+
} else {
497+
await installDependenciesPnpm(ctx, ctx.projectDir);
498+
}
499+
}
429500
},
430501
{
431502
title: '📝 Preparing final instructions...',
432503
task: (ctx) => {
433504
console.log(chalk.green(`✅ Successfully created your new Adminforth project in ${ctx.projectDir}!\n`));
434-
console.log(generateFinalInstructions(ctx.skipPrismaSetup, options));
505+
if (options.useNpm) {
506+
console.log(generateFinalInstructionsNpm(ctx.skipPrismaSetup, options));
507+
} else {
508+
console.log(generateFinalInstructionsPnpm(ctx.skipPrismaSetup, options));
509+
}
435510
console.log('\n\n');
436511
}
437512
}

0 commit comments

Comments
 (0)